@seanyao/roll 3.607.1 → 3.607.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/roll.mjs +306 -112
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.607.2 — 2026-06-07
|
|
4
|
+
|
|
5
|
+
### 自动化流水线
|
|
6
|
+
|
|
7
|
+
- 无技能子模块的项目跑 loop 找不到技能、选 agent 无视项目配置;补全局技能兜底、读项目配置选人、新增 pi 接管(FIX-221) `[loop]`
|
|
8
|
+
- loop 选 agent 被项目级单一默认一票否决:所有难度档坍缩成一个 agent,难题不再给 claude;装机探测永真空转;按 v2 链路修复(FIX-223) `[loop]`
|
|
9
|
+
- 非 claude agent 的 loop 接管命令全量 port(kimi/codex/deepseek/qwen/agy/gemini/antigravity)(US-PORT-010)
|
|
10
|
+
- roll loop now 手动触发降噪:交互终端只看关键节点,不再被逐行 JSON 淹没(FIX-220) `[loop]`
|
|
11
|
+
|
|
12
|
+
### 工程和测试
|
|
13
|
+
|
|
14
|
+
- difftest 卸 oracle 收尾:全仓断言测试期不再起任何旧引擎,桥接表与文档记 oracle 卸任(US-PORT-009e)
|
|
15
|
+
- 看板冻结测试时钟钉死:快照不再随墙钟与时区漂移,任意日期任意时区可复现,提交闸不再被误堵(FIX-222)
|
|
16
|
+
|
|
17
|
+
### 其他
|
|
18
|
+
|
|
19
|
+
- 验收卡史诗归属适配新档案布局:两级目录解析收敛为单一解析点(PR#513)
|
|
20
|
+
|
|
3
21
|
## v3.607.1 — 2026-06-07
|
|
4
22
|
|
|
5
23
|
### 可见性
|
package/dist/roll.mjs
CHANGED
|
@@ -3028,6 +3028,21 @@ function agentBinNames(agent) {
|
|
|
3028
3028
|
return null;
|
|
3029
3029
|
}
|
|
3030
3030
|
}
|
|
3031
|
+
function realAgentEnv() {
|
|
3032
|
+
return {
|
|
3033
|
+
home: homedir(),
|
|
3034
|
+
commandOnPath,
|
|
3035
|
+
dirExists: (p) => existsSync2(p),
|
|
3036
|
+
fileExecutable: (p) => {
|
|
3037
|
+
try {
|
|
3038
|
+
accessSync(p, constants.X_OK);
|
|
3039
|
+
return statSync(p).isFile();
|
|
3040
|
+
} catch {
|
|
3041
|
+
return false;
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
3031
3046
|
function commandOnPath(bin) {
|
|
3032
3047
|
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
3033
3048
|
if (dir === "")
|
|
@@ -3130,6 +3145,115 @@ var nodeFileStore = {
|
|
|
3130
3145
|
}
|
|
3131
3146
|
};
|
|
3132
3147
|
|
|
3148
|
+
// packages/core/dist/agent/registry.js
|
|
3149
|
+
function agentBinNames2(agent) {
|
|
3150
|
+
switch (agent) {
|
|
3151
|
+
case "claude":
|
|
3152
|
+
return ["claude"];
|
|
3153
|
+
case "codex":
|
|
3154
|
+
case "openai":
|
|
3155
|
+
return ["codex"];
|
|
3156
|
+
case "agy":
|
|
3157
|
+
case "gemini":
|
|
3158
|
+
return ["agy", "gemini"];
|
|
3159
|
+
case "kimi":
|
|
3160
|
+
return ["kimi-code", "kimi-cli", "kimi"];
|
|
3161
|
+
case "deepseek":
|
|
3162
|
+
return ["deepseek"];
|
|
3163
|
+
case "qwen":
|
|
3164
|
+
return ["qwen"];
|
|
3165
|
+
case "pi":
|
|
3166
|
+
return ["pi"];
|
|
3167
|
+
default:
|
|
3168
|
+
return null;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
function joinPath(...parts) {
|
|
3172
|
+
return parts.join("/");
|
|
3173
|
+
}
|
|
3174
|
+
function agentInstalledByName2(env, agent, dir) {
|
|
3175
|
+
const home = env.home;
|
|
3176
|
+
switch (agent) {
|
|
3177
|
+
case "trae":
|
|
3178
|
+
return env.dirExists(joinPath(home, "Library", "Application Support", "Trae")) || env.dirExists(joinPath(home, ".config", "Trae"));
|
|
3179
|
+
case "opencode":
|
|
3180
|
+
return env.fileExecutable(joinPath(home, ".opencode", "bin", "opencode"));
|
|
3181
|
+
case "cursor":
|
|
3182
|
+
return env.commandOnPath("cursor") || env.dirExists(joinPath(home, ".cursor"));
|
|
3183
|
+
case "openclaw":
|
|
3184
|
+
return env.dirExists(joinPath(home, ".openclaw", "workspace"));
|
|
3185
|
+
}
|
|
3186
|
+
const bins = agentBinNames2(agent);
|
|
3187
|
+
if (bins !== null)
|
|
3188
|
+
return bins.some((b) => env.commandOnPath(b));
|
|
3189
|
+
return dir !== void 0 && dir !== "" && env.dirExists(dir);
|
|
3190
|
+
}
|
|
3191
|
+
var FIRST_INSTALLED_ORDER = [
|
|
3192
|
+
"claude",
|
|
3193
|
+
"codex",
|
|
3194
|
+
"kimi",
|
|
3195
|
+
"deepseek",
|
|
3196
|
+
"qwen",
|
|
3197
|
+
"agy",
|
|
3198
|
+
"pi",
|
|
3199
|
+
"cursor",
|
|
3200
|
+
"opencode",
|
|
3201
|
+
"trae",
|
|
3202
|
+
"openclaw"
|
|
3203
|
+
];
|
|
3204
|
+
function firstInstalledAgent(env) {
|
|
3205
|
+
return FIRST_INSTALLED_ORDER.find((a) => agentInstalledByName2(env, a));
|
|
3206
|
+
}
|
|
3207
|
+
function lineAgentValue(line) {
|
|
3208
|
+
const s = line.replace(/\t/g, " ");
|
|
3209
|
+
if (s.startsWith("agent:"))
|
|
3210
|
+
return s.slice("agent:".length);
|
|
3211
|
+
const m7 = /[ ,{]agent:/.exec(s);
|
|
3212
|
+
if (m7 === null)
|
|
3213
|
+
return void 0;
|
|
3214
|
+
return s.slice(m7.index + m7[0].length);
|
|
3215
|
+
}
|
|
3216
|
+
function cleanAgentValue(raw) {
|
|
3217
|
+
let v = raw;
|
|
3218
|
+
const hash = v.indexOf("#");
|
|
3219
|
+
if (hash >= 0)
|
|
3220
|
+
v = v.slice(0, hash);
|
|
3221
|
+
v = v.replace(/[{}",']/g, "").replace(/,/g, "");
|
|
3222
|
+
return v.trim();
|
|
3223
|
+
}
|
|
3224
|
+
function readSlotFromText(text, slot) {
|
|
3225
|
+
let inBlock = false;
|
|
3226
|
+
let agent = "";
|
|
3227
|
+
let found = false;
|
|
3228
|
+
const slotHeader = `${slot}:`;
|
|
3229
|
+
for (const raw of text.split("\n")) {
|
|
3230
|
+
const line = raw.replace(/\r$/, "");
|
|
3231
|
+
if (line === slotHeader || line.startsWith(`${slot}: `) || line.startsWith(`${slot}:{`)) {
|
|
3232
|
+
inBlock = true;
|
|
3233
|
+
const v = lineAgentValue(line);
|
|
3234
|
+
if (v !== void 0) {
|
|
3235
|
+
agent = v;
|
|
3236
|
+
found = true;
|
|
3237
|
+
}
|
|
3238
|
+
} else if (line.length > 0 && line[0] !== " ") {
|
|
3239
|
+
if (inBlock)
|
|
3240
|
+
break;
|
|
3241
|
+
} else if (inBlock && !found) {
|
|
3242
|
+
const v = lineAgentValue(line);
|
|
3243
|
+
if (v !== void 0) {
|
|
3244
|
+
agent = v;
|
|
3245
|
+
found = true;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
if (found)
|
|
3249
|
+
break;
|
|
3250
|
+
}
|
|
3251
|
+
if (!inBlock)
|
|
3252
|
+
return void 0;
|
|
3253
|
+
const cleaned = cleanAgentValue(agent);
|
|
3254
|
+
return cleaned === "" ? void 0 : cleaned;
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3133
3257
|
// packages/core/dist/agent/router.js
|
|
3134
3258
|
var EASY_MAX_MIN = 8;
|
|
3135
3259
|
var HARD_MIN_MIN = 20;
|
|
@@ -6028,14 +6152,22 @@ function findFeatureFile(projectPath, storyId) {
|
|
|
6028
6152
|
function reportFileName(storyId) {
|
|
6029
6153
|
return `${storyId}-report.html`;
|
|
6030
6154
|
}
|
|
6155
|
+
function isEpicName(name) {
|
|
6156
|
+
return name !== "" && name !== "." && name !== "features";
|
|
6157
|
+
}
|
|
6158
|
+
function epicFromFeaturePath(featureFile) {
|
|
6159
|
+
const storyDir = dirname4(featureFile);
|
|
6160
|
+
const epic = basename3(dirname4(storyDir));
|
|
6161
|
+
if (isEpicName(epic))
|
|
6162
|
+
return epic;
|
|
6163
|
+
const legacy = basename3(storyDir);
|
|
6164
|
+
return isEpicName(legacy) ? legacy : null;
|
|
6165
|
+
}
|
|
6031
6166
|
function liveEpicOf(projectPath, storyId) {
|
|
6032
6167
|
const file = findFeatureFile(projectPath, storyId);
|
|
6033
6168
|
if (file === null)
|
|
6034
6169
|
return null;
|
|
6035
|
-
|
|
6036
|
-
if (epic === "" || epic === "." || epic === "features")
|
|
6037
|
-
return null;
|
|
6038
|
-
return epic;
|
|
6170
|
+
return epicFromFeaturePath(file);
|
|
6039
6171
|
}
|
|
6040
6172
|
function readIndex(projectPath) {
|
|
6041
6173
|
const p = join5(projectPath, ".roll", "index.json");
|
|
@@ -7243,7 +7375,7 @@ function screenshotEvidenceRef(result, href) {
|
|
|
7243
7375
|
|
|
7244
7376
|
// packages/cli/dist/commands/attest.js
|
|
7245
7377
|
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync6, rmSync as rmSync5, symlinkSync as symlinkSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
7246
|
-
import { basename as basename4,
|
|
7378
|
+
import { basename as basename4, join as join10, relative } from "node:path";
|
|
7247
7379
|
|
|
7248
7380
|
// packages/cli/dist/lib/story-page.js
|
|
7249
7381
|
var STORY_ID_RE = /^(FIX|US|IDEA|REFACTOR)-/;
|
|
@@ -7537,11 +7669,11 @@ function buildCardContext(projectPath, featureFile, storyId, env) {
|
|
|
7537
7669
|
summary = extractSummary(readFileSync9(featureFile, "utf8"));
|
|
7538
7670
|
} catch {
|
|
7539
7671
|
}
|
|
7540
|
-
const epic =
|
|
7672
|
+
const epic = epicFromFeaturePath(featureFile);
|
|
7541
7673
|
const cycleId = env.LOOP_CYCLE_ID;
|
|
7542
7674
|
const ctx = {
|
|
7543
7675
|
...oneLiner !== void 0 && oneLiner !== "" ? { oneLiner } : {},
|
|
7544
|
-
...epic !==
|
|
7676
|
+
...epic !== null ? { epic } : {},
|
|
7545
7677
|
...summary !== void 0 ? { summary } : {},
|
|
7546
7678
|
...row2.status !== void 0 ? { backlogStatus: row2.status } : {},
|
|
7547
7679
|
...cycleId !== void 0 && cycleId !== "" ? { delivery: { cycleId } } : {}
|
|
@@ -8443,7 +8575,7 @@ import { spawnSync as spawnSync3 } from "node:child_process";
|
|
|
8443
8575
|
// packages/cli/dist/commands/setup-shared.js
|
|
8444
8576
|
import { copyFileSync, existsSync as existsSync18, lstatSync, mkdirSync as mkdirSync10, readFileSync as readFileSync13, readdirSync as readdirSync7, readlinkSync as readlinkSync2, realpathSync as realpathSync2, rmSync as rmSync6, statSync as statSync8, symlinkSync as symlinkSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
8445
8577
|
import { homedir as homedir5 } from "node:os";
|
|
8446
|
-
import { basename as basename5, dirname as
|
|
8578
|
+
import { basename as basename5, dirname as dirname9, join as join12 } from "node:path";
|
|
8447
8579
|
function rollHome() {
|
|
8448
8580
|
return process.env["ROLL_HOME"] ?? join12(homedir5(), ".roll");
|
|
8449
8581
|
}
|
|
@@ -8491,7 +8623,7 @@ function canonicalDir(path) {
|
|
|
8491
8623
|
return null;
|
|
8492
8624
|
}
|
|
8493
8625
|
}
|
|
8494
|
-
function
|
|
8626
|
+
function agentBinNames3(agent) {
|
|
8495
8627
|
switch (agent) {
|
|
8496
8628
|
case "claude":
|
|
8497
8629
|
return ["claude"];
|
|
@@ -8528,7 +8660,7 @@ function onPath(bin) {
|
|
|
8528
8660
|
}
|
|
8529
8661
|
return false;
|
|
8530
8662
|
}
|
|
8531
|
-
function
|
|
8663
|
+
function agentInstalledByName3(agent, dir = "") {
|
|
8532
8664
|
const home = homedir5();
|
|
8533
8665
|
switch (agent) {
|
|
8534
8666
|
case "trae":
|
|
@@ -8548,7 +8680,7 @@ function agentInstalledByName2(agent, dir = "") {
|
|
|
8548
8680
|
default:
|
|
8549
8681
|
break;
|
|
8550
8682
|
}
|
|
8551
|
-
const bins =
|
|
8683
|
+
const bins = agentBinNames3(agent);
|
|
8552
8684
|
if (bins !== null) {
|
|
8553
8685
|
return bins.some((b) => onPath(b));
|
|
8554
8686
|
}
|
|
@@ -8557,13 +8689,13 @@ function agentInstalledByName2(agent, dir = "") {
|
|
|
8557
8689
|
function isAiInstalled(aiDir) {
|
|
8558
8690
|
let bn = basename5(aiDir).replace(/^\./, "");
|
|
8559
8691
|
if (bn === "agent" || bn === "workspace") {
|
|
8560
|
-
bn = basename5(
|
|
8692
|
+
bn = basename5(dirname9(aiDir)).replace(/^\./, "");
|
|
8561
8693
|
}
|
|
8562
8694
|
if (bn === "gemini")
|
|
8563
8695
|
bn = "agy";
|
|
8564
8696
|
if (bn === "kimi-code")
|
|
8565
8697
|
bn = "kimi";
|
|
8566
|
-
return
|
|
8698
|
+
return agentInstalledByName3(bn, aiDir);
|
|
8567
8699
|
}
|
|
8568
8700
|
function listDirEntries(dir) {
|
|
8569
8701
|
try {
|
|
@@ -8594,7 +8726,7 @@ function pruneDir(installedDir, sourceDir) {
|
|
|
8594
8726
|
function safeCopy(src, dst, force) {
|
|
8595
8727
|
if (!existsSync18(src))
|
|
8596
8728
|
return;
|
|
8597
|
-
mkdirSync10(
|
|
8729
|
+
mkdirSync10(dirname9(dst), { recursive: true });
|
|
8598
8730
|
if (existsSync18(dst) && !force) {
|
|
8599
8731
|
if (sameFile(src, dst))
|
|
8600
8732
|
return;
|
|
@@ -8771,7 +8903,7 @@ loop_dream_hour: 3
|
|
|
8771
8903
|
# loop_dream_minute: 10 # omit to auto-derive
|
|
8772
8904
|
primary_agent: claude
|
|
8773
8905
|
`;
|
|
8774
|
-
function
|
|
8906
|
+
function firstInstalledAgent2() {
|
|
8775
8907
|
for (const agent of [
|
|
8776
8908
|
"claude",
|
|
8777
8909
|
"codex",
|
|
@@ -8785,7 +8917,7 @@ function firstInstalledAgent() {
|
|
|
8785
8917
|
"trae",
|
|
8786
8918
|
"openclaw"
|
|
8787
8919
|
]) {
|
|
8788
|
-
if (
|
|
8920
|
+
if (agentInstalledByName3(agent))
|
|
8789
8921
|
return agent;
|
|
8790
8922
|
}
|
|
8791
8923
|
return null;
|
|
@@ -8810,7 +8942,7 @@ function installLocal(force) {
|
|
|
8810
8942
|
}
|
|
8811
8943
|
if (!existsSync18(cfg)) {
|
|
8812
8944
|
writeFileSync9(cfg, DEFAULT_CONFIG);
|
|
8813
|
-
const detected =
|
|
8945
|
+
const detected = firstInstalledAgent2();
|
|
8814
8946
|
if (detected !== null && detected !== "claude")
|
|
8815
8947
|
replacePrimaryAgent(detected);
|
|
8816
8948
|
}
|
|
@@ -8820,7 +8952,7 @@ function installLocal(force) {
|
|
|
8820
8952
|
function syncConventionForTool(src, mainDst, force) {
|
|
8821
8953
|
if (!existsSync18(src))
|
|
8822
8954
|
return;
|
|
8823
|
-
const dstDir =
|
|
8955
|
+
const dstDir = dirname9(mainDst);
|
|
8824
8956
|
if (dstDir !== join12(homedir5(), ".claude") && !isAiInstalled(dstDir) && !existsSync18(dstDir)) {
|
|
8825
8957
|
return;
|
|
8826
8958
|
}
|
|
@@ -10959,8 +11091,17 @@ function nextCronHint(zh) {
|
|
|
10959
11091
|
const nxtSh = toShanghai(new Date(nxtEpoch));
|
|
10960
11092
|
return `${pad22(nxtSh.getUTCHours())}:${pad22(nxtSh.getUTCMinutes())} \xB7 in ${mins}m ${pad22(secs)}s`;
|
|
10961
11093
|
}
|
|
11094
|
+
function renderNow() {
|
|
11095
|
+
const v = process.env["ROLL_RENDER_NOW"] ?? "";
|
|
11096
|
+
if (v !== "") {
|
|
11097
|
+
const ms = /^\d+$/.test(v) ? Number(v) : Date.parse(v);
|
|
11098
|
+
if (!Number.isNaN(ms))
|
|
11099
|
+
return new Date(ms);
|
|
11100
|
+
}
|
|
11101
|
+
return /* @__PURE__ */ new Date();
|
|
11102
|
+
}
|
|
10962
11103
|
function fixtureData() {
|
|
10963
|
-
const now =
|
|
11104
|
+
const now = renderNow();
|
|
10964
11105
|
const events = [];
|
|
10965
11106
|
const cron = [];
|
|
10966
11107
|
let cycleId = 0;
|
|
@@ -11163,7 +11304,7 @@ function render(out2, events, cron, state, backlog, args) {
|
|
|
11163
11304
|
out2.push(" " + c("dim", agentLine));
|
|
11164
11305
|
let skillLine = "";
|
|
11165
11306
|
try {
|
|
11166
|
-
skillLine = selfScoreSummaryLine();
|
|
11307
|
+
skillLine = selfScoreSummaryLine(process.env["ROLL_NOTES_DIR"]);
|
|
11167
11308
|
} catch {
|
|
11168
11309
|
skillLine = "";
|
|
11169
11310
|
}
|
|
@@ -11554,7 +11695,7 @@ roll-loop-status.py: error: unrecognized arguments: ${args.unknown.join(" ")}
|
|
|
11554
11695
|
}
|
|
11555
11696
|
renderState.useColor = !args.noColor && (process.env["NO_COLOR"] ?? "") === "" && (process.stdout.isTTY === true || (process.env["FORCE_COLOR"] ?? "") !== "");
|
|
11556
11697
|
const lang4 = args.en ? "en" : args.zh ? "zh" : "both";
|
|
11557
|
-
const now =
|
|
11698
|
+
const now = renderNow();
|
|
11558
11699
|
let events;
|
|
11559
11700
|
let cron;
|
|
11560
11701
|
let state;
|
|
@@ -11901,7 +12042,7 @@ function loopRunsCommand(argv) {
|
|
|
11901
12042
|
|
|
11902
12043
|
// packages/cli/dist/commands/loop-signals.js
|
|
11903
12044
|
import { appendFileSync as appendFileSync3, existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
|
|
11904
|
-
import { dirname as
|
|
12045
|
+
import { dirname as dirname10, join as join17 } from "node:path";
|
|
11905
12046
|
function lang2() {
|
|
11906
12047
|
return resolveLang({ rollLang: process.env["ROLL_LANG"], lcAll: process.env["LC_ALL"], lang: process.env["LANG"] });
|
|
11907
12048
|
}
|
|
@@ -11956,7 +12097,7 @@ function loopSignalsCommand(argv) {
|
|
|
11956
12097
|
const seenFile = join17(rtDir, `signals-seen-${slug}`);
|
|
11957
12098
|
const candFile = join17(projectPath, ".roll", "signals", "candidates.md");
|
|
11958
12099
|
mkdirSync11(rtDir, { recursive: true });
|
|
11959
|
-
mkdirSync11(
|
|
12100
|
+
mkdirSync11(dirname10(candFile), { recursive: true });
|
|
11960
12101
|
if (!existsSync22(seenFile))
|
|
11961
12102
|
writeFileSync10(seenFile, "");
|
|
11962
12103
|
let lastId = 0;
|
|
@@ -12214,7 +12355,7 @@ var out = { lines: [] };
|
|
|
12214
12355
|
function emit(line) {
|
|
12215
12356
|
out.lines.push(line);
|
|
12216
12357
|
}
|
|
12217
|
-
function
|
|
12358
|
+
function agentBinNames4(agent) {
|
|
12218
12359
|
switch (agent) {
|
|
12219
12360
|
case "claude":
|
|
12220
12361
|
return ["claude"];
|
|
@@ -12251,7 +12392,7 @@ function commandOnPath2(bin) {
|
|
|
12251
12392
|
}
|
|
12252
12393
|
return false;
|
|
12253
12394
|
}
|
|
12254
|
-
function
|
|
12395
|
+
function agentInstalledByName4(agent, dir) {
|
|
12255
12396
|
const home = homedir9();
|
|
12256
12397
|
switch (agent) {
|
|
12257
12398
|
case "trae":
|
|
@@ -12270,7 +12411,7 @@ function agentInstalledByName3(agent, dir) {
|
|
|
12270
12411
|
case "openclaw":
|
|
12271
12412
|
return existsSync24(join19(home, ".openclaw", "workspace"));
|
|
12272
12413
|
default: {
|
|
12273
|
-
const bins =
|
|
12414
|
+
const bins = agentBinNames4(agent);
|
|
12274
12415
|
if (bins !== null)
|
|
12275
12416
|
return bins.some(commandOnPath2);
|
|
12276
12417
|
return dir !== "" && existsSync24(dir) && safeIsDir(dir);
|
|
@@ -12319,7 +12460,7 @@ function agentSection(p) {
|
|
|
12319
12460
|
dir = dir.replace(/^ /, "");
|
|
12320
12461
|
if (dir.startsWith("~"))
|
|
12321
12462
|
dir = home + dir.slice(1);
|
|
12322
|
-
const installed =
|
|
12463
|
+
const installed = agentInstalledByName4(name, dir) ? t(v2Catalog, msgLang6(), "doctor.agent_installed") : t(v2Catalog, msgLang6(), "doctor.agent_missing");
|
|
12323
12464
|
const dirExists = safeIsDir(dir) ? t(v2Catalog, msgLang6(), "doctor.agent_dir_exists") : t(v2Catalog, msgLang6(), "doctor.agent_dir_missing");
|
|
12324
12465
|
const tag = name === primary ? ` (${t(v2Catalog, msgLang6(), "doctor.agent_primary_label")})` : "";
|
|
12325
12466
|
emit(` ${padEnd(name, 10)} ${padEnd(installed, 14)} ${dirExists}${tag}`);
|
|
@@ -12525,16 +12666,8 @@ function killLiveAgents(signal2 = "SIGKILL") {
|
|
|
12525
12666
|
}
|
|
12526
12667
|
var AUTORUN_DIRECTIVE = "[roll \u81EA\u4E3B\u6A21\u5F0F] \u4F60\u6B63\u5728\u65E0\u4EBA\u503C\u5B88\u7684\u81EA\u52A8\u5316\u5FAA\u73AF\u4E2D\u8FD0\u884C,\u8FD9\u4E0D\u662F\u5BF9\u8BDD\u3002\u8BF7\u7ACB\u5373\u3001\u5B8C\u6574\u5730\u6267\u884C\u4E0B\u9762\u8FD9\u4EFD\u6280\u80FD\u6587\u6863\u63CF\u8FF0\u7684\u5DE5\u4F5C\u6D41,\u76F4\u5230\u5B8C\u6210\u4EA4\u4ED8\u6216\u5199\u51FA ALERT \u4E3A\u6B62;\u4E25\u7981\u53CD\u95EE\u3001\u4E25\u7981\u7B49\u5F85\u786E\u8BA4\u3001\u4E25\u7981\u53EA\u590D\u8FF0\u6216\u603B\u7ED3\u800C\u4E0D\u52A8\u624B\u3002\u6280\u80FD\u6587\u6863\u5982\u4E0B: ";
|
|
12527
12668
|
var AGENT_ARGV_TODO = {
|
|
12528
|
-
kimi: "kimi-code|kimi-cli|kimi -p <prompt> (FIX-126/133; no stream-json splice)",
|
|
12529
|
-
pi: "pi -p <prompt> (text mode; no usage on stdout \u2014 cost via session file)",
|
|
12530
|
-
deepseek: "deepseek <prompt> (positional)",
|
|
12531
|
-
codex: "codex exec <prompt>",
|
|
12532
12669
|
openai: "codex exec <prompt>",
|
|
12533
|
-
opencode: "opencode run <prompt>"
|
|
12534
|
-
gemini: "agy -p --dangerously-skip-permissions <prompt> (FIX-153)",
|
|
12535
|
-
agy: "agy -p --dangerously-skip-permissions <prompt> (FIX-153)",
|
|
12536
|
-
antigravity: "agy -p --dangerously-skip-permissions <prompt> (FIX-153)",
|
|
12537
|
-
qwen: "qwen <prompt> (positional)"
|
|
12670
|
+
opencode: "opencode run <prompt>"
|
|
12538
12671
|
};
|
|
12539
12672
|
function storyPinDirective(storyId) {
|
|
12540
12673
|
return `[\u672C\u5468\u671F\u6307\u5B9A\u6545\u4E8B] \u8C03\u5EA6\u5668\u5DF2\u9501\u5B9A ${storyId} \u5E76\u5728 backlog \u6807\u8BB0 \u{1F528} In Progress\u2014\u2014\u53EA\u6267\u884C\u8FD9\u4E00\u4E2A\u6545\u4E8B,\u4E25\u7981\u91CD\u65B0\u6311\u9009\u6216\u987A\u624B\u505A\u522B\u7684;\u82E5\u5B83\u786E\u5B9E\u4E0D\u53EF\u6267\u884C,\u5199 ALERT \u8BF4\u660E\u539F\u56E0\u540E\u5E72\u51C0\u9000\u51FA\u3002
|
|
@@ -12545,7 +12678,7 @@ function buildClaudeArgv(input) {
|
|
|
12545
12678
|
const bin = input.bin ?? "claude";
|
|
12546
12679
|
const pin = input.storyId !== void 0 && input.storyId !== "" ? storyPinDirective(input.storyId) : "";
|
|
12547
12680
|
const prompt = `${AUTORUN_DIRECTIVE}${pin}${input.skillBody}`;
|
|
12548
|
-
const args = [
|
|
12681
|
+
const args = input.interactive ? ["-p", prompt, "--dangerously-skip-permissions", "--add-dir", input.worktree] : [
|
|
12549
12682
|
"-p",
|
|
12550
12683
|
prompt,
|
|
12551
12684
|
"--verbose",
|
|
@@ -12557,20 +12690,42 @@ function buildClaudeArgv(input) {
|
|
|
12557
12690
|
];
|
|
12558
12691
|
return { bin, args };
|
|
12559
12692
|
}
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12693
|
+
function buildSpawnCommand(agent, opts) {
|
|
12694
|
+
const prompt = `${AUTORUN_DIRECTIVE}${opts.storyId !== void 0 && opts.storyId !== "" ? storyPinDirective(opts.storyId) : ""}${opts.skillBody}`;
|
|
12695
|
+
if (agent === "claude") {
|
|
12696
|
+
return buildClaudeArgv({
|
|
12697
|
+
worktree: opts.cwd,
|
|
12698
|
+
skillBody: opts.skillBody,
|
|
12699
|
+
...opts.storyId !== void 0 ? { storyId: opts.storyId } : {},
|
|
12700
|
+
bin: opts.bin,
|
|
12701
|
+
interactive: opts.interactive
|
|
12702
|
+
});
|
|
12564
12703
|
}
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
|
|
12569
|
-
bin: opts.bin
|
|
12570
|
-
}
|
|
12704
|
+
if (agent === "pi") {
|
|
12705
|
+
return { bin: opts.bin ?? "pi", args: ["-p", prompt] };
|
|
12706
|
+
}
|
|
12707
|
+
if (agent === "kimi") {
|
|
12708
|
+
return { bin: opts.bin ?? "kimi", args: ["-p", prompt] };
|
|
12709
|
+
}
|
|
12710
|
+
if (agent === "codex") {
|
|
12711
|
+
return { bin: opts.bin ?? "codex", args: ["exec", prompt] };
|
|
12712
|
+
}
|
|
12713
|
+
if (agent === "deepseek") {
|
|
12714
|
+
return { bin: opts.bin ?? "deepseek", args: [prompt] };
|
|
12715
|
+
}
|
|
12716
|
+
if (agent === "qwen") {
|
|
12717
|
+
return { bin: opts.bin ?? "qwen", args: [prompt] };
|
|
12718
|
+
}
|
|
12719
|
+
if (agent === "agy" || agent === "gemini" || agent === "antigravity") {
|
|
12720
|
+
return { bin: opts.bin ?? "agy", args: ["-p", "--dangerously-skip-permissions", prompt] };
|
|
12721
|
+
}
|
|
12722
|
+
const hint = AGENT_ARGV_TODO[agent] ?? "unknown agent";
|
|
12723
|
+
throw new Error(`runner: agent '${agent}' argv not yet ported. v2 shape: ${hint}`);
|
|
12724
|
+
}
|
|
12725
|
+
function spawnAndWait(bin, args, opts) {
|
|
12571
12726
|
process.stderr.write(`[runner] spawn ${bin} argv=${JSON.stringify(args.map((a) => a.length > 80 ? `${a.slice(0, 77)}...` : a))}
|
|
12572
12727
|
`);
|
|
12573
|
-
return new Promise((resolve3
|
|
12728
|
+
return new Promise((resolve3) => {
|
|
12574
12729
|
const child = spawn(bin, args, {
|
|
12575
12730
|
cwd: opts.cwd,
|
|
12576
12731
|
env: opts.env ?? process.env,
|
|
@@ -12616,16 +12771,22 @@ var realAgentSpawn = (agent, opts) => {
|
|
|
12616
12771
|
settle({ stdout, stderr, exitCode: code ?? 1, timedOut });
|
|
12617
12772
|
});
|
|
12618
12773
|
});
|
|
12774
|
+
}
|
|
12775
|
+
var realAgentSpawn = (agent, opts) => {
|
|
12776
|
+
const { bin, args } = buildSpawnCommand(agent, opts);
|
|
12777
|
+
return spawnAndWait(bin, args, opts);
|
|
12619
12778
|
};
|
|
12620
12779
|
|
|
12621
12780
|
// packages/cli/dist/runner/skill-body.js
|
|
12622
12781
|
import { existsSync as existsSync25, readFileSync as readFileSync20 } from "node:fs";
|
|
12782
|
+
import { homedir as homedir10 } from "node:os";
|
|
12623
12783
|
import { join as join20 } from "node:path";
|
|
12624
12784
|
function readSkillBody(projectPath, opts) {
|
|
12625
12785
|
const candidates = [
|
|
12626
12786
|
opts.envOverride ?? "",
|
|
12627
12787
|
join20(projectPath, ".roll", "skills", opts.skillName, "SKILL.md"),
|
|
12628
|
-
join20(projectPath, "skills", opts.skillName, "SKILL.md")
|
|
12788
|
+
join20(projectPath, "skills", opts.skillName, "SKILL.md"),
|
|
12789
|
+
join20(homedir10(), ".roll", "skills", opts.skillName, "SKILL.md")
|
|
12629
12790
|
].filter((p) => p !== "");
|
|
12630
12791
|
for (const p of candidates) {
|
|
12631
12792
|
if (!existsSync25(p))
|
|
@@ -12701,7 +12862,7 @@ dream run-once: \u627E\u4E0D\u5230 roll-.dream SKILL.md \u2014 \u62D2\u7EDD\u76F
|
|
|
12701
12862
|
// packages/cli/dist/commands/feedback.js
|
|
12702
12863
|
import { execFileSync as execFileSync6, spawnSync as spawnSync4 } from "node:child_process";
|
|
12703
12864
|
import { existsSync as existsSync26, readFileSync as readFileSync22 } from "node:fs";
|
|
12704
|
-
import { homedir as
|
|
12865
|
+
import { homedir as homedir11 } from "node:os";
|
|
12705
12866
|
import { basename as basename8, join as join23 } from "node:path";
|
|
12706
12867
|
|
|
12707
12868
|
// packages/cli/dist/commands/version.js
|
|
@@ -12745,7 +12906,7 @@ function err8(line) {
|
|
|
12745
12906
|
`);
|
|
12746
12907
|
}
|
|
12747
12908
|
function projectAgent2() {
|
|
12748
|
-
const
|
|
12909
|
+
const readField2 = (file, key) => {
|
|
12749
12910
|
if (!existsSync26(file))
|
|
12750
12911
|
return void 0;
|
|
12751
12912
|
let text;
|
|
@@ -12764,14 +12925,14 @@ function projectAgent2() {
|
|
|
12764
12925
|
};
|
|
12765
12926
|
const local = ".roll/local.yaml";
|
|
12766
12927
|
if (existsSync26(local) && /^agent:/m.test(safeRead(local))) {
|
|
12767
|
-
return
|
|
12928
|
+
return readField2(local, /^agent:/) ?? "claude";
|
|
12768
12929
|
}
|
|
12769
12930
|
if (existsSync26(".roll.yaml") && /^agent:/m.test(safeRead(".roll.yaml"))) {
|
|
12770
|
-
return
|
|
12931
|
+
return readField2(".roll.yaml", /^agent:/) ?? "claude";
|
|
12771
12932
|
}
|
|
12772
12933
|
const cfg = rollConfig2();
|
|
12773
12934
|
if (existsSync26(cfg) && /primary_agent:/.test(safeRead(cfg))) {
|
|
12774
|
-
return
|
|
12935
|
+
return readField2(cfg, /primary_agent:/) ?? "claude";
|
|
12775
12936
|
}
|
|
12776
12937
|
return "claude";
|
|
12777
12938
|
}
|
|
@@ -12783,7 +12944,7 @@ function safeRead(p) {
|
|
|
12783
12944
|
}
|
|
12784
12945
|
}
|
|
12785
12946
|
function rollConfig2() {
|
|
12786
|
-
const rollHome4 = process.env["ROLL_HOME"] ?? join23(
|
|
12947
|
+
const rollHome4 = process.env["ROLL_HOME"] ?? join23(homedir11(), ".roll");
|
|
12787
12948
|
return join23(rollHome4, "config.yaml");
|
|
12788
12949
|
}
|
|
12789
12950
|
function feedbackYamlField(file, field) {
|
|
@@ -12830,7 +12991,7 @@ function feedbackDefaultRepo() {
|
|
|
12830
12991
|
let v = feedbackYamlField(".roll/local.yaml", "feedback_repo");
|
|
12831
12992
|
if (v)
|
|
12832
12993
|
return v;
|
|
12833
|
-
v = feedbackYamlField(join23(
|
|
12994
|
+
v = feedbackYamlField(join23(homedir11(), ".roll", "config.yaml"), "feedback_repo");
|
|
12834
12995
|
if (v)
|
|
12835
12996
|
return v;
|
|
12836
12997
|
return feedbackOriginRepo();
|
|
@@ -13283,8 +13444,8 @@ ${rows.join("\n")}
|
|
|
13283
13444
|
// packages/cli/dist/commands/init.js
|
|
13284
13445
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
13285
13446
|
import { copyFileSync as copyFileSync2, existsSync as existsSync30, mkdirSync as mkdirSync14, readFileSync as readFileSync23, realpathSync as realpathSync4, statSync as statSync15, writeFileSync as writeFileSync15 } from "node:fs";
|
|
13286
|
-
import { homedir as
|
|
13287
|
-
import { dirname as
|
|
13447
|
+
import { homedir as homedir12 } from "node:os";
|
|
13448
|
+
import { dirname as dirname11, join as join27 } from "node:path";
|
|
13288
13449
|
function err9(line) {
|
|
13289
13450
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
13290
13451
|
const RED = noColor2 ? "" : "\x1B[0;31m";
|
|
@@ -13293,7 +13454,7 @@ function err9(line) {
|
|
|
13293
13454
|
`);
|
|
13294
13455
|
}
|
|
13295
13456
|
function rollHome2() {
|
|
13296
|
-
return process.env["ROLL_HOME"] ?? join27(
|
|
13457
|
+
return process.env["ROLL_HOME"] ?? join27(homedir12(), ".roll");
|
|
13297
13458
|
}
|
|
13298
13459
|
function rollGlobal2() {
|
|
13299
13460
|
return join27(rollHome2(), "conventions", "global");
|
|
@@ -13534,7 +13695,7 @@ function writeBacklog(path, summary) {
|
|
|
13534
13695
|
summary.push("unchanged|.roll/backlog.md");
|
|
13535
13696
|
return;
|
|
13536
13697
|
}
|
|
13537
|
-
mkdirSync14(
|
|
13698
|
+
mkdirSync14(dirname11(path), { recursive: true });
|
|
13538
13699
|
writeFileSync15(path, BACKLOG_TEMPLATE);
|
|
13539
13700
|
summary.push("created|.roll/backlog.md");
|
|
13540
13701
|
}
|
|
@@ -13561,7 +13722,7 @@ function writeFeaturesMd(path, summary) {
|
|
|
13561
13722
|
summary.push("unchanged|.roll/features.md");
|
|
13562
13723
|
return;
|
|
13563
13724
|
}
|
|
13564
|
-
mkdirSync14(
|
|
13725
|
+
mkdirSync14(dirname11(path), { recursive: true });
|
|
13565
13726
|
writeFileSync15(path, FEATURES_TEMPLATE);
|
|
13566
13727
|
summary.push("created|.roll/features.md");
|
|
13567
13728
|
}
|
|
@@ -13575,7 +13736,7 @@ function initSeedAgentRoutes(templateName, projectDir, summary) {
|
|
|
13575
13736
|
if (!existsSync30(src)) {
|
|
13576
13737
|
return 1;
|
|
13577
13738
|
}
|
|
13578
|
-
mkdirSync14(
|
|
13739
|
+
mkdirSync14(dirname11(dest), { recursive: true });
|
|
13579
13740
|
copyFileSync2(src, dest);
|
|
13580
13741
|
summary.push("created|.roll/agent-routes.yaml");
|
|
13581
13742
|
return 0;
|
|
@@ -13760,10 +13921,10 @@ function initCommand(args) {
|
|
|
13760
13921
|
// packages/cli/dist/commands/lang.js
|
|
13761
13922
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
13762
13923
|
import { existsSync as existsSync31, mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync3, readFileSync as readFileSync24, renameSync as renameSync2, writeFileSync as writeFileSync16 } from "node:fs";
|
|
13763
|
-
import { homedir as
|
|
13764
|
-
import { dirname as
|
|
13924
|
+
import { homedir as homedir13, tmpdir as tmpdir3 } from "node:os";
|
|
13925
|
+
import { dirname as dirname12, join as join28 } from "node:path";
|
|
13765
13926
|
function rollConfigPath4() {
|
|
13766
|
-
const rollHome4 = process.env["ROLL_HOME"] ?? join28(
|
|
13927
|
+
const rollHome4 = process.env["ROLL_HOME"] ?? join28(homedir13(), ".roll");
|
|
13767
13928
|
return join28(rollHome4, "config.yaml");
|
|
13768
13929
|
}
|
|
13769
13930
|
function configLang2() {
|
|
@@ -13843,7 +14004,7 @@ function err10(line) {
|
|
|
13843
14004
|
}
|
|
13844
14005
|
function writeLang(value) {
|
|
13845
14006
|
const cfg = rollConfigPath4();
|
|
13846
|
-
mkdirSync15(
|
|
14007
|
+
mkdirSync15(dirname12(cfg), { recursive: true });
|
|
13847
14008
|
const existing = existsSync31(cfg) ? readFileSync24(cfg, "utf8") : "";
|
|
13848
14009
|
const kept = existing === "" ? [] : existing.split("\n").filter((l) => !/^lang:/.test(l));
|
|
13849
14010
|
if (kept.length > 0 && kept[kept.length - 1] === "")
|
|
@@ -13965,8 +14126,8 @@ async function loopFmtCommand(args) {
|
|
|
13965
14126
|
// packages/cli/dist/commands/loop-pr-inbox.js
|
|
13966
14127
|
import { spawn as spawn2 } from "node:child_process";
|
|
13967
14128
|
import { appendFileSync as appendFileSync5, existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
|
|
13968
|
-
import { homedir as
|
|
13969
|
-
import { dirname as
|
|
14129
|
+
import { homedir as homedir14 } from "node:os";
|
|
14130
|
+
import { dirname as dirname13, join as join29 } from "node:path";
|
|
13970
14131
|
function reducePrView(raw) {
|
|
13971
14132
|
const reviews = raw.reviews ?? [];
|
|
13972
14133
|
const botReviews = reviews.filter((r) => r.authorAssociation === "BOT" || r.authorAssociation === "APP");
|
|
@@ -14067,17 +14228,17 @@ function tickPath() {
|
|
|
14067
14228
|
return join29(runtimeDir(), "pr-tick.jsonl");
|
|
14068
14229
|
}
|
|
14069
14230
|
function engineBin() {
|
|
14070
|
-
let dir =
|
|
14231
|
+
let dir = dirname13(new URL(import.meta.url).pathname);
|
|
14071
14232
|
for (let i = 0; i < 10; i++) {
|
|
14072
14233
|
const candidate = join29(dir, "bin", "roll");
|
|
14073
14234
|
if (existsSync32(candidate))
|
|
14074
14235
|
return candidate;
|
|
14075
|
-
const parent =
|
|
14236
|
+
const parent = dirname13(dir);
|
|
14076
14237
|
if (parent === dir)
|
|
14077
14238
|
break;
|
|
14078
14239
|
dir = parent;
|
|
14079
14240
|
}
|
|
14080
|
-
return join29(
|
|
14241
|
+
return join29(homedir14(), ".local", "lib", "roll", "bin", "roll");
|
|
14081
14242
|
}
|
|
14082
14243
|
function pal2() {
|
|
14083
14244
|
return (process.env["NO_COLOR"] ?? "") !== "" ? { yellow: "", nc: "" } : { yellow: "\x1B[0;33m", nc: "\x1B[0m" };
|
|
@@ -14087,7 +14248,7 @@ function nowSec() {
|
|
|
14087
14248
|
}
|
|
14088
14249
|
function writeTickFile(tick) {
|
|
14089
14250
|
const file = tickPath();
|
|
14090
|
-
mkdirSync16(
|
|
14251
|
+
mkdirSync16(dirname13(file), { recursive: true });
|
|
14091
14252
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
14092
14253
|
appendFileSync5(file, `${JSON.stringify({ ts, ...tick })}
|
|
14093
14254
|
`);
|
|
@@ -14101,7 +14262,7 @@ function writeTickFile(tick) {
|
|
|
14101
14262
|
}
|
|
14102
14263
|
function appendAlert(line) {
|
|
14103
14264
|
const file = alertPath();
|
|
14104
|
-
mkdirSync16(
|
|
14265
|
+
mkdirSync16(dirname13(file), { recursive: true });
|
|
14105
14266
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
14106
14267
|
appendFileSync5(file, `[${ts}] ${line}
|
|
14107
14268
|
`);
|
|
@@ -14117,7 +14278,7 @@ function rebaseCircuitAllowed(num2) {
|
|
|
14117
14278
|
writeRebaseAttempts(state, num2, verdict.freshTimestamps);
|
|
14118
14279
|
if (!verdict.allowed) {
|
|
14119
14280
|
const file = alertPath();
|
|
14120
|
-
mkdirSync16(
|
|
14281
|
+
mkdirSync16(dirname13(file), { recursive: true });
|
|
14121
14282
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 16).replace("T", " ");
|
|
14122
14283
|
writeFileSync17(file, [
|
|
14123
14284
|
`# ALERT \u2014 PR rebase circuit breaker tripped`,
|
|
@@ -14173,7 +14334,7 @@ function upsertRebaseAttempts(stateBody, pr, value) {
|
|
|
14173
14334
|
`;
|
|
14174
14335
|
}
|
|
14175
14336
|
function writeRebaseAttempts(state, pr, timestamps) {
|
|
14176
|
-
mkdirSync16(
|
|
14337
|
+
mkdirSync16(dirname13(state), { recursive: true });
|
|
14177
14338
|
let body = "";
|
|
14178
14339
|
try {
|
|
14179
14340
|
body = readFileSync25(state, "utf8");
|
|
@@ -14267,12 +14428,12 @@ async function loopPrInboxCommand(_args, deps = realDeps2()) {
|
|
|
14267
14428
|
|
|
14268
14429
|
// packages/cli/dist/commands/loop-run-once.js
|
|
14269
14430
|
import { appendFileSync as appendFileSync7, existsSync as existsSync36, mkdirSync as mkdirSync18, readFileSync as readFileSync28, writeFileSync as writeFileSync19 } from "node:fs";
|
|
14270
|
-
import { dirname as
|
|
14431
|
+
import { dirname as dirname15, join as join33 } from "node:path";
|
|
14271
14432
|
|
|
14272
14433
|
// packages/cli/dist/runner/executor.js
|
|
14273
14434
|
import { execFile as execFile8 } from "node:child_process";
|
|
14274
14435
|
import { appendFileSync as appendFileSync6, existsSync as existsSync35, lstatSync as lstatSync2, mkdirSync as mkdirSync17, readFileSync as readFileSync27, rmSync as rmSync8, symlinkSync as symlinkSync4, unlinkSync, writeFileSync as writeFileSync18 } from "node:fs";
|
|
14275
|
-
import { dirname as
|
|
14436
|
+
import { dirname as dirname14, join as join32 } from "node:path";
|
|
14276
14437
|
import { promisify as promisify8 } from "node:util";
|
|
14277
14438
|
|
|
14278
14439
|
// packages/cli/dist/runner/peer-gate.js
|
|
@@ -14503,7 +14664,7 @@ async function executeCommand(cmd, ports, ctx) {
|
|
|
14503
14664
|
// execute: spawn the agent (TCR commits happen inside the worktree). The
|
|
14504
14665
|
// exit code + timeout feed back as agent_exited; usage is captured for cost.
|
|
14505
14666
|
case "spawn_agent": {
|
|
14506
|
-
const livePath = join32(
|
|
14667
|
+
const livePath = join32(dirname14(ports.paths.eventsPath), "live.log");
|
|
14507
14668
|
try {
|
|
14508
14669
|
writeFileSync18(livePath, `\u2500\u2500 cycle ${ctx.cycleId ?? "?"} \xB7 ${ctx.storyId ?? "?"} \xB7 agent ${cmd.agent} \u2500\u2500
|
|
14509
14670
|
`);
|
|
@@ -14523,7 +14684,7 @@ async function executeCommand(cmd, ports, ctx) {
|
|
|
14523
14684
|
}
|
|
14524
14685
|
});
|
|
14525
14686
|
try {
|
|
14526
|
-
const logDir = join32(
|
|
14687
|
+
const logDir = join32(dirname14(ports.paths.eventsPath), "cycle-logs");
|
|
14527
14688
|
mkdirSync17(logDir, { recursive: true });
|
|
14528
14689
|
writeFileSync18(join32(logDir, `${ctx.cycleId ?? "cycle"}.agent.log`), `# exit=${res.exitCode} timedOut=${res.timedOut}
|
|
14529
14690
|
--- stdout ---
|
|
@@ -14572,7 +14733,7 @@ ${res.stderr}
|
|
|
14572
14733
|
tcrCount = await ports.git.tcrCount(ports.paths.worktreePath);
|
|
14573
14734
|
} catch {
|
|
14574
14735
|
}
|
|
14575
|
-
await runPeerGate(ports.paths.worktreePath,
|
|
14736
|
+
await runPeerGate(ports.paths.worktreePath, dirname14(ports.paths.eventsPath), ctx.cycleId ?? "", {
|
|
14576
14737
|
alert: (m7) => ports.events.appendAlert(ports.paths.alertsPath, m7),
|
|
14577
14738
|
event: (p) => ports.events.appendEvent(ports.paths.eventsPath, {
|
|
14578
14739
|
type: "peer:gate",
|
|
@@ -14765,7 +14926,7 @@ async function linkRollIntoWorktree(repoCwd, worktreePath) {
|
|
|
14765
14926
|
const exclude = join32(common, "info", "exclude");
|
|
14766
14927
|
const cur = existsSync35(exclude) ? readFileSync27(exclude, "utf8") : "";
|
|
14767
14928
|
if (!/^\.roll$/m.test(cur)) {
|
|
14768
|
-
mkdirSync17(
|
|
14929
|
+
mkdirSync17(dirname14(exclude), { recursive: true });
|
|
14769
14930
|
appendFileSync6(exclude, `${cur === "" || cur.endsWith("\n") ? "" : "\n"}.roll
|
|
14770
14931
|
`, "utf8");
|
|
14771
14932
|
}
|
|
@@ -14886,7 +15047,7 @@ function nodePorts(opts) {
|
|
|
14886
15047
|
};
|
|
14887
15048
|
}
|
|
14888
15049
|
function appendAlertLine(alertsPath, message) {
|
|
14889
|
-
mkdirSync17(
|
|
15050
|
+
mkdirSync17(dirname14(alertsPath), { recursive: true });
|
|
14890
15051
|
appendFileSync6(alertsPath, `${message}
|
|
14891
15052
|
`, "utf8");
|
|
14892
15053
|
}
|
|
@@ -15191,6 +15352,38 @@ function readSkillBody2(projectPath) {
|
|
|
15191
15352
|
envOverride: process.env["ROLL_LOOP_SKILL"]
|
|
15192
15353
|
});
|
|
15193
15354
|
}
|
|
15355
|
+
function buildLoopRouteDeps(projectPath) {
|
|
15356
|
+
function readSlot(slot) {
|
|
15357
|
+
const agentsYaml = join33(projectPath, ".roll", "agents.yaml");
|
|
15358
|
+
try {
|
|
15359
|
+
return readSlotFromText(readFileSync28(agentsYaml, "utf8"), slot);
|
|
15360
|
+
} catch {
|
|
15361
|
+
return void 0;
|
|
15362
|
+
}
|
|
15363
|
+
}
|
|
15364
|
+
function firstInstalled() {
|
|
15365
|
+
const fromLocal = readField(join33(projectPath, ".roll", "local.yaml"), /^agent:/);
|
|
15366
|
+
if (fromLocal !== void 0)
|
|
15367
|
+
return fromLocal;
|
|
15368
|
+
return firstInstalledAgent(realAgentEnv());
|
|
15369
|
+
}
|
|
15370
|
+
return { readSlot, firstInstalled };
|
|
15371
|
+
}
|
|
15372
|
+
function readField(path, re) {
|
|
15373
|
+
try {
|
|
15374
|
+
const text = readFileSync28(path, "utf8");
|
|
15375
|
+
for (const line of text.split("\n")) {
|
|
15376
|
+
const m7 = line.match(re);
|
|
15377
|
+
if (m7 !== null) {
|
|
15378
|
+
const v = line.slice((m7.index ?? 0) + m7[0].length).trim();
|
|
15379
|
+
if (v !== "")
|
|
15380
|
+
return v.replace(/^["']|["']$/g, "");
|
|
15381
|
+
}
|
|
15382
|
+
}
|
|
15383
|
+
} catch {
|
|
15384
|
+
}
|
|
15385
|
+
return void 0;
|
|
15386
|
+
}
|
|
15194
15387
|
async function loopRunOnceCommand(args) {
|
|
15195
15388
|
const dryRun = args.includes("--dry-run");
|
|
15196
15389
|
const id = await projectIdentity();
|
|
@@ -15215,7 +15408,7 @@ async function loopRunOnceCommand(args) {
|
|
|
15215
15408
|
}
|
|
15216
15409
|
const rt = runtimeDir2(id.path);
|
|
15217
15410
|
const alertsPath = join33(rt, `ALERT-${id.slug}.md`);
|
|
15218
|
-
mkdirSync18(
|
|
15411
|
+
mkdirSync18(dirname15(alertsPath), { recursive: true });
|
|
15219
15412
|
const paths = {
|
|
15220
15413
|
eventsPath: join33(rt, "events.ndjson"),
|
|
15221
15414
|
runsPath: join33(rt, "runs.jsonl"),
|
|
@@ -15238,15 +15431,16 @@ loop run-once: \u627E\u4E0D\u5230 roll-loop SKILL.md \u2014 \u62D2\u7EDD\u76F2\u
|
|
|
15238
15431
|
incrementConsecutiveFails(id.path, id.slug, alertsPath, cycleId, "", "skill_missing");
|
|
15239
15432
|
return 1;
|
|
15240
15433
|
}
|
|
15241
|
-
const routeDeps =
|
|
15242
|
-
|
|
15243
|
-
firstInstalled: () => process.env["ROLL_LOOP_AGENT"] ?? "claude"
|
|
15244
|
-
};
|
|
15434
|
+
const routeDeps = buildLoopRouteDeps(id.path);
|
|
15435
|
+
const isInteractive = (process.env["ROLL_LOOP_FORCE"] ?? "").trim() !== "";
|
|
15245
15436
|
const ports = nodePorts({
|
|
15246
15437
|
repoCwd: id.path,
|
|
15247
15438
|
paths,
|
|
15248
15439
|
skillBody,
|
|
15249
|
-
routeDeps
|
|
15440
|
+
routeDeps,
|
|
15441
|
+
...isInteractive ? {
|
|
15442
|
+
agentSpawn: (agent, opts) => realAgentSpawn(agent, { ...opts, interactive: true })
|
|
15443
|
+
} : {}
|
|
15250
15444
|
});
|
|
15251
15445
|
const disposeSignals = installCycleSignalTeardown(paths, cycleId, branch);
|
|
15252
15446
|
let result;
|
|
@@ -15279,14 +15473,14 @@ loop run-once: \u627E\u4E0D\u5230 roll-loop SKILL.md \u2014 \u62D2\u7EDD\u76F2\u
|
|
|
15279
15473
|
import { createHash as createHash4 } from "node:crypto";
|
|
15280
15474
|
import { spawn as spawn4, spawnSync as spawnSync6 } from "node:child_process";
|
|
15281
15475
|
import { existsSync as existsSync37, mkdirSync as mkdirSync19, readFileSync as readFileSync29, rmSync as rmSync9, writeFileSync as writeFileSync20 } from "node:fs";
|
|
15282
|
-
import { homedir as
|
|
15283
|
-
import { dirname as
|
|
15476
|
+
import { homedir as homedir15 } from "node:os";
|
|
15477
|
+
import { dirname as dirname16, join as join34 } from "node:path";
|
|
15284
15478
|
function realDeps3() {
|
|
15285
15479
|
return {
|
|
15286
15480
|
identity: () => projectIdentity(),
|
|
15287
15481
|
uid: () => process.getuid?.() ?? 501,
|
|
15288
|
-
sharedRoot: () => process.env["ROLL_SHARED_ROOT"] || join34(
|
|
15289
|
-
launchdDir: () => join34(
|
|
15482
|
+
sharedRoot: () => process.env["ROLL_SHARED_ROOT"] || join34(homedir15(), ".shared", "roll"),
|
|
15483
|
+
launchdDir: () => join34(homedir15(), "Library", "LaunchAgents"),
|
|
15290
15484
|
launchd: { reinstall, uninstall, isLoaded },
|
|
15291
15485
|
execRunner: (runner) => new Promise((resolve3) => {
|
|
15292
15486
|
const child = spawn4("bash", [runner], {
|
|
@@ -15478,7 +15672,7 @@ function parseLoopPeriodMinutes(text) {
|
|
|
15478
15672
|
return 30;
|
|
15479
15673
|
}
|
|
15480
15674
|
function pathValue() {
|
|
15481
|
-
const home =
|
|
15675
|
+
const home = homedir15();
|
|
15482
15676
|
return [
|
|
15483
15677
|
"/opt/homebrew/bin",
|
|
15484
15678
|
`${home}/.local/bin`,
|
|
@@ -15490,7 +15684,7 @@ function pathValue() {
|
|
|
15490
15684
|
].join(":");
|
|
15491
15685
|
}
|
|
15492
15686
|
function writeExecutable(path, content) {
|
|
15493
|
-
mkdirSync19(
|
|
15687
|
+
mkdirSync19(dirname16(path), { recursive: true });
|
|
15494
15688
|
writeFileSync20(path, content, { mode: 493 });
|
|
15495
15689
|
}
|
|
15496
15690
|
function pauseMarkerPath(projectPath, slug) {
|
|
@@ -15617,7 +15811,7 @@ Loop \u5DF2\u505C\u7528(loop/dream/pr \u5747\u5DF2\u5378\u8F7D)
|
|
|
15617
15811
|
async function loopPauseCommand(_args, deps = realDeps3()) {
|
|
15618
15812
|
const id = await deps.identity();
|
|
15619
15813
|
const marker = pauseMarkerPath(id.path, id.slug);
|
|
15620
|
-
mkdirSync19(
|
|
15814
|
+
mkdirSync19(dirname16(marker), { recursive: true });
|
|
15621
15815
|
const already = existsSync37(marker);
|
|
15622
15816
|
if (!already)
|
|
15623
15817
|
writeFileSync20(marker, `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
@@ -15699,7 +15893,7 @@ cycle finished \u2014 logs: .roll/loop/cron.log \xB7 .roll/loop/cycle-logs/
|
|
|
15699
15893
|
// packages/cli/dist/commands/migrate.js
|
|
15700
15894
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
15701
15895
|
import { existsSync as existsSync38, mkdirSync as mkdirSync20 } from "node:fs";
|
|
15702
|
-
import { dirname as
|
|
15896
|
+
import { dirname as dirname17 } from "node:path";
|
|
15703
15897
|
function colors() {
|
|
15704
15898
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
15705
15899
|
return noColor2 ? { RED: "", GREEN: "", YELLOW: "", CYAN: "", NC: "" } : {
|
|
@@ -15818,7 +16012,7 @@ function migrateExecute(activeMoves) {
|
|
|
15818
16012
|
for (const move of activeMoves) {
|
|
15819
16013
|
const src = srcOf(move);
|
|
15820
16014
|
const tgt = tgtOf(move);
|
|
15821
|
-
const targetDir =
|
|
16015
|
+
const targetDir = dirname17(tgt);
|
|
15822
16016
|
if (!existsSync38(targetDir))
|
|
15823
16017
|
mkdirSync20(targetDir, { recursive: true });
|
|
15824
16018
|
const r = git3(["mv", src, tgt]);
|
|
@@ -16009,7 +16203,7 @@ function migrateFeaturesCommand(args) {
|
|
|
16009
16203
|
// packages/cli/dist/commands/offboard.js
|
|
16010
16204
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
16011
16205
|
import { existsSync as existsSync40, readFileSync as readFileSync31, realpathSync as realpathSync5, rmSync as rmSync10, writeFileSync as writeFileSync22 } from "node:fs";
|
|
16012
|
-
import { homedir as
|
|
16206
|
+
import { homedir as homedir16 } from "node:os";
|
|
16013
16207
|
import { join as join36, resolve as resolve2 } from "node:path";
|
|
16014
16208
|
function pal3() {
|
|
16015
16209
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
@@ -16058,7 +16252,7 @@ function runLaunchctl(args) {
|
|
|
16058
16252
|
if (args[0] !== void 0 && readOnly.has(args[0])) {
|
|
16059
16253
|
return spawnSync8("launchctl", args, { stdio: "inherit" }).status ?? 1;
|
|
16060
16254
|
}
|
|
16061
|
-
const canonical = join36(
|
|
16255
|
+
const canonical = join36(homedir16(), "Library", "LaunchAgents");
|
|
16062
16256
|
const launchdDir = process.env["_LAUNCHD_DIR"] ?? canonical;
|
|
16063
16257
|
if (launchdDir !== canonical)
|
|
16064
16258
|
return 0;
|
|
@@ -16240,7 +16434,7 @@ function offboardCommand(args) {
|
|
|
16240
16434
|
}
|
|
16241
16435
|
}
|
|
16242
16436
|
for (const item of plists) {
|
|
16243
|
-
const plistPath = join36(
|
|
16437
|
+
const plistPath = join36(homedir16(), "Library", "LaunchAgents", item);
|
|
16244
16438
|
const r = runLaunchctl(["unload", "-w", plistPath]);
|
|
16245
16439
|
if (r === 0)
|
|
16246
16440
|
process.stdout.write(` unloaded ${item}
|
|
@@ -16711,7 +16905,7 @@ import { join as join41 } from "node:path";
|
|
|
16711
16905
|
|
|
16712
16906
|
// packages/cli/dist/commands/slides/render.js
|
|
16713
16907
|
import { readFileSync as readFileSync35, existsSync as existsSync44, readdirSync as readdirSync18, statSync as statSync19 } from "node:fs";
|
|
16714
|
-
import { join as join40, dirname as
|
|
16908
|
+
import { join as join40, dirname as dirname18, basename as basename9 } from "node:path";
|
|
16715
16909
|
function coerceScalar(v) {
|
|
16716
16910
|
if (v.length >= 2 && v[0] === v[v.length - 1] && (v[0] === "'" || v[0] === '"')) {
|
|
16717
16911
|
return v.slice(1, -1);
|
|
@@ -17283,7 +17477,7 @@ function isFile(p) {
|
|
|
17283
17477
|
function libDirFor(_metaUrl) {
|
|
17284
17478
|
void _metaUrl;
|
|
17285
17479
|
void existsSync44;
|
|
17286
|
-
void
|
|
17480
|
+
void dirname18;
|
|
17287
17481
|
return join40(repoLibFallback(), "lib");
|
|
17288
17482
|
}
|
|
17289
17483
|
function repoLibFallback() {
|
|
@@ -17291,7 +17485,7 @@ function repoLibFallback() {
|
|
|
17291
17485
|
for (let i = 0; i < 12; i++) {
|
|
17292
17486
|
if (existsSync44(join40(dir, "bin", "roll")))
|
|
17293
17487
|
return dir;
|
|
17294
|
-
const parent =
|
|
17488
|
+
const parent = dirname18(dir);
|
|
17295
17489
|
if (parent === dir)
|
|
17296
17490
|
break;
|
|
17297
17491
|
dir = parent;
|
|
@@ -18214,10 +18408,10 @@ function rowThree(a, b, c2) {
|
|
|
18214
18408
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
18215
18409
|
import { createHash as createHash5 } from "node:crypto";
|
|
18216
18410
|
import { existsSync as existsSync45, lstatSync as lstatSync4, readdirSync as readdirSync20, readFileSync as readFileSync38, realpathSync as realpathSync6, statSync as statSync22 } from "node:fs";
|
|
18217
|
-
import { homedir as
|
|
18218
|
-
import { basename as basename10, dirname as
|
|
18411
|
+
import { homedir as homedir17 } from "node:os";
|
|
18412
|
+
import { basename as basename10, dirname as dirname19, join as join42 } from "node:path";
|
|
18219
18413
|
function rollHome3() {
|
|
18220
|
-
return process.env["ROLL_HOME"] ?? join42(
|
|
18414
|
+
return process.env["ROLL_HOME"] ?? join42(homedir17(), ".roll");
|
|
18221
18415
|
}
|
|
18222
18416
|
var globalDir = () => join42(rollHome3(), "conventions", "global");
|
|
18223
18417
|
var templatesDir = () => join42(rollHome3(), "conventions", "templates");
|
|
@@ -18251,7 +18445,7 @@ function parseAiEntries() {
|
|
|
18251
18445
|
const m7 = /^ai_[a-z]+:\s*(.+)/.exec(line);
|
|
18252
18446
|
if (m7 === null)
|
|
18253
18447
|
continue;
|
|
18254
|
-
const val = (m7[1] ?? "").trim().replaceAll("~",
|
|
18448
|
+
const val = (m7[1] ?? "").trim().replaceAll("~", homedir17());
|
|
18255
18449
|
const parts = val.split("|");
|
|
18256
18450
|
if (parts.length < 3)
|
|
18257
18451
|
continue;
|
|
@@ -18260,7 +18454,7 @@ function parseAiEntries() {
|
|
|
18260
18454
|
const srcFile = (parts[2] ?? "").trim();
|
|
18261
18455
|
let name = basename10(aiDir).replace(/^\.+/, "");
|
|
18262
18456
|
if (name === "workspace" || name === "agent") {
|
|
18263
|
-
name = basename10(
|
|
18457
|
+
name = basename10(dirname19(aiDir)).replace(/^\.+/, "");
|
|
18264
18458
|
}
|
|
18265
18459
|
entries.push({ name, ai_dir: aiDir, cfg_file: cfgFile, src_file: srcFile });
|
|
18266
18460
|
}
|
|
@@ -18341,7 +18535,7 @@ function skillsInstalled() {
|
|
|
18341
18535
|
}
|
|
18342
18536
|
function launchdState(service, slug) {
|
|
18343
18537
|
const label4 = `com.roll.${service}.${slug}`;
|
|
18344
|
-
const plist = join42(
|
|
18538
|
+
const plist = join42(homedir17(), "Library", "LaunchAgents", `${label4}.plist`);
|
|
18345
18539
|
if (!existsSync45(plist))
|
|
18346
18540
|
return "not-installed";
|
|
18347
18541
|
try {
|
|
@@ -18476,7 +18670,7 @@ function renderThisProject(out2, d) {
|
|
|
18476
18670
|
}
|
|
18477
18671
|
function liveData() {
|
|
18478
18672
|
const slug = projectSlugPy();
|
|
18479
|
-
const home =
|
|
18673
|
+
const home = homedir17();
|
|
18480
18674
|
const aiClients = parseAiEntries().map((e) => ({
|
|
18481
18675
|
name: e.name,
|
|
18482
18676
|
cfg_file: e.cfg_file,
|
|
@@ -18520,7 +18714,7 @@ function statusCommand(args) {
|
|
|
18520
18714
|
// packages/cli/dist/commands/test.js
|
|
18521
18715
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
18522
18716
|
import { existsSync as existsSync46, mkdirSync as mkdirSync24, readFileSync as readFileSync39, rmSync as rmSync12, writeFileSync as writeFileSync24 } from "node:fs";
|
|
18523
|
-
import { dirname as
|
|
18717
|
+
import { dirname as dirname20, join as join43 } from "node:path";
|
|
18524
18718
|
function pal5() {
|
|
18525
18719
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
18526
18720
|
return noColor2 ? { CYAN: "", GREEN: "", YELLOW: "", RED: "", NC: "" } : { CYAN: "\x1B[0;36m", GREEN: "\x1B[0;32m", YELLOW: "\x1B[0;33m", RED: "\x1B[0;31m", NC: "\x1B[0m" };
|
|
@@ -18596,7 +18790,7 @@ function resetAcquireLock() {
|
|
|
18596
18790
|
const lock = resetLockPath();
|
|
18597
18791
|
if (existsSync46(lock))
|
|
18598
18792
|
return false;
|
|
18599
|
-
mkdirSync24(
|
|
18793
|
+
mkdirSync24(dirname20(lock), { recursive: true });
|
|
18600
18794
|
writeFileSync24(lock, `${process.pid}
|
|
18601
18795
|
`);
|
|
18602
18796
|
return true;
|