@virtengine/openfleet 0.25.0 → 0.26.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.
package/.env.example CHANGED
@@ -735,11 +735,15 @@ COMPLEXITY_ROUTING_ENABLED=true
735
735
  # COMPLEXITY_ROUTING_CODEX_LOW_REASONING=low
736
736
  # COMPLEXITY_ROUTING_CODEX_MEDIUM_MODEL=gpt-5.2-codex
737
737
  # COMPLEXITY_ROUTING_CODEX_MEDIUM_VARIANT=DEFAULT
738
+ # COMPLEXITY_ROUTING_CODEX_MEDIUM_REASONING=medium
738
739
  # COMPLEXITY_ROUTING_CODEX_HIGH_MODEL=gpt-5.1-codex-max
739
740
  # COMPLEXITY_ROUTING_CODEX_HIGH_VARIANT=GPT51_CODEX_MAX
740
- # COMPLEXITY_ROUTING_COPILOT_LOW_MODEL=haiku-4.5
741
- # COMPLEXITY_ROUTING_COPILOT_MEDIUM_MODEL=sonnet-4.5
742
- # COMPLEXITY_ROUTING_COPILOT_HIGH_MODEL=opus-4.6
741
+ # COMPLEXITY_ROUTING_CODEX_HIGH_REASONING=high
742
+ # COMPLEXITY_ROUTING_COPILOT_LOW_MODEL=claude-haiku-4.5
743
+ # COMPLEXITY_ROUTING_COPILOT_MEDIUM_MODEL=claude-sonnet-4.5
744
+ # COMPLEXITY_ROUTING_COPILOT_MEDIUM_REASONING=medium
745
+ # COMPLEXITY_ROUTING_COPILOT_HIGH_MODEL=claude-opus-4.6
746
+ # COMPLEXITY_ROUTING_COPILOT_HIGH_REASONING=high
743
747
 
744
748
  # ─── Shared Cloud Workspaces ────────────────────────────────────────────────
745
749
  # Registry file for shared workspace leasing (default: .cache/openfleet/shared-workspaces.json)
package/cli.mjs CHANGED
@@ -689,6 +689,68 @@ async function main() {
689
689
  console.log("\n Setup complete! Starting openfleet...\n");
690
690
  }
691
691
 
692
+ // ── Handle --echo-logs: tail the active monitor's log instead of spawning a new instance ──
693
+ if (args.includes("--echo-logs")) {
694
+ // Search for the monitor PID file in common cache locations
695
+ const candidatePidFiles = [
696
+ process.env.CODEX_MONITOR_DIR
697
+ ? resolve(process.env.CODEX_MONITOR_DIR, ".cache", "openfleet.pid")
698
+ : null,
699
+ resolve(__dirname, "..", ".cache", "openfleet.pid"),
700
+ resolve(process.cwd(), ".cache", "openfleet.pid"),
701
+ ].filter(Boolean);
702
+
703
+ let activePidFile = null;
704
+ for (const f of candidatePidFiles) {
705
+ if (existsSync(f)) {
706
+ activePidFile = f;
707
+ break;
708
+ }
709
+ }
710
+
711
+ if (activePidFile) {
712
+ try {
713
+ const pidData = JSON.parse(readFileSync(activePidFile, "utf8"));
714
+ const monitorPid = Number(pidData.pid);
715
+ const monitorPath = (pidData.argv || [])[1] || "";
716
+
717
+ let isAlive = false;
718
+ try {
719
+ process.kill(monitorPid, 0);
720
+ isAlive = true;
721
+ } catch {}
722
+
723
+ if (isAlive && monitorPath) {
724
+ const logDir = resolve(dirname(monitorPath), "logs");
725
+ const daemonLog = resolve(logDir, "daemon.log");
726
+ const monitorLog = resolve(logDir, "monitor.log");
727
+ const logFile = existsSync(daemonLog) ? daemonLog : monitorLog;
728
+
729
+ if (existsSync(logFile)) {
730
+ console.log(
731
+ `\n Tailing logs for active openfleet (PID ${monitorPid}):\n ${logFile}\n`,
732
+ );
733
+ await new Promise((res) => {
734
+ const tail = spawn("tail", ["-f", "-n", "200", logFile], {
735
+ stdio: "inherit",
736
+ });
737
+ tail.on("exit", res);
738
+ process.on("SIGINT", () => {
739
+ tail.kill();
740
+ res();
741
+ });
742
+ });
743
+ process.exit(0);
744
+ }
745
+ }
746
+ } catch {
747
+ // best-effort — fall through to normal start
748
+ }
749
+ }
750
+
751
+ // No active monitor found — start normally; echoLogs will be picked up by config.mjs
752
+ }
753
+
692
754
  // Fork monitor as a child process — enables self-restart on source changes.
693
755
  // When monitor exits with code 75, cli re-forks with a fresh ESM module cache.
694
756
  await runMonitor();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@virtengine/openfleet",
3
- "version": "0.25.0",
3
+ "version": "0.26.1",
4
4
  "description": "AI-powered orchestrator supervisor — manages AI agent executors with failover, auto-restarts on failure, analyzes crashes with Codex SDK, creates PRs via Vibe-Kanban API, and sends Telegram notifications. Supports N executors with weighted distribution, multi-repo projects, and auto-setup.",
5
5
  "type": "module",
6
6
  "license": "Apache 2.0",
@@ -92,7 +92,11 @@
92
92
  "prepush:check": "npm run syntax:check && npm test",
93
93
  "prepublishOnly": "node prepublish-check.mjs",
