@seanyao/roll 4.713.2 → 4.714.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/roll.mjs +109 -11
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v4.714.2 — 2026-07-14
6
+
7
+ ### 稳定性
8
+ - agent 用哪个 model 现在完全由配置决定(`.roll/agents.yaml` 的 `rigs:`/`routing:`),源码不再写死运行时默认。以前缺配置会**静默**落到源码里写死的值(reasonix 一直跑 flash),配置丢了都发现不了;现在缺配置会**明确报错并引导**(需要显式 model 的 agent),配好的 model 一路带到 spawn。改某个 agent 的 model = 编辑一行配置,不用动源码、不用重新发版 (FIX-1249) `[loop]`
9
+
10
+ ## v4.714.1 — 2026-07-14
11
+
12
+ ### 稳定性
13
+ - roll 给用户项目自动合并 PR 时,现在同时认 GitHub 的两种检查状态——Actions 运行**和** commit status / 外部 check-run(取二者并集)。以前只看 Actions,导致用别的 CI 上报状态的项目里"其实全绿"的 PR 被误判成"状态未知"而一直卡着不自动合并、账也对不上;现在全绿(不论来自哪种)照常自动合,状态未知/进行中的按"等待"处理而非误判失败 (FIX-1248) `[loop]`
14
+
5
15
  ## v4.713.2 — 2026-07-13
6
16
 
7
17
  ### 自动化流水线
package/dist/roll.mjs CHANGED
@@ -4369,6 +4369,15 @@ function normalizeAgentConfig(text2) {
4369
4369
  errors
4370
4370
  };
4371
4371
  }
4372
+ function readRouteSlot(text2, slot) {
4373
+ const { config } = normalizeAgentConfig(text2);
4374
+ const resolved = config.routing[slot];
4375
+ if (resolved !== void 0) {
4376
+ const { agent, model } = resolved.rig;
4377
+ return model !== void 0 && model !== "" ? { agent, model } : { agent };
4378
+ }
4379
+ return readSlotFromText(text2, slot);
4380
+ }
4372
4381
  var DEFAULT_STANDARD;
