@factiii/runner 0.11.0 → 0.11.1

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 (2) hide show
  1. package/dist/cli.js +102 -8
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -13465,10 +13465,12 @@ function execLogin(command, opts) {
13465
13465
  let output = "";
13466
13466
  let settled = false;
13467
13467
  let timer;
13468
+ let idleTimer;
13468
13469
  const done = (code, extra = "") => {
13469
13470
  if (settled) return;
13470
13471
  settled = true;
13471
13472
  if (timer) clearTimeout(timer);
13473
+ if (idleTimer) clearTimeout(idleTimer);
13472
13474
  resolve2({ code, output: (output + extra).slice(-cap) });
13473
13475
  };
13474
13476
  let proc;
@@ -13490,9 +13492,22 @@ function execLogin(command, opts) {
13490
13492
  done(-1, `
13491
13493
  [timed out after ${Math.round(opts.timeout / 1e3)}s]`);
13492
13494
  }, opts.timeout);
13495
+ const idleMs = opts.idleTimeout;
13496
+ const bumpIdle = () => {
13497
+ if (!idleMs) return;
13498
+ if (idleTimer) clearTimeout(idleTimer);
13499
+ idleTimer = setTimeout(() => {
13500
+ killTree(proc);
13501
+ const secs = Math.round(idleMs / 1e3);
13502
+ done(-1, `
13503
+ [no output for ${secs}s - timed out]`);
13504
+ }, idleMs);
13505
+ };
13506
+ bumpIdle();
13493
13507
  const collect = (chunk) => {
13494
13508
  output += chunk.toString("utf-8");
13495
13509
  if (output.length > cap * 2) output = output.slice(-cap);
13510
+ bumpIdle();
13496
13511
  opts.onOutput?.(output);
13497
13512
  };
13498
13513
  proc.stdout.on("data", collect);
@@ -14639,6 +14654,60 @@ async function checkDeployStatus(opts) {
14639
14654
  variables
14640
14655
  };
14641
14656
  }
14657
+ var RELEASE_BRANCH_LIMIT = 25;
14658
+ var BRANCH_FIELDS = "%(refname:short)%09%(committerdate:unix)";
14659
+ async function listReleaseBranches(opts) {
14660
+ const { workspace, branch } = await ensureWorkspaceClone(opts);
14661
+ await hostGit(workspace, "fetch", "origin", "--prune");
14662
+ let counted = true;
14663
+ let raw = "";
14664
+ try {
14665
+ raw = await hostGit(
14666
+ workspace,
14667
+ "for-each-ref",
14668
+ "--sort=-committerdate",
14669
+ `--format=${BRANCH_FIELDS}%09%(ahead-behind:refs/remotes/origin/${branch})%09%(contents:subject)`,
14670
+ "refs/remotes/origin"
14671
+ );
14672
+ } catch {
14673
+ counted = false;
14674
+ raw = await hostGit(
14675
+ workspace,
14676
+ "for-each-ref",
14677
+ "--sort=-committerdate",
14678
+ `--format=${BRANCH_FIELDS}%09%(contents:subject)`,
14679
+ "refs/remotes/origin"
14680
+ );
14681
+ }
14682
+ const branches = [];
14683
+ for (const row of raw.split("\n")) {
14684
+ if (branches.length >= RELEASE_BRANCH_LIMIT) break;
14685
+ const [ref = "", unix = "", ...rest] = row.split(" ");
14686
+ if (!ref.startsWith("origin/")) continue;
14687
+ const name = ref.slice("origin/".length);
14688
+ if (name === "HEAD" || name === branch) continue;
14689
+ let ahead = counted ? Number(rest.shift()?.split(" ")[0]) || 0 : 0;
14690
+ if (!counted) {
14691
+ try {
14692
+ const count = await hostGit(
14693
+ workspace,
14694
+ "rev-list",
14695
+ "--count",
14696
+ `origin/${branch}..${ref}`
14697
+ );
14698
+ ahead = Number(count.trim()) || 0;
14699
+ } catch {
14700
+ }
14701
+ }
14702
+ branches.push({
14703
+ name,
14704
+ ahead,
14705
+ updated: Number(unix) || 0,
14706
+ subject: rest.join(" ").trim()
14707
+ });
14708
+ }
14709
+ return branches;
14710
+ }
14642
14711
  var requiredVariableSchema = external_exports.object({
14643
14712
  key: external_exports.string().min(1),
14644
14713
  title: external_exports.string().catch(""),
@@ -18578,7 +18647,8 @@ var SECRETS_MARKER = "NEED_SECRETS:";
18578
18647
  var COMPLETE_MARKER = "DEPLOY_COMPLETE:";
18579
18648
  var FAILED_MARKER = "DEPLOY_FAILED:";
18580
18649
  var MAX_MARKERLESS_TURNS = 3;
18581
- var COMMAND_TIMEOUT_MS = 45 * 6e4;
18650
+ var COMMAND_IDLE_TIMEOUT_MS = 45 * 6e4;
18651
+ var COMMAND_TIMEOUT_MS = 6 * 60 * 6e4;
18582
18652
  var tail = (s, max = 8e3) => s.length > max ? s.slice(-max) : s;
18583
18653
  function tailMarker(text) {
18584
18654
  const zone = text.slice(-2e3);
@@ -18631,6 +18701,7 @@ async function authorizeAndRun(opts) {
18631
18701
  cwd: opts.cwd,
18632
18702
  env: { ...process.env, ...spaceEnv(opts.spaceDir), ...secrets },
18633
18703
  timeout: COMMAND_TIMEOUT_MS,
18704
+ idleTimeout: COMMAND_IDLE_TIMEOUT_MS,
18634
18705
  maxBuffer: 32 * 1024 * 1024
18635
18706
  });
18636
18707
  const output = redact(res.output);
@@ -18661,13 +18732,18 @@ async function startDeployRun(opts) {
18661
18732
  );
18662
18733
  await hostGit(workspace, "clean", "-fd");
18663
18734
  await ensureClaudeSkillLink(workspace);
18735
+ const release = (opts.releaseBranch || "").replace(/[^\w./-]/g, "");
18736
+ const releaseNote = release && release !== status.branch ? `The release branch for this run is \`${release}\` - it was chosen in the Deploy modal, so do not ask which branch to ship. Check it out as your first step.` : "";
18737
+ if (releaseNote) {
18738
+ hooks.sendLog({
18739
+ type: "system",
18740
+ content: `Release branch: ${release}`
18741
+ });
18742
+ }
18664
18743
  const contract = prompts_default.deployRun.join("\n");
18665
18744
  const reminder = "Reminder: every declared deploy variable is intentionally unset in your shell. Never check for them or abort over them - prefix any command that needs one with `factiii-secrets run --` and the runner injects the values.";
18666
- let prompt2 = opts.provider === "codex" ? `Use the "deploy" skill: load it and execute it step by step.
18667
-
18668
- ${reminder}` : `/deploy
18669
-
18670
- ${reminder}`;
18745
+ const opening = opts.provider === "codex" ? 'Use the "deploy" skill: load it and execute it step by step.' : "/deploy";
18746
+ let prompt2 = [opening, releaseNote, reminder].filter(Boolean).join("\n\n");
18671
18747
  let sessionId = "";
18672
18748
  let markerless = 0;
18673
18749
  let todos = [];
@@ -19713,6 +19789,20 @@ var BoardAgentEngine = class _BoardAgentEngine {
19713
19789
  githubToken: config.githubToken
19714
19790
  });
19715
19791
  }