94
94
  "publish:env": "node publish.mjs",
95
- "publish:dry-run": "node publish.mjs --dry-run"
95
+ "publish:dry-run": "node publish.mjs --dry-run",
96
+ "publish:minor": "node publish.mjs --bump minor",
97
+ "publish:major": "node publish.mjs --bump major",
98
+ "publish:minor:dry": "node publish.mjs --bump minor --dry-run",
99
+ "publish:major:dry": "node publish.mjs --bump major --dry-run"
96
100
  },
97
101
  "files": [
98
102
  ".env.example",
package/publish.mjs CHANGED
@@ -1,7 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ //
3
+ // Usage:
4
+ // node publish.mjs # publish at current version
5
+ // node publish.mjs --bump minor # 0.25.0 → 0.25.1 (patch digit)
6
+ // node publish.mjs --bump major # 0.25.0 → 0.26.0 (minor digit)
7
+ // node publish.mjs --bump minor --dry-run
8
+ //
9
+ // Terminology matches the openfleet convention (not semver):
10
+ // minor = last digit (semver patch)
11
+ // major = middle digit (semver minor)
2
12
 
3
13
  import { spawnSync } from "node:child_process";
4
- import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
14
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
5
15
  import { tmpdir } from "node:os";
6
16
  import { join, resolve } from "node:path";
7
17
  import { fileURLToPath } from "node:url";
@@ -64,8 +74,82 @@ function runCheck(label, command, args, env) {
64
74
 
65
75
  const NPM_BIN = "npm";
66
76
 
77
+ /**
78
+ * Bump the version in package.json and sync package-lock.json.
79
+ * type: "minor" → patch digit (0.25.0 → 0.25.1)
80
+ * "major" → middle digit (0.25.0 → 0.26.0)
81
+ * Returns the new version string.
82
+ */
83
+ function bumpVersion(type, dryRun) {
84
+ const pkgPath = resolve(SCRIPT_DIR, "package.json");
85
+ const lockPath = resolve(SCRIPT_DIR, "package-lock.json");
86
+
87
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
88
+ const [maj, mid, pat] = pkg.version.split(".").map(Number);
89
+
90
+ let newVersion;
91
+ if (type === "minor") {
92
+ // minor = patch digit (last number)
93
+ newVersion = `${maj}.${mid}.${pat + 1}`;
94
+ } else if (type === "major") {
95
+ // major = middle digit, reset patch
96
+ newVersion = `${maj}.${mid + 1}.0`;
97
+ } else {
98
+ console.error(
99
+ `[publish] Unknown bump type "${type}". Use "minor" (0.25.0→0.25.1) or "major" (0.25.0→0.26.0).`,
100
+ );
101
+ process.exit(1);
102
+ }
103
+
104
+ console.log(`[publish] Bumping version: ${pkg.version} → ${newVersion}`);
105
+
106
+ if (!dryRun) {
107
+ pkg.version = newVersion;
108
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
109
+
110
+ // Update package-lock.json in-place
111
+ try {
112
+ const lock = JSON.parse(readFileSync(lockPath, "utf8"));
113
+ lock.version = newVersion;
114
+ if (lock.packages?.[""] != null) {
115
+ lock.packages[""].version = newVersion;
116
+ }
117
+ writeFileSync(lockPath, JSON.stringify(lock, null, 2) + "\n", "utf8");
118
+ console.log(
119
+ `[publish] package.json + package-lock.json updated to ${newVersion}`,
120
+ );
121
+ } catch {
122
+ console.warn(
123
+ "[publish] Could not update package-lock.json — regenerating...",
124
+ );
125
+ spawnSync(NPM_BIN, ["install", "--package-lock-only", "--ignore-scripts"], {
126
+ stdio: "inherit",
127
+ cwd: SCRIPT_DIR,
128
+ shell: true,
129
+ });
130
+ }
131
+ } else {
132
+ console.log(
133
+ `[publish] dry-run: would write version ${newVersion} to package.json & package-lock.json`,
134
+ );
135
+ }
136
+
137
+ return newVersion;
138
+ }
139
+
140
+ function getBumpArg() {
141
+ const idx = process.argv.indexOf("--bump");
142
+ if (idx !== -1 && process.argv[idx + 1]) return process.argv[idx + 1];
143
+ const flag = process.argv.find((a) => a.startsWith("--bump="));
144
+ if (flag) return flag.slice(7);
145
+ return null;
146
+ }
147
+
67
148
  function main() {
149
+ const bumpType = getBumpArg();
68
150
  const dryRun = hasArg("--dry-run");
151
+ if (bumpType) bumpVersion(bumpType, dryRun);
152
+
69
153
  const tag = process.env.NPM_PUBLISH_TAG || "latest";
70
154
  const otp = process.env.NPM_OTP || "";
71
155
  const access = process.env.NPM_PUBLISH_ACCESS || "public";
package/telegram-bot.mjs CHANGED
@@ -2614,7 +2614,7 @@ async function clearWebAppMenuButton() {
2614
2614
  }
2615
2615
  }
2616
2616
 
2617
- const MENU_BUTTON_REFRESH_MS = 5 * 60 * 1000; // 5 minutes
2617
+ const MENU_BUTTON_REFRESH_MS = 60 * 1000; // 1 minute — re-sync after tunnel URL rotates
2618
2618
 
2619
2619
  async function refreshMenuButton() {
2620
2620
  const { uiUrl: currentUiUrl, webAppUrl: currentUrl } = syncUiUrlsFromServer();