4373
4382
  var init_config_v4 = __esm({
4374
4383
  "packages/core/dist/agent/config-v4.js"() {
@@ -4382,6 +4391,24 @@ var init_config_v4 = __esm({
4382
4391
  }
4383
4392
  });
4384
4393
 
4394
+ // packages/core/dist/agent/model-config.js
4395
+ function configuredModelForAgent(agent, config) {
4396
+ const canonical = canonicalAgentName(agent);
4397
+ for (const rig of Object.values(config.rigs)) {
4398
+ if (canonicalAgentName(rig.agent) === canonical && rig.model !== void 0 && rig.model !== "") {
4399
+ return rig.model;
4400
+ }
4401
+ }
4402
+ return void 0;
4403
+ }
4404
+ var init_model_config = __esm({
4405
+ "packages/core/dist/agent/model-config.js"() {
4406
+ "use strict";
4407
+ init_registry();
4408
+ init_specs();
4409
+ }
4410
+ });
4411
+
4385
4412
  // packages/core/dist/agent/scope-config.js
4386
4413
  function isMap2(v) {
4387
4414
  return typeof v === "object" && v !== null;
@@ -18228,6 +18255,7 @@ var init_dist2 = __esm({
18228
18255
  init_registry();
18229
18256
  init_specs();
18230
18257
  init_config_v4();
18258
+ init_model_config();
18231
18259
  init_scope_config();
18232
18260
  init_scope_resolver();
18233
18261
  init_scope_migration();
@@ -19388,6 +19416,7 @@ __export(github_exports, {
19388
19416
  prViewHeadRef: () => prViewHeadRef,
19389
19417
  prViewMergeInfo: () => prViewMergeInfo,
19390
19418
  prViewState: () => prViewState,
19419
+ prViewStatusCheckRollup: () => prViewStatusCheckRollup,
19391
19420
  prViewUrl: () => prViewUrl,
19392
19421
  rawGh: () => rawGh,
19393
19422
  repoViewSlug: () => repoViewSlug,
@@ -19592,6 +19621,17 @@ async function prViewMergeInfo(slug3, ref) {
19592
19621
  return void 0;
19593
19622
  }
19594
19623
  }
19624
+ async function prViewStatusCheckRollup(slug3, ref) {
19625
+ const r = await gh(["-R", slug3, "pr", "view", ref, "--json", "statusCheckRollup"]);
19626
+ if (r.code !== 0 || r.stdout.trim() === "")
19627
+ return [];
19628
+ try {
19629
+ const j = JSON.parse(r.stdout);
19630
+ return Array.isArray(j.statusCheckRollup) ? j.statusCheckRollup : [];
19631
+ } catch {
19632
+ return [];
19633
+ }
19634
+ }
19595
19635
  async function prCreate(input) {
19596
19636
  const base = input.base ?? "main";
19597
19637
  const r = await invokeInfraTool({
@@ -20035,11 +20075,47 @@ function reduceRunConclusions(conclusions) {
20035
20075
  }
20036
20076
  return "pending";
20037
20077
  }
20038
- var GitHubPrStatusProvider, githubPrStatusProvider;
20078
+ function reduceRollupEntry(e) {
20079
+ if (e.__typename === "StatusContext") {
20080
+ const state = e.state ?? "";
20081
+ if (state === "FAILURE" || state === "ERROR")
20082
+ return "red";
20083
+ if (state === "SUCCESS")
20084
+ return "green";
20085
+ return "pending";
20086
+ }
20087
+ if (e.status !== "COMPLETED")
20088
+ return "pending";
20089
+ const conclusion = e.conclusion;
20090
+ if (conclusion == null)
20091
+ return "pending";
20092
+ return GREEN_CONCLUSIONS.has(conclusion) ? "green" : "red";
20093
+ }
20094
+ function reduceStatusCheckRollup(entries) {
20095
+ if (entries.length === 0)
20096
+ return "unknown";
20097
+ const states = entries.map(reduceRollupEntry);
20098
+ if (states.some((s) => s === "red"))
20099
+ return "red";
20100
+ if (states.some((s) => s === "pending"))
20101
+ return "pending";
20102
+ return "green";
20103
+ }
20104
+ function mergeCiStates(a, b) {
20105
+ if (a === "red" || b === "red")
20106
+ return "red";
20107
+ if (a === "pending" || b === "pending")
20108
+ return "pending";
20109
+ if (a === "unknown" && b === "unknown")
20110
+ return "unknown";
20111
+ return "green";
20112
+ }
20113
+ var GREEN_CONCLUSIONS, GitHubPrStatusProvider, githubPrStatusProvider;
20039
20114
  var init_pr_provider = __esm({
20040
20115
  "packages/infra/dist/pr-provider.js"() {
20041
20116
  "use strict";
20042
20117
  init_github();
20118
+ GREEN_CONCLUSIONS = /* @__PURE__ */ new Set(["SUCCESS", "SKIPPED", "NEUTRAL"]);
20043
20119
  GitHubPrStatusProvider = class {
20044
20120
  name = "github";
20045
20121
  /**
@@ -20070,9 +20146,11 @@ var init_pr_provider = __esm({
20070
20146
  }
20071
20147
  if (state === "OPEN") {
20072
20148
  const branch = info6.headRefName;
20073
- const runs = branch !== void 0 ? await runList(s, "conclusion", { branch }) : [];
20074
- const conclusions = runs.map((r) => r.conclusion);
20075
- const ci = reduceRunConclusions(conclusions);
20149
+ const [runs, rollup] = await Promise.all([
20150
+ branch !== void 0 ? runList(s, "conclusion", { branch }) : Promise.resolve([]),
20151
+ prViewStatusCheckRollup(s, String(prNumber))
20152
+ ]);
20153
+ const ci = mergeCiStates(reduceRunConclusions(runs.map((r) => r.conclusion)), reduceStatusCheckRollup(rollup));
20076
20154
  return { kind: "open", ci, draft: info6.isDraft, mergeable: info6.mergeable, checkedAt };
20077
20155
  }
20078
20156
  return { kind: "unreachable", reason: "provider_error", checkedAt };
@@ -23723,6 +23801,7 @@ __export(dist_exports, {
23723
23801
  lsRemote: () => lsRemote,
23724
23802
  mcpTools: () => mcpTools,
23725
23803
  mergeBase: () => mergeBase,
23804
+ mergeCiStates: () => mergeCiStates,
23726
23805
  networkTools: () => networkTools,
23727
23806
  newSession: () => newSession,
23728
23807
  openEvidenceFrame: () => openEvidenceFrame,
@@ -23751,6 +23830,7 @@ __export(dist_exports, {
23751
23830
  prViewHeadRef: () => prViewHeadRef,
23752
23831
  prViewMergeInfo: () => prViewMergeInfo,
23753
23832
  prViewState: () => prViewState,
23833
+ prViewStatusCheckRollup: () => prViewStatusCheckRollup,
23754
23834
  prViewUrl: () => prViewUrl,
23755
23835
  projectConfigPath: () => projectConfigPath,
23756
23836
  projectIdentity: () => projectIdentity,
@@ -23764,6 +23844,8 @@ __export(dist_exports, {
23764
23844
  readPngDimensions: () => readPngDimensions,
23765
23845
  redactInfraToolValue: () => redactInfraToolValue,
23766
23846
  redactSecrets: () => redactSecrets,
23847
+ reduceRunConclusions: () => reduceRunConclusions,
23848
+ reduceStatusCheckRollup: () => reduceStatusCheckRollup,
23767
23849
  reinstall: () => reinstall,
23768
23850
  releaseLock: () => releaseLock,
23769
23851
  remoteUrl: () => remoteUrl,
@@ -237572,14 +237654,14 @@ var AGENT_PROFILES = {
237572
237654
  secretEnv: ["DEEPSEEK_API_KEY"],
237573
237655
  buildSpawnCommand: (opts) => {
237574
237656
  const routedModel = opts.model?.trim();
237575
- const model = routedModel !== void 0 && routedModel !== "" ? routedModel : getAgentSpec("reasonix")?.defaultModel ?? "deepseek-flash";
237657
+ const modelArgs = routedModel !== void 0 && routedModel !== "" ? ["--model", routedModel] : [];
237576
237658
  const maxSteps = opts.maxSteps ?? 1e3;
237577
237659
  const roots = writableRootsForSpawn(opts);
237578
237660
  if (roots.length > 0)
237579
237661
  opts.cleanup = chainCleanup(opts.cleanup, writeReasonixSandboxConfig(opts.cwd, roots));
237580
237662
  return {
237581
237663
  bin: opts.bin ?? "reasonix",
237582
- args: ["run", "--max-steps", String(maxSteps), "--model", model, "--dir", opts.cwd, agentPrompt(opts)]
237664
+ args: ["run", "--max-steps", String(maxSteps), ...modelArgs, "--dir", opts.cwd, agentPrompt(opts)]
237583
237665
  };
237584
237666
  },
237585
237667
  childEnv: reasonixEnv
@@ -269105,7 +269187,7 @@ function applyPrCloudState(facts, st) {
269105
269187
  return;
269106
269188
  case "open":
269107
269189
  facts.prState = "OPEN";
269108
- facts.ciGreen = st.ci === "green";
269190
+ facts.ciGreen = st.ci === "green" ? true : st.ci === "red" ? false : void 0;
269109
269191
  facts.prDraft = st.draft;
269110
269192
  facts.prMergeable = st.mergeable;
269111
269193
  return;
@@ -275955,15 +276037,27 @@ function clearSelfHeal(runtimeDir11, storyId) {
275955
276037
 
275956
276038
  // packages/cli/dist/runner/node-ports.js
275957
276039
  var execFileAsync16 = promisify16(execFile16);
276040
+ function configuredModelBackstop(repoCwd, agent) {
276041
+ if (agent === "")
276042
+ return "";
276043
+ try {
276044
+ const { config } = normalizeAgentConfig(readFileSync120(join137(repoCwd, ".roll", "agents.yaml"), "utf8"));
276045
+ return configuredModelForAgent(agent, config) ?? "";
276046
+ } catch {
276047
+ return "";
276048
+ }
276049
+ }
275958
276050
  function scopedStoryExecuteRoute(repoCwd) {
275959
276051
  const scoped = resolveScopedStoryExecute(repoCwd);
275960
276052
  if (scoped === null)
275961
276053
  return null;
275962
276054
  const { resolution } = scoped;
275963
276055
  if (resolution.ok) {
276056
+ const agent = resolution.resolved.agent;
276057
+ const model = resolution.resolved.model ?? "";
275964
276058
  return {
275965
- agent: resolution.resolved.agent,
275966
- model: resolution.resolved.model ?? ""
276059
+ agent,
276060
+ model: model !== "" ? model : configuredModelBackstop(repoCwd, agent)
275967
276061
  };
275968
276062
  }
275969
276063
  const hasScopedBindingFailure = resolution.failure.source !== void 0 || resolution.failure.candidates.length > 0;
@@ -276216,7 +276310,11 @@ function nodePorts(opts) {
276216
276310
  const rt = (process.env["ROLL_PROJECT_RUNTIME_DIR"] ?? "").trim() || join137(opts.repoCwd, ".roll", "loop");
276217
276311
  const tried = storyId !== "" ? readSelfHeal(rt, storyId).triedAgents : [];
276218
276312
  const dec = tried.length > 0 ? resolveRouteExcluding(tier, routeDeps, tried) ?? resolveRoute(tier, routeDeps) : resolveRoute(tier, routeDeps);
276219
- return { agent: dec.agent, model: dec.model ?? "" };
276313
+ const routedModel = dec.model ?? "";
276314
+ return {
276315
+ agent: dec.agent,
276316
+ model: routedModel !== "" ? routedModel : configuredModelBackstop(opts.repoCwd, dec.agent)
276317
+ };
276220
276318
  }
276221
276319
  } : { resolve: () => ({ agent: "claude", model: "" }) },
276222
276320
  evidence: {
@@ -277255,7 +277353,7 @@ function buildLoopRouteDeps(projectPath3) {
277255
277353
  function readSlot(slot) {
277256
277354
  const agentsYaml = join139(projectPath3, ".roll", "agents.yaml");
277257
277355
  try {
277258
- return readSlotFromText(readFileSync124(agentsYaml, "utf8"), slot);
277356
+ return readRouteSlot(readFileSync124(agentsYaml, "utf8"), slot);
277259
277357
  } catch {
277260
277358
  return void 0;
277261
277359
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seanyao/roll",
3
- "version": "4.713.2",
3
+ "version": "4.714.2",
4
4
  "description": "Roll — Roll out features with AI agents",
5
5
  "packageManager": "pnpm@11.1.3",
6
6
  "scripts": {