19792
+ // What the Deploy modal's release picker offers: branches on origin that
19793
+ // could ship, newest first. See listReleaseBranches.
19794
+ async deployBranches() {
19795
+ const config = this.core.readConfig();
19796
+ if (!config.repoUrl || !config.githubToken) {
19797
+ throw new Error("Set the repository URL and GitHub token first.");
19798
+ }
19799
+ return listReleaseBranches({
19800
+ spaceDir: this.core.spaceDir(),
19801
+ repoUrl: config.repoUrl,
19802
+ mainBranch: config.mainBranch,
19803
+ githubToken: config.githubToken
19804
+ });
19805
+ }
19716
19806
  // ── Agent skills (SKILL.md) ──
19717
19807
  // Repo opts are optional here, unlike deploy: the global roots are readable
19718
19808
  // with no repo configured, and listSkills reports repoAvailable: false.
@@ -19874,7 +19964,7 @@ var BoardAgentEngine = class _BoardAgentEngine {
19874
19964
  return this.activity.clear("deploy-run");
19875
19965
  }
19876
19966
  }
19877
- deployRunStart(sendLog, provider) {
19967
+ deployRunStart(sendLog, provider, releaseBranch) {
19878
19968
  if (this.runState.phase === "running" || this.runState.phase === "awaiting-input" || this.runState.phase === "awaiting-auth") {
19879
19969
  throw new Error("A deploy run is already in progress.");
19880
19970
  }
@@ -19917,6 +20007,7 @@ var BoardAgentEngine = class _BoardAgentEngine {
19917
20007
  mainBranch: opts.mainBranch,
19918
20008
  githubToken: opts.githubToken,
19919
20009
  provider: opts.provider,
20010
+ releaseBranch,
19920
20011
  hooks: {
19921
20012
  sendLog: bufferLog,
19922
20013
  onTodos: (todos) => this.setRun({ todos }),
@@ -20964,6 +21055,8 @@ ${c.content.trim() || "(no description)"}`
20964
21055
  return await this.bareWorkNames();
20965
21056
  case "deployStatus":
20966
21057
  return await this.deployStatus();
21058
+ case "deployBranches":
21059
+ return await this.deployBranches();
20967
21060
  case "skillsList":
20968
21061
  return await this.skillsList();
20969
21062
  case "skillRead":
@@ -21018,7 +21111,8 @@ ${c.content.trim() || "(no description)"}`
21018
21111
  return this.deployRunStart(
21019
21112
  askLogSender ?? (() => {
21020
21113
  }),
21021
- payload?.provider
21114
+ payload?.provider,
21115
+ payload?.branch
21022
21116
  );
21023
21117
  case "deployRunState":
21024
21118
  return this.deployRunState();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@factiii/runner",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Factiii Runner, run Board AI agents on a machine you control. Pairs with the Factiii web/mobile clients over WebRTC.",
5
5
  "license": "ISC",
6
6
  "keywords": [