@spencer-kit/coder-studio 0.3.4 → 0.3.6

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.
@@ -385,34 +385,34 @@ var init_config = __esm({
385
385
  });
386
386
 
387
387
  // packages/core/src/runtime.ts
388
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
389
- import { homedir as homedir2 } from "node:os";
390
- import { dirname as dirname2, join as join2 } from "node:path";
388
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
389
+ import { homedir } from "node:os";
390
+ import { dirname, join } from "node:path";
391
391
  function getRuntimeDir() {
392
392
  const override = process.env.CODER_STUDIO_RUNTIME_DIR;
393
393
  if (override && override.trim()) {
394
394
  return override;
395
395
  }
396
- return join2(homedir2(), ".coder-studio");
396
+ return join(homedir(), ".coder-studio");
397
397
  }
398
398
  function getRuntimePath() {
399
399
  const pathOverride = process.env.CODER_STUDIO_RUNTIME_JSON_PATH;
400
400
  if (pathOverride && pathOverride.trim()) {
401
401
  return pathOverride;
402
402
  }
403
- return join2(getRuntimeDir(), "runtime.json");
403
+ return join(getRuntimeDir(), "runtime.json");
404
404
  }
405
405
  function writeRuntimeConfig(config) {
406
406
  const runtimePath = getRuntimePath();
407
- const runtimeDir = dirname2(runtimePath);
408
- if (!existsSync4(runtimeDir)) {
409
- mkdirSync2(runtimeDir, { recursive: true });
407
+ const runtimeDir = dirname(runtimePath);
408
+ if (!existsSync(runtimeDir)) {
409
+ mkdirSync(runtimeDir, { recursive: true });
410
410
  }
411
- writeFileSync2(runtimePath, JSON.stringify(config, null, 2), "utf-8");
411
+ writeFileSync(runtimePath, JSON.stringify(config, null, 2), "utf-8");
412
412
  }
413
413
  function deleteRuntimeConfig() {
414
414
  const runtimePath = getRuntimePath();
415
- if (existsSync4(runtimePath)) {
415
+ if (existsSync(runtimePath)) {
416
416
  unlinkSync(runtimePath);
417
417
  }
418
418
  }
@@ -593,6 +593,7 @@ var init_config_schema2 = __esm({
593
593
  "packages/providers/src/codex/config-schema.ts"() {
594
594
  "use strict";
595
595
  codexConfigSchema = z2.object({
596
+ model: z2.string().min(1).optional(),
596
597
  additionalArgs: z2.array(z2.string()).default([]),
597
598
  envVars: z2.record(z2.string(), z2.string()).default({})
598
599
  });
@@ -639,6 +640,7 @@ function buildCodexSupervisorEvalCommand(config, req) {
639
640
  "-s",
640
641
  "read-only",
641
642
  "--skip-git-repo-check",
643
+ ...req.model ? ["-m", req.model] : [],
642
644
  ...cfg.additionalArgs,
643
645
  req.prompt
644
646
  ],
@@ -786,7 +788,7 @@ var init_src = __esm({
786
788
  });
787
789
 
788
790
  // packages/utils/src/direct-execution.ts
789
- import { posix, resolve as resolve2 } from "node:path";
791
+ import { posix, resolve } from "node:path";
790
792
  function isWindowsDrivePath(path10) {
791
793
  return /^[A-Za-z]:\//.test(path10);
792
794
  }
@@ -820,7 +822,7 @@ function normalizeModuleUrlPath(moduleUrl) {
820
822
  }
821
823
  function normalizeArgvPath(argv1) {
822
824
  const isAbsoluteWindowsPath = /^[A-Za-z]:[\\/]/.test(argv1) || /^\\\\/.test(argv1);
823
- return normalizeComparablePath(isAbsoluteWindowsPath ? argv1 : resolve2(argv1));
825
+ return normalizeComparablePath(isAbsoluteWindowsPath ? argv1 : resolve(argv1));
824
826
  }
825
827
  function isDirectExecution(moduleUrl, argv1 = process.argv[1]) {
826
828
  if (argv1 === void 0) {
@@ -995,7 +997,7 @@ var init_image = __esm({
995
997
  // packages/server/src/fs/file-io.ts
996
998
  import { createHash } from "crypto";
997
999
  import { readFile as fsReadFile, writeFile as fsWriteFile, mkdir, rm, stat } from "fs/promises";
998
- import { dirname as dirname3, isAbsolute, relative, resolve as resolve3 } from "path";
1000
+ import { dirname as dirname2, isAbsolute, relative, resolve as resolve2 } from "path";
999
1001
  async function statSafe(path10) {
1000
1002
  try {
1001
1003
  return await stat(path10);
@@ -1009,7 +1011,7 @@ async function createFile(rootPath, relPath) {
1009
1011
  if (existing) {
1010
1012
  throw { code: "already_exists", message: "File already exists" };
1011
1013
  }
1012
- await mkdir(dirname3(abs), { recursive: true });
1014
+ await mkdir(dirname2(abs), { recursive: true });
1013
1015
  await fsWriteFile(abs, "", "utf-8");
1014
1016
  }
1015
1017
  async function createDirectory(rootPath, relPath) {
@@ -1029,8 +1031,8 @@ async function deleteEntry(rootPath, relPath) {
1029
1031
  await rm(abs, { recursive: true });
1030
1032
  }
1031
1033
  function resolveSafe(root, relPath) {
1032
- const absRoot = resolve3(root);
1033
- const abs = resolve3(absRoot, relPath);
1034
+ const absRoot = resolve2(root);
1035
+ const abs = resolve2(absRoot, relPath);
1034
1036
  const rel = relative(absRoot, abs);
1035
1037
  if (rel === ".." || rel.startsWith(`..${"/"}`) || isAbsolute(rel)) {
1036
1038
  throw { code: "path_escape", message: "Path escapes workspace root" };
@@ -1079,7 +1081,7 @@ async function writeFile(rootPath, relPath, content, baseHash) {
1079
1081
  };
1080
1082
  }
1081
1083
  }
1082
- await mkdir(dirname3(abs), { recursive: true });
1084
+ await mkdir(dirname2(abs), { recursive: true });
1083
1085
  await fsWriteFile(abs, content, "utf-8");
1084
1086
  const newHash = createHash("sha256").update(content).digest("hex");
1085
1087
  return { newHash };
@@ -2108,8 +2110,8 @@ var init_command_check = __esm({
2108
2110
  });
2109
2111
 
2110
2112
  // packages/server/src/provider-runtime/e2e-provider-mock.ts
2111
- import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
2112
- import { dirname as dirname4, join as join3 } from "node:path";
2113
+ import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
2114
+ import { dirname as dirname3, join as join2 } from "node:path";
2113
2115
  function createE2EProviderMockOverrides(env = process.env) {
2114
2116
  const statePath = env.CODER_STUDIO_E2E_PROVIDER_STATE_PATH;
2115
2117
  if (!statePath) {
@@ -2191,10 +2193,10 @@ function getInstallProviderId(file, args) {
2191
2193
  return null;
2192
2194
  }
2193
2195
  function readMockState(statePath) {
2194
- if (!existsSync6(statePath)) {
2196
+ if (!existsSync3(statePath)) {
2195
2197
  return {};
2196
2198
  }
2197
- const raw = readFileSync5(statePath, "utf8");
2199
+ const raw = readFileSync3(statePath, "utf8");
2198
2200
  if (!raw.trim()) {
2199
2201
  return {};
2200
2202
  }
@@ -2209,22 +2211,22 @@ function readMockState(statePath) {
2209
2211
  function writeMockState(statePath, updater) {
2210
2212
  const nextState = readMockState(statePath);
2211
2213
  updater(nextState);
2212
- mkdirSync3(dirname4(statePath), { recursive: true });
2213
- writeFileSync3(statePath, JSON.stringify(nextState, null, 2));
2214
+ mkdirSync2(dirname3(statePath), { recursive: true });
2215
+ writeFileSync2(statePath, JSON.stringify(nextState, null, 2));
2214
2216
  return nextState;
2215
2217
  }
2216
2218
  function ensureProviderCommand(binDir, providerId) {
2217
- mkdirSync3(binDir, { recursive: true });
2218
- const scriptPath = join3(binDir, providerId);
2219
- writeFileSync3(scriptPath, PROVIDER_COMMAND_SCRIPTS[providerId], "utf8");
2219
+ mkdirSync2(binDir, { recursive: true });
2220
+ const scriptPath = join2(binDir, providerId);
2221
+ writeFileSync2(scriptPath, PROVIDER_COMMAND_SCRIPTS[providerId], "utf8");
2220
2222
  chmodSync(scriptPath, 493);
2221
2223
  }
2222
2224
  function appendDebugLog(path10, line) {
2223
2225
  if (!path10) {
2224
2226
  return;
2225
2227
  }
2226
- mkdirSync3(dirname4(path10), { recursive: true });
2227
- writeFileSync3(path10, `${line}
2228
+ mkdirSync2(dirname3(path10), { recursive: true });
2229
+ writeFileSync2(path10, `${line}
2228
2230
  `, { flag: "a" });
2229
2231
  }
2230
2232
  var PROVIDER_INSTALL_PACKAGES, PROVIDER_COMMAND_SCRIPTS;
@@ -2705,12 +2707,46 @@ function resolveSupervisorEvaluationTimeoutSec(value) {
2705
2707
  }
2706
2708
  return value;
2707
2709
  }
2708
- var DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC, MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC, DEFAULT_SUPERVISOR_CONFIG;
2710
+ function resolveSupervisorRetryEnabled(value) {
2711
+ return typeof value === "boolean" ? value : DEFAULT_SUPERVISOR_RETRY_ENABLED;
2712
+ }
2713
+ function resolveSupervisorRetryMaxCount(value) {
2714
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isSafeInteger(value)) {
2715
+ return DEFAULT_SUPERVISOR_RETRY_MAX_COUNT;
2716
+ }
2717
+ if (value < 0 || value > MAX_SUPERVISOR_RETRY_MAX_COUNT) {
2718
+ return DEFAULT_SUPERVISOR_RETRY_MAX_COUNT;
2719
+ }
2720
+ return value;
2721
+ }
2722
+ function resolveSupervisorRetryDelaySec(value) {
2723
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isSafeInteger(value)) {
2724
+ return DEFAULT_SUPERVISOR_RETRY_DELAY_SEC;
2725
+ }
2726
+ if (value < 1 || value > MAX_SUPERVISOR_RETRY_DELAY_SEC) {
2727
+ return DEFAULT_SUPERVISOR_RETRY_DELAY_SEC;
2728
+ }
2729
+ return value;
2730
+ }
2731
+ function resolveSupervisorRetryOnTimeout(value) {
2732
+ return typeof value === "boolean" ? value : DEFAULT_SUPERVISOR_RETRY_ON_TIMEOUT;
2733
+ }
2734
+ function resolveSupervisorRetryOnEvaluatorError(value) {
2735
+ return typeof value === "boolean" ? value : DEFAULT_SUPERVISOR_RETRY_ON_EVALUATOR_ERROR;
2736
+ }
2737
+ var DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC, MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC, DEFAULT_SUPERVISOR_RETRY_ENABLED, DEFAULT_SUPERVISOR_RETRY_MAX_COUNT, MAX_SUPERVISOR_RETRY_MAX_COUNT, DEFAULT_SUPERVISOR_RETRY_DELAY_SEC, MAX_SUPERVISOR_RETRY_DELAY_SEC, DEFAULT_SUPERVISOR_RETRY_ON_TIMEOUT, DEFAULT_SUPERVISOR_RETRY_ON_EVALUATOR_ERROR, DEFAULT_SUPERVISOR_CONFIG;
2709
2738
  var init_supervisor = __esm({
2710
2739
  "packages/core/src/domain/supervisor.ts"() {
2711
2740
  "use strict";
2712
2741
  DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC = 600;
2713
2742
  MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC = 86400;
2743
+ DEFAULT_SUPERVISOR_RETRY_ENABLED = false;
2744
+ DEFAULT_SUPERVISOR_RETRY_MAX_COUNT = 0;
2745
+ MAX_SUPERVISOR_RETRY_MAX_COUNT = 20;
2746
+ DEFAULT_SUPERVISOR_RETRY_DELAY_SEC = 10;
2747
+ MAX_SUPERVISOR_RETRY_DELAY_SEC = 3600;
2748
+ DEFAULT_SUPERVISOR_RETRY_ON_TIMEOUT = true;
2749
+ DEFAULT_SUPERVISOR_RETRY_ON_EVALUATOR_ERROR = false;
2714
2750
  DEFAULT_SUPERVISOR_CONFIG = {
2715
2751
  maxCyclesPerSession: 100,
2716
2752
  terminalLinesForEvaluation: 500,
@@ -3738,10 +3774,10 @@ var init_database = __esm({
3738
3774
  }
3739
3775
  });
3740
3776
 
3741
- // packages/server/src/storage/db.ts
3777
+ // packages/server/src/storage/schema-version.ts
3742
3778
  import { DatabaseSync } from "node:sqlite";
3743
- import { readFileSync as readFileSync6 } from "fs";
3744
- import { join as join4 } from "path";
3779
+ import { readFileSync as readFileSync4 } from "fs";
3780
+ import { join as join3 } from "path";
3745
3781
  function normalizeSql(sql) {
3746
3782
  return (sql ?? "").replace(/\s+/g, " ").trim();
3747
3783
  }
@@ -3762,15 +3798,229 @@ function listSchemaEntries(db) {
3762
3798
  sql: normalizeSql(row.sql)
3763
3799
  }));
3764
3800
  }
3765
- function buildExpectedSchemaEntries() {
3801
+ function schemaEntrySignature(entry) {
3802
+ return `${entry.type}:${entry.name}:${entry.tableName}:${entry.sql}`;
3803
+ }
3804
+ function buildSchemaEntries(schemaSql) {
3766
3805
  const db = new DatabaseSync(":memory:");
3767
3806
  try {
3768
- db.exec(SCHEMA_SQL);
3807
+ db.exec(schemaSql);
3769
3808
  return listSchemaEntries(db);
3770
3809
  } finally {
3771
3810
  db.close();
3772
3811
  }
3773
3812
  }
3813
+ function hasExactFingerprint(actualEntries, expectedEntries) {
3814
+ if (actualEntries.length !== expectedEntries.length) {
3815
+ return false;
3816
+ }
3817
+ return actualEntries.every(
3818
+ (entry, index) => schemaEntrySignature(entry) === schemaEntrySignature(expectedEntries[index])
3819
+ );
3820
+ }
3821
+ function describeSchemaMismatch(expected, actual) {
3822
+ const expectedByName = new Map(expected.map((entry) => [`${entry.type}:${entry.name}`, entry]));
3823
+ const actualByName = new Map(actual.map((entry) => [`${entry.type}:${entry.name}`, entry]));
3824
+ const keys = /* @__PURE__ */ new Set([...expectedByName.keys(), ...actualByName.keys()]);
3825
+ for (const key of keys) {
3826
+ const expectedEntry = expectedByName.get(key);
3827
+ const actualEntry = actualByName.get(key);
3828
+ if (!expectedEntry) {
3829
+ return `unexpected ${actualEntry?.type ?? "schema object"} ${actualEntry?.name ?? key}`;
3830
+ }
3831
+ if (!actualEntry) {
3832
+ return `missing ${expectedEntry.type} ${expectedEntry.name}`;
3833
+ }
3834
+ if (schemaEntrySignature(expectedEntry) !== schemaEntrySignature(actualEntry)) {
3835
+ return `definition mismatch for ${expectedEntry.type} ${expectedEntry.name}`;
3836
+ }
3837
+ }
3838
+ return "unknown schema drift";
3839
+ }
3840
+ function detectSchema(db) {
3841
+ const actualEntries = listSchemaEntries(db);
3842
+ const userVersionRow = db.prepare("PRAGMA user_version").get();
3843
+ const userVersion = userVersionRow?.user_version ?? 0;
3844
+ if (actualEntries.length === 0) {
3845
+ return {
3846
+ state: "empty",
3847
+ userVersion,
3848
+ mismatch: null
3849
+ };
3850
+ }
3851
+ if (hasExactFingerprint(actualEntries, CURRENT_SCHEMA_ENTRIES)) {
3852
+ return {
3853
+ state: "current",
3854
+ userVersion,
3855
+ mismatch: null
3856
+ };
3857
+ }
3858
+ if (hasExactFingerprint(actualEntries, V1_SCHEMA_ENTRIES)) {
3859
+ return {
3860
+ state: "v1",
3861
+ userVersion,
3862
+ mismatch: null
3863
+ };
3864
+ }
3865
+ return {
3866
+ state: "incompatible",
3867
+ userVersion,
3868
+ mismatch: describeSchemaMismatch(CURRENT_SCHEMA_ENTRIES, actualEntries)
3869
+ };
3870
+ }
3871
+ function stampCurrentSchemaVersion(db) {
3872
+ db.exec(`PRAGMA user_version = ${CURRENT_SCHEMA_VERSION}`);
3873
+ }
3874
+ var CURRENT_SCHEMA_VERSION, CURRENT_SCHEMA_PATH, CURRENT_SCHEMA_SQL, V1_SCHEMA_SQL, CURRENT_SCHEMA_ENTRIES, V1_SCHEMA_ENTRIES, IncompatibleSchemaError;
3875
+ var init_schema_version = __esm({
3876
+ "packages/server/src/storage/schema-version.ts"() {
3877
+ "use strict";
3878
+ CURRENT_SCHEMA_VERSION = 2;
3879
+ CURRENT_SCHEMA_PATH = join3(import.meta.dirname, "migrations", "001_init.sql");
3880
+ CURRENT_SCHEMA_SQL = readFileSync4(CURRENT_SCHEMA_PATH, "utf-8");
3881
+ V1_SCHEMA_SQL = `
3882
+ CREATE TABLE workspaces (
3883
+ id TEXT PRIMARY KEY,
3884
+ path TEXT NOT NULL UNIQUE,
3885
+ target_runtime TEXT NOT NULL,
3886
+ wsl_distro TEXT,
3887
+ opened_at INTEGER NOT NULL,
3888
+ last_active_at INTEGER NOT NULL,
3889
+ ui_state TEXT
3890
+ );
3891
+
3892
+ CREATE TABLE terminals (
3893
+ id TEXT PRIMARY KEY,
3894
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
3895
+ kind TEXT NOT NULL,
3896
+ cwd TEXT NOT NULL,
3897
+ argv TEXT NOT NULL,
3898
+ env TEXT,
3899
+ title TEXT,
3900
+ cols INTEGER NOT NULL,
3901
+ rows INTEGER NOT NULL,
3902
+ created_at INTEGER NOT NULL,
3903
+ ended_at INTEGER,
3904
+ exit_code INTEGER
3905
+ );
3906
+
3907
+ CREATE INDEX idx_terminals_workspace ON terminals(workspace_id);
3908
+ CREATE INDEX idx_terminals_kind ON terminals(workspace_id, kind);
3909
+
3910
+ CREATE TABLE sessions (
3911
+ id TEXT PRIMARY KEY,
3912
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
3913
+ terminal_id TEXT NOT NULL REFERENCES terminals(id) ON DELETE CASCADE,
3914
+ provider_id TEXT NOT NULL,
3915
+ capability TEXT NOT NULL,
3916
+ state TEXT NOT NULL,
3917
+ started_at INTEGER NOT NULL,
3918
+ ended_at INTEGER,
3919
+ last_active_at INTEGER NOT NULL,
3920
+ completion_percent INTEGER,
3921
+ error_reason TEXT,
3922
+ archived BOOLEAN DEFAULT 0,
3923
+ title TEXT
3924
+ );
3925
+
3926
+ CREATE INDEX idx_sessions_workspace ON sessions(workspace_id);
3927
+ CREATE UNIQUE INDEX idx_sessions_terminal ON sessions(terminal_id);
3928
+ CREATE UNIQUE INDEX idx_sessions_id_workspace ON sessions(id, workspace_id);
3929
+
3930
+ CREATE TABLE provider_configs (
3931
+ provider_id TEXT PRIMARY KEY,
3932
+ config TEXT NOT NULL
3933
+ );
3934
+
3935
+ CREATE TABLE user_settings (
3936
+ key TEXT PRIMARY KEY,
3937
+ value TEXT NOT NULL
3938
+ );
3939
+
3940
+ CREATE TABLE auth_sessions (
3941
+ token TEXT PRIMARY KEY,
3942
+ created_at INTEGER NOT NULL,
3943
+ last_seen_at INTEGER NOT NULL
3944
+ );
3945
+
3946
+ CREATE INDEX idx_auth_sessions_last_seen_at ON auth_sessions(last_seen_at);
3947
+
3948
+ CREATE TABLE supervisors (
3949
+ id TEXT PRIMARY KEY,
3950
+ session_id TEXT NOT NULL UNIQUE,
3951
+ workspace_id TEXT NOT NULL,
3952
+ state TEXT NOT NULL,
3953
+ objective TEXT NOT NULL,
3954
+ evaluator_provider_id TEXT NOT NULL,
3955
+ last_cycle_at INTEGER,
3956
+ last_evaluated_turn_id TEXT,
3957
+ error_reason TEXT,
3958
+ created_at INTEGER NOT NULL,
3959
+ updated_at INTEGER NOT NULL,
3960
+ FOREIGN KEY (session_id, workspace_id) REFERENCES sessions(id, workspace_id) ON DELETE CASCADE,
3961
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
3962
+ );
3963
+
3964
+ CREATE INDEX idx_supervisors_workspace ON supervisors(workspace_id);
3965
+ CREATE INDEX idx_supervisors_session ON supervisors(session_id);
3966
+ CREATE UNIQUE INDEX idx_supervisors_id_session ON supervisors(id, session_id);
3967
+
3968
+ CREATE TABLE supervisor_cycles (
3969
+ id TEXT PRIMARY KEY,
3970
+ supervisor_id TEXT NOT NULL,
3971
+ session_id TEXT NOT NULL,
3972
+ status TEXT NOT NULL,
3973
+ trigger TEXT NOT NULL,
3974
+ evidence_source TEXT NOT NULL,
3975
+ objective TEXT NOT NULL,
3976
+ evaluator_provider_id TEXT NOT NULL,
3977
+ turn_id TEXT,
3978
+ progress INTEGER,
3979
+ result TEXT,
3980
+ injected_guidance TEXT,
3981
+ error_reason TEXT,
3982
+ created_at INTEGER NOT NULL,
3983
+ completed_at INTEGER,
3984
+ FOREIGN KEY (supervisor_id, session_id) REFERENCES supervisors(id, session_id) ON DELETE CASCADE,
3985
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
3986
+ );
3987
+
3988
+ CREATE INDEX idx_supervisor_cycles_supervisor ON supervisor_cycles(supervisor_id, created_at DESC);
3989
+ CREATE INDEX idx_supervisor_cycles_session ON supervisor_cycles(session_id, created_at DESC);
3990
+
3991
+ CREATE TABLE auth_login_blocks (
3992
+ ip TEXT PRIMARY KEY,
3993
+ failed_count INTEGER NOT NULL,
3994
+ first_failed_at INTEGER NOT NULL,
3995
+ last_failed_at INTEGER NOT NULL,
3996
+ blocked_until INTEGER
3997
+ );
3998
+
3999
+ CREATE INDEX idx_auth_login_blocks_blocked_until ON auth_login_blocks(blocked_until);
4000
+
4001
+ CREATE TABLE auth_login_failures (
4002
+ ip TEXT NOT NULL,
4003
+ failed_at INTEGER NOT NULL
4004
+ );
4005
+
4006
+ CREATE INDEX idx_auth_login_failures_ip_failed_at ON auth_login_failures(ip, failed_at);
4007
+ `;
4008
+ CURRENT_SCHEMA_ENTRIES = buildSchemaEntries(CURRENT_SCHEMA_SQL);
4009
+ V1_SCHEMA_ENTRIES = buildSchemaEntries(V1_SCHEMA_SQL);
4010
+ IncompatibleSchemaError = class extends Error {
4011
+ code = "db_incompatible_schema";
4012
+ constructor(dbPath, mismatch) {
4013
+ super(
4014
+ `db_incompatible_schema: Database schema mismatch detected at ${dbPath}: ${mismatch}. This build requires the current baseline schema. Delete the local database file and restart.`
4015
+ );
4016
+ this.name = "IncompatibleSchemaError";
4017
+ }
4018
+ };
4019
+ }
4020
+ });
4021
+
4022
+ // packages/server/src/storage/db.ts
4023
+ import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
3774
4024
  function hasTable(db, tableName) {
3775
4025
  const row = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(tableName);
3776
4026
  return row?.name === tableName;
@@ -3797,68 +4047,75 @@ function detectLegacySchema(db) {
3797
4047
  }
3798
4048
  return reasons;
3799
4049
  }
3800
- function schemaEntrySignature(entry) {
3801
- return `${entry.type}:${entry.name}:${entry.tableName}:${entry.sql}`;
3802
- }
3803
- function isSchemaEmpty(db) {
3804
- return listSchemaEntries(db).length === 0;
3805
- }
3806
- function assertNoLegacySchema(db, dbPath) {
4050
+ function throwIfLegacySchema(db, dbPath) {
3807
4051
  const reasons = detectLegacySchema(db);
3808
4052
  if (reasons.length === 0) {
3809
4053
  return;
3810
4054
  }
3811
- throw new Error(
3812
- `Legacy database schema detected at ${dbPath}: ${reasons.join(", ")}. This build no longer supports automatic database upgrades. Delete the local database file and restart.`
3813
- );
3814
- }
3815
- function describeSchemaMismatch(expected, actual) {
3816
- const expectedByName = new Map(expected.map((entry) => [`${entry.type}:${entry.name}`, entry]));
3817
- const actualByName = new Map(actual.map((entry) => [`${entry.type}:${entry.name}`, entry]));
3818
- const keys = /* @__PURE__ */ new Set([...expectedByName.keys(), ...actualByName.keys()]);
3819
- for (const key of keys) {
3820
- const expectedEntry = expectedByName.get(key);
3821
- const actualEntry = actualByName.get(key);
3822
- if (!expectedEntry) {
3823
- return `unexpected ${actualEntry?.type ?? "schema object"} ${actualEntry?.name ?? key}`;
3824
- }
3825
- if (!actualEntry) {
3826
- return `missing ${expectedEntry.type} ${expectedEntry.name}`;
3827
- }
3828
- if (schemaEntrySignature(expectedEntry) !== schemaEntrySignature(actualEntry)) {
3829
- return `definition mismatch for ${expectedEntry.type} ${expectedEntry.name}`;
3830
- }
3831
- }
3832
- return "unknown schema drift";
3833
- }
3834
- function assertSchemaMatchesBaseline(db, dbPath) {
3835
- const actualEntries = listSchemaEntries(db);
3836
- const expectedSignatures = EXPECTED_SCHEMA_ENTRIES.map(schemaEntrySignature);
3837
- const actualSignatures = actualEntries.map(schemaEntrySignature);
3838
- if (actualSignatures.length === expectedSignatures.length && actualSignatures.every((signature, index) => signature === expectedSignatures[index])) {
3839
- return;
3840
- }
3841
- const mismatch = describeSchemaMismatch(EXPECTED_SCHEMA_ENTRIES, actualEntries);
3842
- throw new Error(
3843
- `Database schema mismatch detected at ${dbPath}: ${mismatch}. This build requires the current baseline schema. Delete the local database file and restart.`
3844
- );
4055
+ throw new IncompatibleSchemaError(dbPath, `legacy schema detected (${reasons.join(", ")})`);
3845
4056
  }
3846
4057
  function initializeSchema(db) {
3847
4058
  withTransaction(db, () => {
3848
- db.exec(SCHEMA_SQL);
4059
+ db.exec(CURRENT_SCHEMA_SQL);
3849
4060
  });
3850
4061
  }
3851
- function initializeOrValidateSchema(db, dbPath) {
3852
- assertNoLegacySchema(db, dbPath);
3853
- if (isSchemaEmpty(db)) {
3854
- initializeSchema(db);
3855
- assertSchemaMatchesBaseline(db, dbPath);
3856
- return;
4062
+ function upgradeSchemaV1ToV2(db) {
4063
+ withTransaction(db, () => {
4064
+ db.exec("ALTER TABLE supervisors ADD COLUMN evaluator_model TEXT");
4065
+ db.exec("ALTER TABLE supervisors ADD COLUMN max_supervision_count INTEGER NOT NULL DEFAULT 0");
4066
+ db.exec(
4067
+ "ALTER TABLE supervisors ADD COLUMN completed_supervision_count INTEGER NOT NULL DEFAULT 0"
4068
+ );
4069
+ db.exec("ALTER TABLE supervisors ADD COLUMN scheduled_at INTEGER");
4070
+ db.exec("ALTER TABLE supervisors ADD COLUMN stop_reason TEXT");
4071
+ db.exec(`
4072
+ CREATE TABLE supervisor_cycle_attempts (
4073
+ id TEXT PRIMARY KEY,
4074
+ cycle_id TEXT NOT NULL REFERENCES supervisor_cycles(id) ON DELETE CASCADE,
4075
+ attempt_index INTEGER NOT NULL,
4076
+ status TEXT NOT NULL,
4077
+ started_at INTEGER NOT NULL,
4078
+ completed_at INTEGER,
4079
+ error_reason TEXT,
4080
+ provider_model TEXT
4081
+ )
4082
+ `);
4083
+ db.exec(
4084
+ "CREATE INDEX idx_supervisor_cycle_attempts_cycle ON supervisor_cycle_attempts(cycle_id, attempt_index)"
4085
+ );
4086
+ stampCurrentSchemaVersion(db);
4087
+ });
4088
+ }
4089
+ function assertCurrentSchema(db, dbPath) {
4090
+ const detection = detectSchema(db);
4091
+ if (detection.state !== "current") {
4092
+ throw new IncompatibleSchemaError(dbPath, detection.mismatch ?? "unknown schema drift");
4093
+ }
4094
+ }
4095
+ function initializeOrUpgradeSchema(db, dbPath) {
4096
+ throwIfLegacySchema(db, dbPath);
4097
+ const detection = detectSchema(db);
4098
+ switch (detection.state) {
4099
+ case "empty":
4100
+ initializeSchema(db);
4101
+ assertCurrentSchema(db, dbPath);
4102
+ return;
4103
+ case "current":
4104
+ if (detection.userVersion !== CURRENT_SCHEMA_VERSION) {
4105
+ stampCurrentSchemaVersion(db);
4106
+ }
4107
+ assertCurrentSchema(db, dbPath);
4108
+ return;
4109
+ case "v1":
4110
+ upgradeSchemaV1ToV2(db);
4111
+ assertCurrentSchema(db, dbPath);
4112
+ return;
4113
+ case "incompatible":
4114
+ throw new IncompatibleSchemaError(dbPath, detection.mismatch ?? "unknown schema drift");
3857
4115
  }
3858
- assertSchemaMatchesBaseline(db, dbPath);
3859
4116
  }
3860
4117
  function openDatabase(dbPath) {
3861
- const db = new DatabaseSync(dbPath);
4118
+ const db = new DatabaseSync2(dbPath);
3862
4119
  try {
3863
4120
  db.exec("PRAGMA journal_mode = WAL");
3864
4121
  db.exec("PRAGMA foreign_keys = ON");
@@ -3866,7 +4123,7 @@ function openDatabase(dbPath) {
3866
4123
  if (integrityResult[0]?.integrity_check !== "ok") {
3867
4124
  throw new Error(`Database integrity check failed: ${JSON.stringify(integrityResult)}`);
3868
4125
  }
3869
- initializeOrValidateSchema(db, dbPath);
4126
+ initializeOrUpgradeSchema(db, dbPath);
3870
4127
  return db;
3871
4128
  } catch (error) {
3872
4129
  try {
@@ -3883,16 +4140,14 @@ function closeDatabase(db) {
3883
4140
  db.close();
3884
4141
  }
3885
4142
  }
3886
- var SCHEMA_PATH, SCHEMA_SQL, LEGACY_TABLES, LEGACY_SESSION_COLUMNS, EXPECTED_SCHEMA_ENTRIES;
4143
+ var LEGACY_TABLES, LEGACY_SESSION_COLUMNS;
3887
4144
  var init_db = __esm({
3888
4145
  "packages/server/src/storage/db.ts"() {
3889
4146
  "use strict";
3890
4147
  init_database();
3891
- SCHEMA_PATH = join4(import.meta.dirname, "migrations", "001_init.sql");
3892
- SCHEMA_SQL = readFileSync6(SCHEMA_PATH, "utf-8");
4148
+ init_schema_version();
3893
4149
  LEGACY_TABLES = ["hook_registrations", "_migrations"];
3894
4150
  LEGACY_SESSION_COLUMNS = ["resume_id", "transcript_path"];
3895
- EXPECTED_SCHEMA_ENTRIES = buildExpectedSchemaEntries();
3896
4151
  }
3897
4152
  });
3898
4153
 
@@ -4142,6 +4397,93 @@ var init_settings_repo = __esm({
4142
4397
  }
4143
4398
  });
4144
4399
 
4400
+ // packages/server/src/storage/repositories/supervisor-cycle-attempt-repo.ts
4401
+ var SupervisorCycleAttemptRepo;
4402
+ var init_supervisor_cycle_attempt_repo = __esm({
4403
+ "packages/server/src/storage/repositories/supervisor-cycle-attempt-repo.ts"() {
4404
+ "use strict";
4405
+ SupervisorCycleAttemptRepo = class {
4406
+ constructor(db) {
4407
+ this.db = db;
4408
+ }
4409
+ db;
4410
+ create(input) {
4411
+ this.db.prepare(
4412
+ `INSERT INTO supervisor_cycle_attempts (id, cycle_id, attempt_index, status, started_at, completed_at, error_reason, provider_model)
4413
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
4414
+ ).run(
4415
+ input.id,
4416
+ input.cycleId,
4417
+ input.attemptIndex,
4418
+ input.status,
4419
+ input.startedAt,
4420
+ input.completedAt ?? null,
4421
+ input.errorReason ?? null,
4422
+ input.providerModel ?? null
4423
+ );
4424
+ return this.findById(input.id);
4425
+ }
4426
+ findById(id) {
4427
+ const row = this.db.prepare("SELECT * FROM supervisor_cycle_attempts WHERE id = ?").get(id);
4428
+ return row ? this.rowToAttempt(row) : void 0;
4429
+ }
4430
+ listForCycle(cycleId) {
4431
+ const rows = this.db.prepare(
4432
+ "SELECT * FROM supervisor_cycle_attempts WHERE cycle_id = ? ORDER BY attempt_index ASC"
4433
+ ).all(cycleId);
4434
+ return rows.map((row) => this.rowToAttempt(row));
4435
+ }
4436
+ update(id, patch) {
4437
+ const assignments = [];
4438
+ const params = { id };
4439
+ if (patch.status !== void 0) {
4440
+ assignments.push("status = @status");
4441
+ params.status = patch.status;
4442
+ }
4443
+ if (patch.completedAt !== void 0) {
4444
+ assignments.push("completed_at = @completedAt");
4445
+ params.completedAt = patch.completedAt;
4446
+ }
4447
+ if (patch.errorReason !== void 0) {
4448
+ assignments.push("error_reason = @errorReason");
4449
+ params.errorReason = patch.errorReason;
4450
+ }
4451
+ if (patch.providerModel !== void 0) {
4452
+ assignments.push("provider_model = @providerModel");
4453
+ params.providerModel = patch.providerModel;
4454
+ }
4455
+ if (assignments.length === 0) {
4456
+ const existing = this.findById(id);
4457
+ if (!existing) {
4458
+ throw new Error(`Supervisor cycle attempt not found: ${id}`);
4459
+ }
4460
+ return existing;
4461
+ }
4462
+ const result = this.db.prepare(`UPDATE supervisor_cycle_attempts SET ${assignments.join(", ")} WHERE id = @id`).run(params);
4463
+ if (result.changes === 0) {
4464
+ throw new Error(`Supervisor cycle attempt not found: ${id}`);
4465
+ }
4466
+ return this.findById(id);
4467
+ }
4468
+ deleteForCycle(cycleId) {
4469
+ this.db.prepare("DELETE FROM supervisor_cycle_attempts WHERE cycle_id = ?").run(cycleId);
4470
+ }
4471
+ rowToAttempt(row) {
4472
+ return {
4473
+ id: row.id,
4474
+ cycleId: row.cycle_id,
4475
+ attemptIndex: row.attempt_index,
4476
+ status: row.status,
4477
+ startedAt: row.started_at,
4478
+ completedAt: row.completed_at ?? void 0,
4479
+ errorReason: row.error_reason ?? void 0,
4480
+ providerModel: row.provider_model ?? void 0
4481
+ };
4482
+ }
4483
+ };
4484
+ }
4485
+ });
4486
+
4145
4487
  // packages/server/src/storage/repositories/supervisor-cycle-repo.ts
4146
4488
  var SupervisorCycleRepo;
4147
4489
  var init_supervisor_cycle_repo = __esm({
@@ -4271,8 +4613,8 @@ var init_supervisor_repo = __esm({
4271
4613
  db;
4272
4614
  create(input) {
4273
4615
  this.db.prepare(
4274
- `INSERT INTO supervisors (id, session_id, workspace_id, state, objective, evaluator_provider_id, last_cycle_at, last_evaluated_turn_id, error_reason, created_at, updated_at)
4275
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
4616
+ `INSERT INTO supervisors (id, session_id, workspace_id, state, objective, evaluator_provider_id, evaluator_model, max_supervision_count, completed_supervision_count, scheduled_at, stop_reason, last_cycle_at, last_evaluated_turn_id, error_reason, created_at, updated_at)
4617
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
4276
4618
  ).run(
4277
4619
  input.id,
4278
4620
  input.sessionId,
@@ -4280,6 +4622,11 @@ var init_supervisor_repo = __esm({
4280
4622
  input.state,
4281
4623
  input.objective,
4282
4624
  input.evaluatorProviderId,
4625
+ input.evaluatorModel ?? null,
4626
+ input.maxSupervisionCount ?? 0,
4627
+ input.completedSupervisionCount ?? 0,
4628
+ input.scheduledAt ?? null,
4629
+ input.stopReason ?? null,
4283
4630
  input.lastCycleAt ?? null,
4284
4631
  input.lastEvaluatedTurnId ?? null,
4285
4632
  input.errorReason ?? null,
@@ -4318,6 +4665,26 @@ var init_supervisor_repo = __esm({
4318
4665
  assignments.push("evaluator_provider_id = @evaluatorProviderId");
4319
4666
  params.evaluatorProviderId = patch.evaluatorProviderId;
4320
4667
  }
4668
+ if (patch.evaluatorModel !== void 0) {
4669
+ assignments.push("evaluator_model = @evaluatorModel");
4670
+ params.evaluatorModel = patch.evaluatorModel;
4671
+ }
4672
+ if (patch.maxSupervisionCount !== void 0) {
4673
+ assignments.push("max_supervision_count = @maxSupervisionCount");
4674
+ params.maxSupervisionCount = patch.maxSupervisionCount;
4675
+ }
4676
+ if (patch.completedSupervisionCount !== void 0) {
4677
+ assignments.push("completed_supervision_count = @completedSupervisionCount");
4678
+ params.completedSupervisionCount = patch.completedSupervisionCount;
4679
+ }
4680
+ if (patch.scheduledAt !== void 0) {
4681
+ assignments.push("scheduled_at = @scheduledAt");
4682
+ params.scheduledAt = patch.scheduledAt;
4683
+ }
4684
+ if (patch.stopReason !== void 0) {
4685
+ assignments.push("stop_reason = @stopReason");
4686
+ params.stopReason = patch.stopReason;
4687
+ }
4321
4688
  if (patch.lastCycleAt !== void 0) {
4322
4689
  assignments.push("last_cycle_at = @lastCycleAt");
4323
4690
  params.lastCycleAt = patch.lastCycleAt;
@@ -4347,6 +4714,11 @@ var init_supervisor_repo = __esm({
4347
4714
  state: row.state,
4348
4715
  objective: row.objective,
4349
4716
  evaluatorProviderId: row.evaluator_provider_id,
4717
+ evaluatorModel: row.evaluator_model ?? void 0,
4718
+ maxSupervisionCount: row.max_supervision_count,
4719
+ completedSupervisionCount: row.completed_supervision_count,
4720
+ scheduledAt: row.scheduled_at ?? void 0,
4721
+ stopReason: row.stop_reason ?? void 0,
4350
4722
  cycles: [],
4351
4723
  lastCycleAt: row.last_cycle_at ?? void 0,
4352
4724
  lastEvaluatedTurnId: row.last_evaluated_turn_id ?? void 0,
@@ -5364,7 +5736,7 @@ var init_context_builder = __esm({
5364
5736
  });
5365
5737
 
5366
5738
  // packages/server/src/terminal/pty-host.ts
5367
- import { chmodSync as chmodSync2, existsSync as existsSync7, statSync } from "node:fs";
5739
+ import { chmodSync as chmodSync2, existsSync as existsSync4, statSync } from "node:fs";
5368
5740
  import { createRequire } from "node:module";
5369
5741
  import path6 from "node:path";
5370
5742
  function ensureNodePtySpawnHelperExecutable(deps = {}) {
@@ -5374,7 +5746,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
5374
5746
  }
5375
5747
  const arch = deps.arch ?? process.arch;
5376
5748
  const resolve4 = deps.resolve ?? ((id) => require2.resolve(id));
5377
- const fileExists = deps.existsSync ?? existsSync7;
5749
+ const fileExists = deps.existsSync ?? existsSync4;
5378
5750
  const stat7 = deps.statSync ?? statSync;
5379
5751
  const chmod = deps.chmodSync ?? chmodSync2;
5380
5752
  let packageJsonPath;
@@ -5534,12 +5906,63 @@ function getSupervisorEvaluationTimeoutMs(settingsRepo) {
5534
5906
  const timeoutSec = resolveSupervisorEvaluationTimeoutSec(storedValue);
5535
5907
  return timeoutSec * 1e3;
5536
5908
  }
5537
- var SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY;
5909
+ function getSettingOrDefault(settingsRepo, key, fallback) {
5910
+ try {
5911
+ return settingsRepo?.get(key) ?? fallback;
5912
+ } catch {
5913
+ return fallback;
5914
+ }
5915
+ }
5916
+ function getSupervisorRetrySettings(settingsRepo) {
5917
+ return {
5918
+ retryEnabled: resolveSupervisorRetryEnabled(
5919
+ getSettingOrDefault(
5920
+ settingsRepo,
5921
+ SUPERVISOR_RETRY_ENABLED_SETTING_KEY,
5922
+ DEFAULT_SUPERVISOR_RETRY_ENABLED
5923
+ )
5924
+ ),
5925
+ retryMaxCount: resolveSupervisorRetryMaxCount(
5926
+ getSettingOrDefault(
5927
+ settingsRepo,
5928
+ SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY,
5929
+ DEFAULT_SUPERVISOR_RETRY_MAX_COUNT
5930
+ )
5931
+ ),
5932
+ retryDelaySec: resolveSupervisorRetryDelaySec(
5933
+ getSettingOrDefault(
5934
+ settingsRepo,
5935
+ SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY,
5936
+ DEFAULT_SUPERVISOR_RETRY_DELAY_SEC
5937
+ )
5938
+ ),
5939
+ retryOnTimeout: resolveSupervisorRetryOnTimeout(
5940
+ getSettingOrDefault(
5941
+ settingsRepo,
5942
+ SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY,
5943
+ DEFAULT_SUPERVISOR_RETRY_ON_TIMEOUT
5944
+ )
5945
+ ),
5946
+ retryOnEvaluatorError: resolveSupervisorRetryOnEvaluatorError(
5947
+ getSettingOrDefault(
5948
+ settingsRepo,
5949
+ SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY,
5950
+ DEFAULT_SUPERVISOR_RETRY_ON_EVALUATOR_ERROR
5951
+ )
5952
+ )
5953
+ };
5954
+ }
5955
+ var SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY, SUPERVISOR_RETRY_ENABLED_SETTING_KEY, SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY, SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY, SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY, SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY;
5538
5956
  var init_settings = __esm({
5539
5957
  "packages/server/src/supervisor/settings.ts"() {
5540
5958
  "use strict";
5541
5959
  init_src3();
5542
5960
  SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY = "supervisor.evaluationTimeoutSec";
5961
+ SUPERVISOR_RETRY_ENABLED_SETTING_KEY = "supervisor.retryEnabled";
5962
+ SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY = "supervisor.retryMaxCount";
5963
+ SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY = "supervisor.retryDelaySec";
5964
+ SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY = "supervisor.retryOnTimeout";
5965
+ SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY = "supervisor.retryOnEvaluatorError";
5543
5966
  }
5544
5967
  });
5545
5968
 
@@ -5761,6 +6184,12 @@ function extractSupervisorMessage(output, providerId) {
5761
6184
  }
5762
6185
  const lines = trimmed.split(/\r?\n/).filter(Boolean);
5763
6186
  if (providerId === "codex") {
6187
+ if (trimmed === "[objective complete]") {
6188
+ return trimmed;
6189
+ }
6190
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
6191
+ return stripCodeFence(trimmed);
6192
+ }
5764
6193
  const scan = scanCodexStream(lines);
5765
6194
  if (scan.turnFailure) {
5766
6195
  throw new Error(`Supervisor (codex) failed: ${scan.turnFailure}`);
@@ -5862,7 +6291,7 @@ var init_evaluator = __esm({
5862
6291
  prompt,
5863
6292
  sessionId: supervisor.sessionId,
5864
6293
  workspacePath: context.workspacePath,
5865
- model: typeof config.model === "string" ? config.model : void 0
6294
+ model: typeof supervisor.evaluatorModel === "string" && supervisor.evaluatorModel.trim() ? supervisor.evaluatorModel.trim() : typeof config.model === "string" ? config.model : void 0
5866
6295
  });
5867
6296
  if (!command) {
5868
6297
  throw {
@@ -5891,7 +6320,11 @@ var init_evaluator = __esm({
5891
6320
  );
5892
6321
  throw error;
5893
6322
  }
5894
- return { message: message.slice(0, this.config.guidanceMaxChars) };
6323
+ const normalizedMessage = message.slice(0, this.config.guidanceMaxChars);
6324
+ return {
6325
+ message: normalizedMessage,
6326
+ objectiveComplete: normalizedMessage.trim() === "[objective complete]"
6327
+ };
5895
6328
  }
5896
6329
  };
5897
6330
  }
@@ -5927,7 +6360,13 @@ var init_injector = __esm({
5927
6360
  }
5928
6361
  deps;
5929
6362
  config;
5930
- async inject(supervisor, input, recentCycles) {
6363
+ async inject(supervisor, input, recentCycles, options = {}) {
6364
+ if (options.signal?.aborted) {
6365
+ throw {
6366
+ code: "supervisor_eval_aborted",
6367
+ message: "Supervisor evaluator aborted"
6368
+ };
6369
+ }
5931
6370
  const session = this.deps.sessionMgr.get(supervisor.sessionId);
5932
6371
  if (!session) {
5933
6372
  throw {
@@ -5948,6 +6387,12 @@ var init_injector = __esm({
5948
6387
  if (duplicate) {
5949
6388
  return { injected: false, text };
5950
6389
  }
6390
+ if (options.signal?.aborted) {
6391
+ throw {
6392
+ code: "supervisor_eval_aborted",
6393
+ message: "Supervisor evaluator aborted"
6394
+ };
6395
+ }
5951
6396
  const BRACKETED_PASTE_START = "\x1B[200~";
5952
6397
  const BRACKETED_PASTE_END = "\x1B[201~";
5953
6398
  const SUBMIT = "\r";
@@ -5970,6 +6415,9 @@ var init_scheduler = __esm({
5970
6415
  }
5971
6416
  deps;
5972
6417
  unsubscribe = null;
6418
+ scheduledTimer = null;
6419
+ scheduledRetryDelayMs = 1e3;
6420
+ retryAtBySupervisorId = /* @__PURE__ */ new Map();
5973
6421
  start() {
5974
6422
  this.unsubscribe?.();
5975
6423
  this.unsubscribe = this.deps.eventBus.on(
@@ -5982,9 +6430,64 @@ var init_scheduler = __esm({
5982
6430
  }
5983
6431
  );
5984
6432
  }
6433
+ refresh() {
6434
+ this.clearScheduledTimer();
6435
+ const scheduled = this.deps.listScheduledSupervisors?.() ?? [];
6436
+ this.pruneRetryState(scheduled);
6437
+ if (scheduled.length === 0) {
6438
+ return;
6439
+ }
6440
+ const now = Date.now();
6441
+ const nextAt = scheduled.reduce((earliest, item) => {
6442
+ const candidate = this.getNextAttemptAt(item, now);
6443
+ return candidate < earliest ? candidate : earliest;
6444
+ }, Number.POSITIVE_INFINITY);
6445
+ if (!Number.isFinite(nextAt)) {
6446
+ return;
6447
+ }
6448
+ const delayMs = Math.max(nextAt - now, 0);
6449
+ this.scheduledTimer = setTimeout(() => {
6450
+ this.scheduledTimer = null;
6451
+ const current = this.deps.listScheduledSupervisors?.() ?? [];
6452
+ this.pruneRetryState(current);
6453
+ const dueAt = Date.now();
6454
+ const due = current.filter(
6455
+ (item) => item.scheduledAt <= dueAt && (this.retryAtBySupervisorId.get(item.supervisorId) ?? Number.NEGATIVE_INFINITY) <= dueAt
6456
+ );
6457
+ for (const item of due) {
6458
+ this.retryAtBySupervisorId.set(item.supervisorId, dueAt + this.scheduledRetryDelayMs);
6459
+ this.deps.onScheduledDue?.(item.supervisorId);
6460
+ }
6461
+ this.refresh();
6462
+ }, delayMs);
6463
+ this.scheduledTimer.unref?.();
6464
+ }
5985
6465
  stop() {
5986
6466
  this.unsubscribe?.();
5987
6467
  this.unsubscribe = null;
6468
+ this.clearScheduledTimer();
6469
+ this.retryAtBySupervisorId.clear();
6470
+ }
6471
+ clearScheduledTimer() {
6472
+ if (this.scheduledTimer) {
6473
+ clearTimeout(this.scheduledTimer);
6474
+ this.scheduledTimer = null;
6475
+ }
6476
+ }
6477
+ getNextAttemptAt(item, now) {
6478
+ if (item.scheduledAt > now) {
6479
+ return item.scheduledAt;
6480
+ }
6481
+ const retryAt = this.retryAtBySupervisorId.get(item.supervisorId);
6482
+ return retryAt && retryAt > now ? retryAt : item.scheduledAt;
6483
+ }
6484
+ pruneRetryState(scheduled) {
6485
+ const scheduledIds = new Set(scheduled.map((item) => item.supervisorId));
6486
+ for (const supervisorId of this.retryAtBySupervisorId.keys()) {
6487
+ if (!scheduledIds.has(supervisorId)) {
6488
+ this.retryAtBySupervisorId.delete(supervisorId);
6489
+ }
6490
+ }
5988
6491
  }
5989
6492
  };
5990
6493
  }
@@ -6005,6 +6508,9 @@ function generateSupervisorId() {
6005
6508
  function generateCycleId() {
6006
6509
  return `cycle_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
6007
6510
  }
6511
+ function generateAttemptId() {
6512
+ return `attempt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
6513
+ }
6008
6514
  function messageOf(error, fallback) {
6009
6515
  if (error instanceof Error) {
6010
6516
  return error.message;
@@ -6032,6 +6538,7 @@ var init_manager2 = __esm({
6032
6538
  init_evaluator();
6033
6539
  init_injector();
6034
6540
  init_scheduler();
6541
+ init_settings();
6035
6542
  NOOP_LOGGER3 = {
6036
6543
  child: () => NOOP_LOGGER3,
6037
6544
  debug: () => {
@@ -6060,7 +6567,8 @@ var init_manager2 = __esm({
6060
6567
  sessionMgr: deps.sessionMgr,
6061
6568
  terminalMgr: deps.terminalMgr,
6062
6569
  providerRegistry: deps.providerRegistry,
6063
- logger: this.logger
6570
+ logger: this.logger,
6571
+ git: deps.git
6064
6572
  });
6065
6573
  this.evaluator = new SupervisorEvaluator({
6066
6574
  providerRegistry: deps.providerRegistry,
@@ -6079,10 +6587,19 @@ var init_manager2 = __esm({
6079
6587
  onTurnCompleted: (sessionId) => {
6080
6588
  const supervisorId = this.supervisorsBySession.get(sessionId);
6081
6589
  if (supervisorId) {
6082
- void this.runEvaluation(supervisorId).catch((error) => {
6590
+ void this.runEvaluation(supervisorId, "turn_completed").catch((error) => {
6083
6591
  this.logger.warn({ err: error, supervisorId }, "Supervisor auto-evaluation failed");
6084
6592
  });
6085
6593
  }
6594
+ },
6595
+ listScheduledSupervisors: () => this.listScheduledSupervisors(),
6596
+ onScheduledDue: (supervisorId) => {
6597
+ void this.runEvaluation(supervisorId, "scheduled").catch((error) => {
6598
+ this.logger.warn(
6599
+ { err: error, supervisorId },
6600
+ "Supervisor scheduled auto-evaluation failed"
6601
+ );
6602
+ });
6086
6603
  }
6087
6604
  });
6088
6605
  }
@@ -6091,6 +6608,7 @@ var init_manager2 = __esm({
6091
6608
  supervisorsBySession = /* @__PURE__ */ new Map();
6092
6609
  inFlight = /* @__PURE__ */ new Set();
6093
6610
  pendingDeletes = /* @__PURE__ */ new Set();
6611
+ pendingPauses = /* @__PURE__ */ new Set();
6094
6612
  evaluationAbortControllers = /* @__PURE__ */ new Map();
6095
6613
  inFlightCompletions = /* @__PURE__ */ new Map();
6096
6614
  scheduler;
@@ -6143,6 +6661,7 @@ var init_manager2 = __esm({
6143
6661
  }
6144
6662
  );
6145
6663
  this.scheduler.start();
6664
+ this.scheduler.refresh();
6146
6665
  }
6147
6666
  stop() {
6148
6667
  this.scheduler.stop();
@@ -6214,12 +6733,17 @@ var init_manager2 = __esm({
6214
6733
  state: "idle",
6215
6734
  objective: req.objective.trim(),
6216
6735
  evaluatorProviderId: req.evaluatorProviderId,
6736
+ evaluatorModel: req.evaluatorModel?.trim() || void 0,
6737
+ maxSupervisionCount: req.maxSupervisionCount ?? 0,
6738
+ completedSupervisionCount: 0,
6739
+ scheduledAt: req.scheduledAt,
6217
6740
  createdAt: now,
6218
6741
  updatedAt: now
6219
6742
  })
6220
6743
  );
6221
6744
  this.storeSnapshot(supervisor);
6222
6745
  this.broadcastState(supervisor, "created");
6746
+ this.scheduler.refresh();
6223
6747
  return supervisor;
6224
6748
  }
6225
6749
  async update(id, patch) {
@@ -6231,6 +6755,9 @@ var init_manager2 = __esm({
6231
6755
  this.deps.supervisorRepo.update(id, {
6232
6756
  objective: patch.objective !== void 0 ? patch.objective.trim() : current.objective,
6233
6757
  evaluatorProviderId: patch.evaluatorProviderId ?? current.evaluatorProviderId,
6758
+ evaluatorModel: patch.evaluatorModel === void 0 ? current.evaluatorModel : patch.evaluatorModel?.trim() || null,
6759
+ maxSupervisionCount: patch.maxSupervisionCount ?? current.maxSupervisionCount,
6760
+ scheduledAt: patch.scheduledAt === void 0 ? current.scheduledAt : patch.scheduledAt,
6234
6761
  state: current.state === "error" ? "idle" : current.state,
6235
6762
  errorReason: null,
6236
6763
  updatedAt: Date.now()
@@ -6238,9 +6765,14 @@ var init_manager2 = __esm({
6238
6765
  );
6239
6766
  this.storeSnapshot(updated);
6240
6767
  this.broadcastState(updated, "updated");
6768
+ this.scheduler.refresh();
6241
6769
  return updated;
6242
6770
  }
6243
6771
  async pause(id) {
6772
+ if (this.inFlight.has(id)) {
6773
+ this.pendingPauses.add(id);
6774
+ this.evaluationAbortControllers.get(id)?.abort();
6775
+ }
6244
6776
  const updated = this.attachCycles(
6245
6777
  this.deps.supervisorRepo.update(id, {
6246
6778
  state: "paused",
@@ -6249,6 +6781,7 @@ var init_manager2 = __esm({
6249
6781
  );
6250
6782
  this.storeSnapshot(updated);
6251
6783
  this.broadcastState(updated, "state_changed");
6784
+ this.scheduler.refresh();
6252
6785
  return updated;
6253
6786
  }
6254
6787
  async resume(id) {
@@ -6261,6 +6794,7 @@ var init_manager2 = __esm({
6261
6794
  );
6262
6795
  this.storeSnapshot(updated);
6263
6796
  this.broadcastState(updated, "state_changed");
6797
+ this.scheduler.refresh();
6264
6798
  return updated;
6265
6799
  }
6266
6800
  async delete(id) {
@@ -6269,6 +6803,7 @@ var init_manager2 = __esm({
6269
6803
  this.pendingDeletes.add(id);
6270
6804
  this.evaluationAbortControllers.get(id)?.abort();
6271
6805
  await this.inFlightCompletions.get(id)?.promise;
6806
+ this.scheduler.refresh();
6272
6807
  return;
6273
6808
  }
6274
6809
  this.deleteNow(supervisor);
@@ -6302,8 +6837,8 @@ var init_manager2 = __esm({
6302
6837
  * auto trigger path (scheduler) and for tests that want to observe the
6303
6838
  * final cycle outcome.
6304
6839
  */
6305
- async runEvaluation(supervisorId) {
6306
- const started = await this.beginCycle(supervisorId, "turn_completed");
6840
+ async runEvaluation(supervisorId, trigger = "turn_completed") {
6841
+ const started = await this.beginCycle(supervisorId, trigger);
6307
6842
  if (!started) {
6308
6843
  return null;
6309
6844
  }
@@ -6347,9 +6882,41 @@ var init_manager2 = __esm({
6347
6882
  }
6348
6883
  return null;
6349
6884
  }
6350
- if (trigger === "turn_completed" && (supervisor.state !== "idle" || session.state !== "running" && session.state !== "idle")) {
6885
+ if (supervisor.state === "stopped") {
6886
+ if (trigger === "manual") {
6887
+ throw {
6888
+ code: "supervisor_stopped",
6889
+ message: `Supervisor ${id} is stopped`
6890
+ };
6891
+ }
6892
+ return null;
6893
+ }
6894
+ if ((trigger === "turn_completed" || trigger === "scheduled") && (supervisor.state !== "idle" || session.state !== "running" && session.state !== "idle")) {
6895
+ return null;
6896
+ }
6897
+ if (supervisor.maxSupervisionCount > 0 && supervisor.completedSupervisionCount >= supervisor.maxSupervisionCount) {
6898
+ const stopped = this.attachCycles(
6899
+ this.deps.supervisorRepo.update(id, {
6900
+ state: "stopped",
6901
+ stopReason: "max_supervision_count_reached",
6902
+ updatedAt: Date.now()
6903
+ })
6904
+ );
6905
+ this.storeSnapshot(stopped);
6906
+ this.broadcastState(stopped, "state_changed");
6907
+ this.scheduler.refresh();
6351
6908
  return null;
6352
6909
  }
6910
+ if (trigger === "turn_completed") {
6911
+ if (supervisor.scheduledAt !== void 0 && supervisor.scheduledAt !== null && supervisor.scheduledAt > Date.now()) {
6912
+ return null;
6913
+ }
6914
+ }
6915
+ if (trigger === "scheduled") {
6916
+ if (supervisor.scheduledAt === void 0 || supervisor.scheduledAt > Date.now()) {
6917
+ return null;
6918
+ }
6919
+ }
6353
6920
  if (trigger === "manual" && !INJECTABLE_SESSION_STATES.has(session.state)) {
6354
6921
  throw {
6355
6922
  code: "supervisor_session_not_ready",
@@ -6360,20 +6927,25 @@ var init_manager2 = __esm({
6360
6927
  this.evaluationAbortControllers.set(id, new AbortController());
6361
6928
  this.inFlightCompletions.set(id, createDeferredCompletion());
6362
6929
  try {
6930
+ const retrySettings = getSupervisorRetrySettings(this.deps.settingsRepo);
6363
6931
  const context = await this.contextBuilder.build(supervisor);
6364
6932
  if (trigger === "turn_completed" && context.lastTurnId && context.lastTurnId === supervisor.lastEvaluatedTurnId) {
6365
6933
  this.releaseInFlight(id);
6366
6934
  return null;
6367
6935
  }
6936
+ const shouldConsumeScheduledAt = trigger === "scheduled" || trigger === "turn_completed" && supervisor.scheduledAt !== void 0 && supervisor.scheduledAt !== null && supervisor.scheduledAt <= Date.now();
6368
6937
  const evaluatingSupervisor = this.attachCycles(
6369
6938
  this.deps.supervisorRepo.update(supervisor.id, {
6370
6939
  state: "evaluating",
6940
+ scheduledAt: shouldConsumeScheduledAt ? null : supervisor.scheduledAt ?? void 0,
6941
+ stopReason: null,
6371
6942
  errorReason: null,
6372
6943
  updatedAt: Date.now()
6373
6944
  })
6374
6945
  );
6375
6946
  this.storeSnapshot(evaluatingSupervisor);
6376
6947
  this.broadcastState(evaluatingSupervisor, "state_changed");
6948
+ this.scheduler.refresh();
6377
6949
  const activeCycle = this.deps.cycleRepo.create({
6378
6950
  id: generateCycleId(),
6379
6951
  supervisorId: supervisor.id,
@@ -6387,7 +6959,18 @@ var init_manager2 = __esm({
6387
6959
  createdAt: Date.now()
6388
6960
  });
6389
6961
  this.broadcastCycle(evaluatingSupervisor, activeCycle, "created");
6390
- return { cycle: activeCycle, context };
6962
+ return {
6963
+ cycle: activeCycle,
6964
+ context,
6965
+ trigger,
6966
+ retry: {
6967
+ retryEnabled: retrySettings.retryEnabled,
6968
+ retryMaxCount: retrySettings.retryMaxCount,
6969
+ retryDelayMs: retrySettings.retryDelaySec * 1e3,
6970
+ retryOnTimeout: retrySettings.retryOnTimeout,
6971
+ retryOnEvaluatorError: retrySettings.retryOnEvaluatorError
6972
+ }
6973
+ };
6391
6974
  } catch (error) {
6392
6975
  this.releaseInFlight(id);
6393
6976
  this.markSupervisorError(id, error);
@@ -6404,75 +6987,20 @@ var init_manager2 = __esm({
6404
6987
  const supervisorId = activeCycle.supervisorId;
6405
6988
  try {
6406
6989
  const supervisorForEval = this.supervisors.get(supervisorId) ?? this.requireSupervisor(supervisorId);
6407
- const evaluation = await this.evaluator.evaluate(supervisorForEval, context, {
6408
- signal: this.evaluationAbortControllers.get(supervisorId)?.signal
6409
- });
6410
- let injected = false;
6411
- let injectedText;
6412
- let cycleResult;
6413
- let injectionError;
6414
- if (evaluation.message.trim()) {
6415
- const injectingSupervisor = this.attachCycles(
6416
- this.deps.supervisorRepo.update(supervisorId, {
6417
- state: "injecting",
6418
- updatedAt: Date.now()
6419
- })
6420
- );
6421
- this.storeSnapshot(injectingSupervisor);
6422
- this.broadcastState(injectingSupervisor, "state_changed");
6423
- const recentCycles = this.deps.cycleRepo.listRecentForSupervisor(supervisorId, this.config.guidanceDedupeWindow + 1).filter((cycle) => cycle.id !== activeCycle.id);
6424
- try {
6425
- const injection = await this.injector.inject(
6426
- injectingSupervisor,
6427
- {
6428
- message: evaluation.message
6429
- },
6430
- recentCycles
6431
- );
6432
- injected = injection.injected;
6433
- injectedText = injection.injected ? injection.text : void 0;
6434
- cycleResult = injection.injected ? injection.text : `Skipped duplicate: ${injection.text}`;
6435
- } catch (error) {
6436
- injectionError = messageOf(error, "Injection failed");
6437
- this.logger.warn(
6438
- { err: error, supervisorId, cycleId: activeCycle.id },
6439
- "Supervisor injection failed"
6440
- );
6441
- }
6442
- }
6443
- const finalStatus = injectionError ? "failed" : injected ? "injected" : "completed";
6444
- const finishedCycle = this.deps.cycleRepo.update(activeCycle.id, {
6445
- status: finalStatus,
6446
- result: cycleResult ?? null,
6447
- injectedGuidance: injectedText,
6448
- errorReason: injectionError ?? null,
6449
- completedAt: Date.now()
6450
- });
6451
- const latestState = this.supervisors.get(supervisorId)?.state;
6452
- const nextState = latestState === "paused" ? "paused" : injectionError ? "error" : "idle";
6453
- const finishedSupervisor = this.attachCycles(
6454
- this.deps.supervisorRepo.update(supervisorId, {
6455
- state: nextState,
6456
- lastCycleAt: finishedCycle.completedAt,
6457
- lastEvaluatedTurnId: context.lastTurnId ?? void 0,
6458
- errorReason: injectionError ?? null,
6459
- updatedAt: Date.now()
6460
- })
6461
- );
6462
- this.storeSnapshot(finishedSupervisor);
6463
- this.broadcastCycle(finishedSupervisor, finishedCycle, "updated");
6464
- this.broadcastState(finishedSupervisor, "state_changed");
6465
- this.deps.cycleRepo.pruneOldest(supervisorId, this.config.maxCyclesPerSession);
6990
+ const signal = this.evaluationAbortControllers.get(supervisorId)?.signal;
6991
+ const evaluation = await this.executeCycleWithRetry(started, supervisorForEval, signal);
6992
+ const finalized = this.finalizeSuccessfulCycle(activeCycle, context, evaluation);
6466
6993
  if (this.pendingDeletes.has(supervisorId)) {
6467
6994
  this.pendingDeletes.delete(supervisorId);
6468
- this.deleteNow(finishedSupervisor);
6995
+ this.deleteNow(finalized.supervisor);
6469
6996
  }
6470
- return finishedCycle;
6997
+ return finalized.cycle;
6471
6998
  } catch (error) {
6472
6999
  if (isSupervisorEvalAborted(error)) {
7000
+ const cancelled = this.pendingPauses.has(supervisorId);
6473
7001
  const abortedCycle = this.deps.cycleRepo.update(activeCycle.id, {
6474
- status: "failed",
6475
- errorReason: messageOf(error, "Supervisor evaluator aborted"),
7002
+ status: cancelled ? "cancelled" : "failed",
7003
+ errorReason: cancelled ? null : messageOf(error, "Supervisor evaluator aborted"),
6476
7004
  completedAt: Date.now()
6477
7005
  });
6478
7006
  const currentSupervisor = this.supervisors.get(supervisorId) ?? this.requireSupervisor(supervisorId);
@@ -6483,10 +7011,11 @@ var init_manager2 = __esm({
6483
7011
  return abortedCycle;
6484
7012
  }
6485
7013
  const latestState = this.supervisors.get(supervisorId)?.state;
6486
- const nextState = latestState === "paused" ? "paused" : "idle";
7014
+ const nextState = cancelled || latestState === "paused" ? "paused" : "idle";
6487
7015
  const recoveredSupervisor = this.attachCycles(
6488
7016
  this.deps.supervisorRepo.update(supervisorId, {
6489
7017
  state: nextState,
7018
+ stopReason: null,
6490
7019
  errorReason: null,
6491
7020
  updatedAt: Date.now()
6492
7021
  })
@@ -6495,6 +7024,8 @@ var init_manager2 = __esm({
6495
7024
  this.broadcastCycle(recoveredSupervisor, abortedCycle, "updated");
6496
7025
  this.broadcastState(recoveredSupervisor, "state_changed");
6497
7026
  this.deps.cycleRepo.pruneOldest(supervisorId, this.config.maxCyclesPerSession);
7027
+ this.scheduler.refresh();
7028
+ this.pendingPauses.delete(supervisorId);
6498
7029
  return abortedCycle;
6499
7030
  }
6500
7031
  logFailure(
@@ -6512,6 +7043,7 @@ var init_manager2 = __esm({
6512
7043
  const failedSupervisor = this.attachCycles(
6513
7044
  this.deps.supervisorRepo.update(supervisorId, {
6514
7045
  state: "error",
7046
+ stopReason: null,
6515
7047
  errorReason: reason,
6516
7048
  updatedAt: Date.now()
6517
7049
  })
@@ -6525,9 +7057,122 @@ var init_manager2 = __esm({
6525
7057
  }
6526
7058
  throw error;
6527
7059
  } finally {
7060
+ this.pendingPauses.delete(supervisorId);
6528
7061
  this.releaseInFlight(supervisorId);
6529
7062
  }
6530
7063
  }
7064
+ async executeCycleWithRetry(started, supervisor, signal) {
7065
+ for (let attemptIndex = 0; ; attemptIndex += 1) {
7066
+ const attempt = this.deps.cycleAttemptRepo.create({
7067
+ id: generateAttemptId(),
7068
+ cycleId: started.cycle.id,
7069
+ attemptIndex,
7070
+ status: "evaluating",
7071
+ startedAt: Date.now()
7072
+ });
7073
+ try {
7074
+ const evaluation = await this.evaluator.evaluate(supervisor, started.context, { signal });
7075
+ this.deps.cycleAttemptRepo.update(attempt.id, {
7076
+ status: "completed",
7077
+ completedAt: Date.now(),
7078
+ providerModel: supervisor.evaluatorModel ?? null
7079
+ });
7080
+ if (evaluation.objectiveComplete) {
7081
+ return {
7082
+ objectiveComplete: true,
7083
+ injected: false,
7084
+ cycleResult: evaluation.message
7085
+ };
7086
+ }
7087
+ if (!evaluation.message.trim()) {
7088
+ return {
7089
+ objectiveComplete: false,
7090
+ injected: false
7091
+ };
7092
+ }
7093
+ if (signal?.aborted || this.pendingPauses.has(supervisor.id)) {
7094
+ throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
7095
+ }
7096
+ const injectingSupervisor = this.attachCycles(
7097
+ this.deps.supervisorRepo.update(supervisor.id, {
7098
+ state: "injecting",
7099
+ updatedAt: Date.now()
7100
+ })
7101
+ );
7102
+ this.storeSnapshot(injectingSupervisor);
7103
+ this.broadcastState(injectingSupervisor, "state_changed");
7104
+ const recentCycles = this.deps.cycleRepo.listRecentForSupervisor(supervisor.id, this.config.guidanceDedupeWindow + 1).filter((cycle) => cycle.id !== started.cycle.id);
7105
+ const injection = await this.injector.inject(
7106
+ injectingSupervisor,
7107
+ {
7108
+ message: evaluation.message
7109
+ },
7110
+ recentCycles,
7111
+ { signal }
7112
+ );
7113
+ return {
7114
+ objectiveComplete: false,
7115
+ injected: injection.injected,
7116
+ injectedText: injection.injected ? injection.text : void 0,
7117
+ cycleResult: injection.injected ? injection.text : `Skipped duplicate: ${injection.text}`
7118
+ };
7119
+ } catch (error) {
7120
+ if (isSupervisorEvalAborted(error)) {
7121
+ this.deps.cycleAttemptRepo.update(attempt.id, {
7122
+ status: this.pendingPauses.has(supervisor.id) ? "cancelled" : "failed",
7123
+ completedAt: Date.now(),
7124
+ errorReason: this.pendingPauses.has(supervisor.id) ? null : messageOf(error, "Supervisor evaluator aborted")
7125
+ });
7126
+ throw error;
7127
+ }
7128
+ const reason = messageOf(error, "Supervisor evaluation failed");
7129
+ this.deps.cycleAttemptRepo.update(attempt.id, {
7130
+ status: "failed",
7131
+ completedAt: Date.now(),
7132
+ errorReason: reason
7133
+ });
7134
+ if (!this.shouldRetryAttempt(error, attemptIndex, started.retry)) {
7135
+ throw error;
7136
+ }
7137
+ await this.sleep(started.retry.retryDelayMs, signal);
7138
+ const evaluatingSupervisor = this.attachCycles(
7139
+ this.deps.supervisorRepo.update(supervisor.id, {
7140
+ state: "evaluating",
7141
+ updatedAt: Date.now()
7142
+ })
7143
+ );
7144
+ this.storeSnapshot(evaluatingSupervisor);
7145
+ this.broadcastState(evaluatingSupervisor, "state_changed");
7146
+ }
7147
+ }
7148
+ }
7149
+ finalizeSuccessfulCycle(activeCycle, context, result) {
7150
+ const finalStatus = result.injected ? "injected" : result.objectiveComplete ? "completed" : "completed";
7151
+ const finishedCycle = this.deps.cycleRepo.update(activeCycle.id, {
7152
+ status: finalStatus,
7153
+ result: result.cycleResult ?? null,
7154
+ injectedGuidance: result.injectedText ?? null,
7155
+ errorReason: null,
7156
+ completedAt: Date.now()
7157
+ });
7158
+ const finishedSupervisor = this.attachCycles(
7159
+ this.deps.supervisorRepo.update(activeCycle.supervisorId, {
7160
+ state: result.objectiveComplete ? "stopped" : "idle",
7161
+ completedSupervisionCount: (this.supervisors.get(activeCycle.supervisorId)?.completedSupervisionCount ?? 0) + 1,
7162
+ stopReason: result.objectiveComplete ? "objective_complete" : null,
7163
+ lastCycleAt: finishedCycle.completedAt,
7164
+ lastEvaluatedTurnId: context.lastTurnId ?? void 0,
7165
+ errorReason: null,
7166
+ updatedAt: Date.now()
7167
+ })
7168
+ );
7169
+ this.storeSnapshot(finishedSupervisor);
7170
+ this.broadcastCycle(finishedSupervisor, finishedCycle, "updated");
7171
+ this.broadcastState(finishedSupervisor, "state_changed");
7172
+ this.deps.cycleRepo.pruneOldest(activeCycle.supervisorId, this.config.maxCyclesPerSession);
7173
+ this.scheduler.refresh();
7174
+ return { cycle: finishedCycle, supervisor: finishedSupervisor };
7175
+ }
6531
7176
  /**
6532
7177
  * Flip a supervisor to 'error' state when something blows up before we
6533
7178
  * had a chance to create a cycle. Without this the supervisor can get
@@ -6593,6 +7238,14 @@ var init_manager2 = __esm({
6593
7238
  cycles: this.deps.cycleRepo.listRecentForSupervisor(supervisor.id, 20)
6594
7239
  };
6595
7240
  }
7241
+ listScheduledSupervisors() {
7242
+ return Array.from(this.supervisors.values()).filter(
7243
+ (supervisor) => supervisor.state === "idle" && typeof supervisor.scheduledAt === "number" && Number.isFinite(supervisor.scheduledAt)
7244
+ ).map((supervisor) => ({
7245
+ supervisorId: supervisor.id,
7246
+ scheduledAt: supervisor.scheduledAt
7247
+ }));
7248
+ }
6596
7249
  storeSnapshot(supervisor) {
6597
7250
  this.supervisors.set(supervisor.id, supervisor);
6598
7251
  this.supervisorsBySession.set(supervisor.sessionId, supervisor.id);
@@ -6602,7 +7255,9 @@ var init_manager2 = __esm({
6602
7255
  this.supervisors.delete(supervisor.id);
6603
7256
  this.supervisorsBySession.delete(supervisor.sessionId);
6604
7257
  this.pendingDeletes.delete(supervisor.id);
7258
+ this.pendingPauses.delete(supervisor.id);
6605
7259
  this.releaseInFlight(supervisor.id);
7260
+ this.scheduler.refresh();
6606
7261
  this.deps.broadcaster.broadcast(
6607
7262
  Topics.supervisorState(supervisor.workspaceId, supervisor.sessionId),
6608
7263
  { supervisorId: supervisor.id, event: "deleted" }
@@ -6636,6 +7291,43 @@ var init_manager2 = __esm({
6636
7291
  { cycle, event }
6637
7292
  );
6638
7293
  }
7294
+ shouldRetryAttempt(error, attemptIndex, retry) {
7295
+ if (!retry.retryEnabled) {
7296
+ return false;
7297
+ }
7298
+ if (attemptIndex >= retry.retryMaxCount) {
7299
+ return false;
7300
+ }
7301
+ const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
7302
+ if (code === "supervisor_eval_timeout") {
7303
+ return retry.retryOnTimeout;
7304
+ }
7305
+ if (code === "supervisor_eval_failed") {
7306
+ return retry.retryOnEvaluatorError;
7307
+ }
7308
+ return false;
7309
+ }
7310
+ async sleep(delayMs, signal) {
7311
+ if (delayMs <= 0) {
7312
+ return;
7313
+ }
7314
+ if (signal?.aborted) {
7315
+ throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
7316
+ }
7317
+ await new Promise((resolve4, reject) => {
7318
+ const timer = setTimeout(() => {
7319
+ signal?.removeEventListener("abort", onAbort);
7320
+ resolve4();
7321
+ }, delayMs);
7322
+ timer.unref?.();
7323
+ const onAbort = () => {
7324
+ clearTimeout(timer);
7325
+ signal?.removeEventListener("abort", onAbort);
7326
+ reject({ code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" });
7327
+ };
7328
+ signal?.addEventListener("abort", onAbort, { once: true });
7329
+ });
7330
+ }
6639
7331
  };
6640
7332
  }
6641
7333
  });
@@ -7446,9 +8138,9 @@ var init_validator = __esm({
7446
8138
  });
7447
8139
 
7448
8140
  // packages/server/src/fs/gitignore.ts
7449
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
8141
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
7450
8142
  import ignore from "ignore";
7451
- import { join as join5, relative as relative3 } from "path";
8143
+ import { join as join4, relative as relative3 } from "path";
7452
8144
  function normalizePath(path10) {
7453
8145
  return path10.replace(/\\/g, "/");
7454
8146
  }
@@ -7468,26 +8160,26 @@ function isIgnoredByGitignore(ig, path10) {
7468
8160
  return ig.ignores(path10) || ig.ignores(`${path10}/`);
7469
8161
  }
7470
8162
  function createGitignoreFilter(rootPath, dirPath) {
7471
- const gitignorePath = join5(rootPath, ".gitignore");
7472
- if (!existsSync8(gitignorePath)) {
8163
+ const gitignorePath = join4(rootPath, ".gitignore");
8164
+ if (!existsSync5(gitignorePath)) {
7473
8165
  return (name) => !isDefaultTreeIgnored(name);
7474
8166
  }
7475
- const gitignoreContent = readFileSync7(gitignorePath, "utf-8");
8167
+ const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
7476
8168
  const ig = ignore().add(gitignoreContent);
7477
8169
  return (name) => {
7478
8170
  if (isAlwaysTreeIgnored(name)) {
7479
8171
  return false;
7480
8172
  }
7481
- const relativePath = relativeToRoot(rootPath, join5(dirPath, name));
8173
+ const relativePath = relativeToRoot(rootPath, join4(dirPath, name));
7482
8174
  return !isIgnoredByGitignore(ig, relativePath);
7483
8175
  };
7484
8176
  }
7485
8177
  function createWatcherIgnoreFilter(rootPath) {
7486
- const gitignorePath = join5(rootPath, ".gitignore");
7487
- if (!existsSync8(gitignorePath)) {
8178
+ const gitignorePath = join4(rootPath, ".gitignore");
8179
+ if (!existsSync5(gitignorePath)) {
7488
8180
  return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
7489
8181
  }
7490
- const gitignoreContent = readFileSync7(gitignorePath, "utf-8");
8182
+ const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
7491
8183
  const ig = ignore().add(gitignoreContent);
7492
8184
  return (path10) => {
7493
8185
  const normalizedPath = normalizePath(path10);
@@ -7537,6 +8229,7 @@ var init_watcher = __esm({
7537
8229
  dirtyTimer = null;
7538
8230
  firstDirtyTime = null;
7539
8231
  pendingReason = null;
8232
+ pendingWorktreeChanged = false;
7540
8233
  DEBOUNCE_MS = 200;
7541
8234
  MAX_WAIT_MS = 1e3;
7542
8235
  /**
@@ -7549,6 +8242,9 @@ var init_watcher = __esm({
7549
8242
  if (this.firstDirtyTime === null) {
7550
8243
  this.firstDirtyTime = now;
7551
8244
  }
8245
+ if (changedPath && this.isWorktreeMetadataPath(changedPath)) {
8246
+ this.pendingWorktreeChanged = true;
8247
+ }
7552
8248
  if (changedPath && !this.isGitMetadataPath(changedPath)) {
7553
8249
  this.pendingReason = "fs_change";
7554
8250
  } else if (changedPath && this.pendingReason !== "fs_change") {
@@ -7567,13 +8263,23 @@ var init_watcher = __esm({
7567
8263
  this.broadcaster?.broadcast(Topics.workspaceFsDirty(this.workspaceId), {
7568
8264
  reason: this.pendingReason ?? "fs_change"
7569
8265
  });
8266
+ if (this.pendingWorktreeChanged) {
8267
+ this.broadcaster?.broadcast(Topics.workspaceGitState(this.workspaceId), {
8268
+ worktreeChanged: true
8269
+ });
8270
+ }
7570
8271
  this.dirtyTimer = null;
7571
8272
  this.firstDirtyTime = null;
7572
8273
  this.pendingReason = null;
8274
+ this.pendingWorktreeChanged = false;
7573
8275
  }
7574
8276
  isGitMetadataPath(changedPath) {
7575
8277
  return changedPath.replace(/\\/g, "/").includes("/.git/");
7576
8278
  }
8279
+ isWorktreeMetadataPath(changedPath) {
8280
+ const normalized = changedPath.replace(/\\/g, "/");
8281
+ return normalized.includes("/.git/worktrees");
8282
+ }
7577
8283
  /**
7578
8284
  * Stops watching and cleans up resources.
7579
8285
  */
@@ -7809,12 +8515,103 @@ var init_manager4 = __esm({
7809
8515
  }
7810
8516
  });
7811
8517
 
8518
+ // packages/server/src/ws/activation.ts
8519
+ var DEFAULT_OPTIONS, ActivationManager;
8520
+ var init_activation = __esm({
8521
+ "packages/server/src/ws/activation.ts"() {
8522
+ "use strict";
8523
+ DEFAULT_OPTIONS = {
8524
+ graceMs: 3e3
8525
+ };
8526
+ ActivationManager = class {
8527
+ options;
8528
+ lease = null;
8529
+ generation = 0;
8530
+ constructor(options) {
8531
+ this.options = { ...DEFAULT_OPTIONS, ...options };
8532
+ }
8533
+ claim(clientInstanceId, wsClientId, request) {
8534
+ const now = Date.now();
8535
+ const activeLease = this.getLease();
8536
+ if (activeLease && activeLease.clientInstanceId === clientInstanceId) {
8537
+ const isGraceRecovery = activeLease.graceUntil !== null && now <= activeLease.graceUntil;
8538
+ const displacedWsClientId2 = isGraceRecovery || activeLease.wsClientId === wsClientId ? null : activeLease.wsClientId;
8539
+ activeLease.wsClientId = wsClientId;
8540
+ activeLease.graceUntil = null;
8541
+ return {
8542
+ active: true,
8543
+ generation: activeLease.generation,
8544
+ recoveryMode: "grace_recover",
8545
+ displacedWsClientId: displacedWsClientId2
8546
+ };
8547
+ }
8548
+ const displacedWsClientId = activeLease && activeLease.clientInstanceId !== clientInstanceId ? activeLease.wsClientId : null;
8549
+ const recoveryMode = displacedWsClientId === null ? "fresh" : "takeover";
8550
+ this.generation += 1;
8551
+ this.lease = {
8552
+ clientInstanceId,
8553
+ wsClientId,
8554
+ generation: this.generation,
8555
+ issuedAt: now,
8556
+ graceUntil: null,
8557
+ ip: request.ip,
8558
+ userAgent: request.headers["user-agent"] ?? ""
8559
+ };
8560
+ return {
8561
+ active: true,
8562
+ generation: this.lease.generation,
8563
+ recoveryMode,
8564
+ displacedWsClientId
8565
+ };
8566
+ }
8567
+ release(clientInstanceId, generation) {
8568
+ const lease = this.getLease();
8569
+ if (!lease) {
8570
+ return;
8571
+ }
8572
+ if (lease.clientInstanceId !== clientInstanceId || lease.generation !== generation) {
8573
+ return;
8574
+ }
8575
+ this.lease = null;
8576
+ }
8577
+ onSocketClosed(wsClientId) {
8578
+ const lease = this.getLease();
8579
+ if (!lease || lease.wsClientId !== wsClientId) {
8580
+ return;
8581
+ }
8582
+ lease.graceUntil = Date.now() + this.options.graceMs;
8583
+ }
8584
+ getLease() {
8585
+ if (!this.lease) {
8586
+ return null;
8587
+ }
8588
+ return this.lease;
8589
+ }
8590
+ };
8591
+ }
8592
+ });
8593
+
7812
8594
  // packages/server/src/ws/dispatch.ts
7813
8595
  function registerCommand(op, schema, handler) {
7814
8596
  handlers.set(op, handler);
7815
8597
  schemas.set(op, schema);
7816
8598
  }
7817
8599
  async function dispatch(msg, ctx, clientId) {
8600
+ const isWsDispatch = clientId !== void 0 && typeof ctx.broadcaster.getRequestMetadata === "function";
8601
+ if (isWsDispatch && !ACTIVATION_ALLOWLIST.has(msg.op)) {
8602
+ const active = ctx.activationMgr.getLease();
8603
+ if (!active || active.wsClientId !== clientId) {
8604
+ return {
8605
+ kind: "result",
8606
+ id: msg.id,
8607
+ ok: false,
8608
+ error: {
8609
+ code: "activation_required",
8610
+ message: "This tab is no longer the active session"
8611
+ }
8612
+ };
8613
+ }
8614
+ }
7818
8615
  const handler = handlers.get(msg.op);
7819
8616
  if (!handler) {
7820
8617
  return {
@@ -7871,21 +8668,26 @@ function normalizeError(error) {
7871
8668
  message: candidate.message || "An internal error occurred"
7872
8669
  };
7873
8670
  }
7874
- var handlers, schemas;
8671
+ var handlers, schemas, ACTIVATION_ALLOWLIST;
7875
8672
  var init_dispatch = __esm({
7876
8673
  "packages/server/src/ws/dispatch.ts"() {
7877
8674
  "use strict";
7878
8675
  handlers = /* @__PURE__ */ new Map();
7879
8676
  schemas = /* @__PURE__ */ new Map();
8677
+ ACTIVATION_ALLOWLIST = /* @__PURE__ */ new Set([
8678
+ "activation.claim",
8679
+ "activation.release",
8680
+ "connection.probe"
8681
+ ]);
7880
8682
  }
7881
8683
  });
7882
8684
 
7883
8685
  // packages/server/src/ws/fencing.ts
7884
- var DEFAULT_OPTIONS, FencingManager;
8686
+ var DEFAULT_OPTIONS2, FencingManager;
7885
8687
  var init_fencing = __esm({
7886
8688
  "packages/server/src/ws/fencing.ts"() {
7887
8689
  "use strict";
7888
- DEFAULT_OPTIONS = {
8690
+ DEFAULT_OPTIONS2 = {
7889
8691
  visibleHeartbeatMs: 1e4,
7890
8692
  // 10 seconds
7891
8693
  hiddenHeartbeatMs: 2e4,
@@ -7904,7 +8706,7 @@ var init_fencing = __esm({
7904
8706
  // workspaceId -> { clientId, closedAt, ip, ua } (for grace period)
7905
8707
  lastWriter = /* @__PURE__ */ new Map();
7906
8708
  constructor(options) {
7907
- this.options = { ...DEFAULT_OPTIONS, ...options };
8709
+ this.options = { ...DEFAULT_OPTIONS2, ...options };
7908
8710
  }
7909
8711
  /**
7910
8712
  * Request controller status for a workspace.
@@ -8053,7 +8855,7 @@ var init_fencing = __esm({
8053
8855
  });
8054
8856
 
8055
8857
  // packages/server/src/commands/terminal.ts
8056
- import { basename as basename2 } from "node:path";
8858
+ import { basename } from "node:path";
8057
8859
  import { z as z5 } from "zod";
8058
8860
  function decodeTerminalInput(args) {
8059
8861
  if ("bytes" in args) {
@@ -8108,11 +8910,11 @@ function resolveShellCommand() {
8108
8910
  const shellPath2 = process.env.ComSpec || process.env.COMSPEC || "cmd.exe";
8109
8911
  return {
8110
8912
  argv: [shellPath2],
8111
- title: basename2(shellPath2) || shellPath2
8913
+ title: basename(shellPath2) || shellPath2
8112
8914
  };
8113
8915
  }
8114
8916
  const shellPath = process.env.SHELL || "/bin/bash";
8115
- const shellName = basename2(shellPath);
8917
+ const shellName = basename(shellPath);
8116
8918
  const argv = shellName === "cmd.exe" ? [shellPath] : [shellPath, "-i"];
8117
8919
  return {
8118
8920
  argv,
@@ -8423,8 +9225,12 @@ var init_client = __esm({
8423
9225
  evictedBytesSinceLastWarn = 0;
8424
9226
  lastStreamBufferWarnAt = 0;
8425
9227
  logger;
9228
+ markAlive() {
9229
+ this.isAlive = true;
9230
+ }
8426
9231
  setupSocketHandlers() {
8427
9232
  this.socket.on("message", (data, isBinary) => {
9233
+ this.markAlive();
8428
9234
  if (isBinary) {
8429
9235
  this.messageHandler?.(data);
8430
9236
  return;
@@ -8443,7 +9249,7 @@ var init_client = __esm({
8443
9249
  this.closeHandler?.();
8444
9250
  });
8445
9251
  this.socket.on("pong", () => {
8446
- this.isAlive = true;
9252
+ this.markAlive();
8447
9253
  });
8448
9254
  }
8449
9255
  /**
@@ -8474,6 +9280,20 @@ var init_client = __esm({
8474
9280
  return false;
8475
9281
  }
8476
9282
  }
9283
+ sendControlAndClose(msg, code, reason) {
9284
+ if (this.socket.readyState !== WebSocket.OPEN) {
9285
+ return false;
9286
+ }
9287
+ try {
9288
+ this.socket.send(JSON.stringify(msg), () => {
9289
+ this.socket.close(code, reason);
9290
+ });
9291
+ return true;
9292
+ } catch (error) {
9293
+ console.error(`Failed to send message to client ${this.id}:`, error);
9294
+ return false;
9295
+ }
9296
+ }
8477
9297
  sendBinary(data) {
8478
9298
  if (this.socket.readyState !== WebSocket.OPEN) {
8479
9299
  return false;
@@ -8638,6 +9458,16 @@ var init_client = __esm({
8638
9458
  };
8639
9459
  return this.send(event);
8640
9460
  }
9461
+ sendEventAndClose(topic, data, code, reason, seq = 0) {
9462
+ const event = {
9463
+ kind: "event",
9464
+ topic,
9465
+ seq,
9466
+ timestamp: Date.now(),
9467
+ data
9468
+ };
9469
+ return this.sendControlAndClose(event, code, reason);
9470
+ }
8641
9471
  /**
8642
9472
  * Check if client subscribes to a topic (supports glob patterns)
8643
9473
  */
@@ -8747,6 +9577,7 @@ var init_hub = __esm({
8747
9577
  }
8748
9578
  deps;
8749
9579
  clients = /* @__PURE__ */ new Map();
9580
+ clientRequests = /* @__PURE__ */ new Map();
8750
9581
  eventUnsubscribers = [];
8751
9582
  nextStreamId = 1;
8752
9583
  // Per-client queue of waiters for the next inbound binary frame. The
@@ -8763,9 +9594,10 @@ var init_hub = __esm({
8763
9594
  /**
8764
9595
  * Handle a new WebSocket connection
8765
9596
  */
8766
- handleConnection(socket, _req) {
9597
+ handleConnection(socket, req) {
8767
9598
  const client = new WsClient(socket, uuidv4(), this.deps.logger);
8768
9599
  this.clients.set(client.id, client);
9600
+ this.clientRequests.set(client.id, req);
8769
9601
  client.sendEvent("connection.status", {
8770
9602
  status: "connected",
8771
9603
  clientId: client.id,
@@ -8899,8 +9731,10 @@ var init_hub = __esm({
8899
9731
  */
8900
9732
  handleClose(client) {
8901
9733
  this.clients.delete(client.id);
9734
+ this.clientRequests.delete(client.id);
8902
9735
  this.discardPendingBinaryWaiters(client.id);
8903
9736
  this.deps.commandContext?.autoFetch.unregisterViewer(client.id);
9737
+ this.deps.commandContext?.activationMgr.onSocketClosed(client.id);
8904
9738
  }
8905
9739
  /**
8906
9740
  * Takeover: Force close existing writer and accept new one
@@ -8941,6 +9775,24 @@ var init_hub = __esm({
8941
9775
  if (!client) return false;
8942
9776
  return client.sendBinary(data);
8943
9777
  }
9778
+ revokeAndCloseClient(clientId, generation) {
9779
+ const client = this.clients.get(clientId);
9780
+ if (!client) {
9781
+ return;
9782
+ }
9783
+ client.sendEventAndClose(
9784
+ "activation.revoked",
9785
+ {
9786
+ reason: "displaced",
9787
+ generation
9788
+ },
9789
+ 4001,
9790
+ "single_active_displaced"
9791
+ );
9792
+ }
9793
+ getRequestMetadata(clientId) {
9794
+ return this.clientRequests.get(clientId);
9795
+ }
8944
9796
  /**
8945
9797
  * Get the current writer client
8946
9798
  * DEPRECATED: Writer tracking now handled by FencingManager
@@ -8953,6 +9805,10 @@ var init_hub = __esm({
8953
9805
  */
8954
9806
  pingAll() {
8955
9807
  for (const client of this.clients.values()) {
9808
+ if (!client.alive) {
9809
+ client.close(1011, "keepalive_timeout");
9810
+ continue;
9811
+ }
8956
9812
  client.ping();
8957
9813
  }
8958
9814
  }
@@ -8964,6 +9820,7 @@ var init_hub = __esm({
8964
9820
  client.close();
8965
9821
  }
8966
9822
  this.clients.clear();
9823
+ this.clientRequests.clear();
8967
9824
  }
8968
9825
  /**
8969
9826
  * Subscribe to domain events and broadcast them
@@ -9093,8 +9950,8 @@ var init_hub = __esm({
9093
9950
 
9094
9951
  // packages/server/src/commands/workspace.ts
9095
9952
  import { readdir as readdir2 } from "node:fs/promises";
9096
- import { homedir as homedir3 } from "node:os";
9097
- import { join as join6 } from "node:path";
9953
+ import { homedir as homedir2 } from "node:os";
9954
+ import { join as join5 } from "node:path";
9098
9955
  import { z as z6 } from "zod";
9099
9956
  var init_workspace = __esm({
9100
9957
  "packages/server/src/commands/workspace.ts"() {
@@ -9109,15 +9966,15 @@ var init_workspace = __esm({
9109
9966
  path: z6.string().optional()
9110
9967
  }),
9111
9968
  async (args) => {
9112
- const basePath = args.path || homedir3();
9969
+ const basePath = args.path || homedir2();
9113
9970
  const entries = await readdir2(basePath, { withFileTypes: true });
9114
9971
  const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
9115
9972
  name: entry.name,
9116
- path: join6(basePath, entry.name)
9973
+ path: join5(basePath, entry.name)
9117
9974
  })).sort((a, b) => a.name.localeCompare(b.name));
9118
9975
  return {
9119
9976
  currentPath: basePath,
9120
- parentPath: basePath !== "/" ? join6(basePath, "..") : null,
9977
+ parentPath: basePath !== "/" ? join5(basePath, "..") : null,
9121
9978
  directories
9122
9979
  };
9123
9980
  }
@@ -9211,6 +10068,63 @@ var init_workspace_activity = __esm({
9211
10068
  }
9212
10069
  });
9213
10070
 
10071
+ // packages/server/src/commands/activation.ts
10072
+ import { z as z8 } from "zod";
10073
+ var init_activation2 = __esm({
10074
+ "packages/server/src/commands/activation.ts"() {
10075
+ "use strict";
10076
+ init_dispatch();
10077
+ registerCommand(
10078
+ "activation.claim",
10079
+ z8.object({ clientInstanceId: z8.string().min(1) }),
10080
+ async (args, ctx, clientId) => {
10081
+ if (!clientId) {
10082
+ throw {
10083
+ code: "activation_request_unavailable",
10084
+ message: "Activation claim requires websocket request metadata"
10085
+ };
10086
+ }
10087
+ const request = ctx.broadcaster.getRequestMetadata?.(clientId);
10088
+ if (!request) {
10089
+ throw {
10090
+ code: "activation_request_unavailable",
10091
+ message: "Activation claim requires websocket request metadata"
10092
+ };
10093
+ }
10094
+ const claim = ctx.activationMgr.claim(args.clientInstanceId, clientId, request);
10095
+ if (claim.displacedWsClientId) {
10096
+ ctx.broadcaster.revokeAndCloseClient?.(claim.displacedWsClientId, claim.generation);
10097
+ }
10098
+ return claim;
10099
+ }
10100
+ );
10101
+ registerCommand(
10102
+ "activation.release",
10103
+ z8.object({ clientInstanceId: z8.string(), generation: z8.number().int().positive() }),
10104
+ async (args, ctx, clientId) => {
10105
+ const lease = ctx.activationMgr.getLease();
10106
+ if (!clientId || !lease || lease.wsClientId !== clientId) {
10107
+ return { ok: false };
10108
+ }
10109
+ ctx.activationMgr.release(args.clientInstanceId, args.generation);
10110
+ return { ok: true };
10111
+ }
10112
+ );
10113
+ }
10114
+ });
10115
+
10116
+ // packages/server/src/commands/connection.ts
10117
+ import { z as z9 } from "zod";
10118
+ var init_connection = __esm({
10119
+ "packages/server/src/commands/connection.ts"() {
10120
+ "use strict";
10121
+ init_dispatch();
10122
+ registerCommand("connection.probe", z9.object({}).default({}), async () => {
10123
+ return { ok: true };
10124
+ });
10125
+ }
10126
+ });
10127
+
9214
10128
  // packages/server/src/provider-runtime/runtime-status.ts
9215
10129
  function canAutoInstall(provider, platform, missingCommands, missingPrerequisites, availableCommands) {
9216
10130
  const strategies = provider.install.strategies[platform] ?? [];
@@ -9305,7 +10219,7 @@ var init_runtime_status = __esm({
9305
10219
  });
9306
10220
 
9307
10221
  // packages/server/src/commands/session.ts
9308
- import { z as z8 } from "zod";
10222
+ import { z as z10 } from "zod";
9309
10223
  function getProviderFromRegistry(providerId, registry) {
9310
10224
  return registry.find((provider) => provider.id === providerId);
9311
10225
  }
@@ -9316,8 +10230,8 @@ var init_session = __esm({
9316
10230
  init_dispatch();
9317
10231
  registerCommand(
9318
10232
  "session.list",
9319
- z8.object({
9320
- workspaceId: z8.string()
10233
+ z10.object({
10234
+ workspaceId: z10.string()
9321
10235
  }),
9322
10236
  async (args, ctx) => {
9323
10237
  return ctx.sessionMgr.getForWorkspace(args.workspaceId);
@@ -9325,10 +10239,10 @@ var init_session = __esm({
9325
10239
  );
9326
10240
  registerCommand(
9327
10241
  "session.create",
9328
- z8.object({
9329
- workspaceId: z8.string(),
9330
- providerId: z8.string(),
9331
- draft: z8.string().optional()
10242
+ z10.object({
10243
+ workspaceId: z10.string(),
10244
+ providerId: z10.string(),
10245
+ draft: z10.string().optional()
9332
10246
  }),
9333
10247
  async (args, ctx) => {
9334
10248
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9362,8 +10276,8 @@ var init_session = __esm({
9362
10276
  );
9363
10277
  registerCommand(
9364
10278
  "session.stop",
9365
- z8.object({
9366
- sessionId: z8.string()
10279
+ z10.object({
10280
+ sessionId: z10.string()
9367
10281
  }),
9368
10282
  async (args, ctx) => {
9369
10283
  await ctx.sessionMgr.stop(args.sessionId);
@@ -9371,8 +10285,8 @@ var init_session = __esm({
9371
10285
  );
9372
10286
  registerCommand(
9373
10287
  "session.remove",
9374
- z8.object({
9375
- sessionId: z8.string()
10288
+ z10.object({
10289
+ sessionId: z10.string()
9376
10290
  }),
9377
10291
  async (args, ctx) => {
9378
10292
  const session = ctx.sessionMgr.get(args.sessionId);
@@ -9390,9 +10304,9 @@ var init_session = __esm({
9390
10304
 
9391
10305
  // packages/server/src/fs/tree.ts
9392
10306
  import { readdir as readdir3, stat as stat6 } from "fs/promises";
9393
- import { join as join7, relative as relative4 } from "path";
10307
+ import { join as join6, relative as relative4 } from "path";
9394
10308
  async function readTree(rootPath, subdir) {
9395
- const targetPath = subdir ? join7(rootPath, subdir) : rootPath;
10309
+ const targetPath = subdir ? join6(rootPath, subdir) : rootPath;
9396
10310
  const filter = createGitignoreFilter(rootPath, targetPath);
9397
10311
  const entries = await readdir3(targetPath, { withFileTypes: true });
9398
10312
  const nodes = [];
@@ -9400,7 +10314,7 @@ async function readTree(rootPath, subdir) {
9400
10314
  if (!filter(entry.name)) {
9401
10315
  continue;
9402
10316
  }
9403
- const fullPath = join7(targetPath, entry.name);
10317
+ const fullPath = join6(targetPath, entry.name);
9404
10318
  const relPath = relative4(rootPath, fullPath);
9405
10319
  if (entry.isDirectory()) {
9406
10320
  nodes.push({
@@ -9444,7 +10358,7 @@ async function searchFiles(rootPath, query, limit = 10) {
9444
10358
  const filteredEntries = entries.filter((entry) => filter(entry.name));
9445
10359
  filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
9446
10360
  for (const entry of filteredEntries) {
9447
- const fullPath = join7(dirPath, entry.name);
10361
+ const fullPath = join6(dirPath, entry.name);
9448
10362
  const relPath = relative4(rootPath, fullPath);
9449
10363
  if (entry.isDirectory()) {
9450
10364
  await walk(fullPath);
@@ -9537,7 +10451,7 @@ var init_tree = __esm({
9537
10451
  });
9538
10452
 
9539
10453
  // packages/server/src/commands/file.ts
9540
- import { z as z9 } from "zod";
10454
+ import { z as z11 } from "zod";
9541
10455
  var init_file = __esm({
9542
10456
  "packages/server/src/commands/file.ts"() {
9543
10457
  "use strict";
@@ -9546,9 +10460,9 @@ var init_file = __esm({
9546
10460
  init_dispatch();
9547
10461
  registerCommand(
9548
10462
  "file.readTree",
9549
- z9.object({
9550
- workspaceId: z9.string(),
9551
- subPath: z9.string().optional()
10463
+ z11.object({
10464
+ workspaceId: z11.string(),
10465
+ subPath: z11.string().optional()
9552
10466
  }),
9553
10467
  async (args, ctx) => {
9554
10468
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9560,10 +10474,10 @@ var init_file = __esm({
9560
10474
  );
9561
10475
  registerCommand(
9562
10476
  "file.search",
9563
- z9.object({
9564
- workspaceId: z9.string(),
9565
- query: z9.string(),
9566
- limit: z9.number().int().positive().max(50).optional()
10477
+ z11.object({
10478
+ workspaceId: z11.string(),
10479
+ query: z11.string(),
10480
+ limit: z11.number().int().positive().max(50).optional()
9567
10481
  }),
9568
10482
  async (args, ctx) => {
9569
10483
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9575,9 +10489,9 @@ var init_file = __esm({
9575
10489
  );
9576
10490
  registerCommand(
9577
10491
  "file.read",
9578
- z9.object({
9579
- workspaceId: z9.string(),
9580
- path: z9.string()
10492
+ z11.object({
10493
+ workspaceId: z11.string(),
10494
+ path: z11.string()
9581
10495
  }),
9582
10496
  async (args, ctx) => {
9583
10497
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9589,9 +10503,9 @@ var init_file = __esm({
9589
10503
  );
9590
10504
  registerCommand(
9591
10505
  "file.create",
9592
- z9.object({
9593
- workspaceId: z9.string(),
9594
- path: z9.string()
10506
+ z11.object({
10507
+ workspaceId: z11.string(),
10508
+ path: z11.string()
9595
10509
  }),
9596
10510
  async (args, ctx) => {
9597
10511
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9609,9 +10523,9 @@ var init_file = __esm({
9609
10523
  );
9610
10524
  registerCommand(
9611
10525
  "file.mkdir",
9612
- z9.object({
9613
- workspaceId: z9.string(),
9614
- path: z9.string()
10526
+ z11.object({
10527
+ workspaceId: z11.string(),
10528
+ path: z11.string()
9615
10529
  }),
9616
10530
  async (args, ctx) => {
9617
10531
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9629,9 +10543,9 @@ var init_file = __esm({
9629
10543
  );
9630
10544
  registerCommand(
9631
10545
  "file.delete",
9632
- z9.object({
9633
- workspaceId: z9.string(),
9634
- path: z9.string()
10546
+ z11.object({
10547
+ workspaceId: z11.string(),
10548
+ path: z11.string()
9635
10549
  }),
9636
10550
  async (args, ctx) => {
9637
10551
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9649,11 +10563,11 @@ var init_file = __esm({
9649
10563
  );
9650
10564
  registerCommand(
9651
10565
  "file.write",
9652
- z9.object({
9653
- workspaceId: z9.string(),
9654
- path: z9.string(),
9655
- content: z9.string(),
9656
- baseHash: z9.string().optional()
10566
+ z11.object({
10567
+ workspaceId: z11.string(),
10568
+ path: z11.string(),
10569
+ content: z11.string(),
10570
+ baseHash: z11.string().optional()
9657
10571
  // For conflict detection
9658
10572
  }),
9659
10573
  async (args, ctx) => {
@@ -9744,7 +10658,7 @@ var init_git_events = __esm({
9744
10658
  });
9745
10659
 
9746
10660
  // packages/server/src/commands/git.ts
9747
- import { z as z10 } from "zod";
10661
+ import { z as z12 } from "zod";
9748
10662
  async function runGitNetworkOperation(ctx, workspaceId, op) {
9749
10663
  if (!ctx.autoFetch?.runExclusive) {
9750
10664
  return op();
@@ -9759,16 +10673,16 @@ var init_git2 = __esm({
9759
10673
  init_diff();
9760
10674
  init_dispatch();
9761
10675
  init_git_events();
9762
- gitHttpAuthSchema = z10.object({
9763
- username: z10.string(),
9764
- password: z10.string()
10676
+ gitHttpAuthSchema = z12.object({
10677
+ username: z12.string(),
10678
+ password: z12.string()
9765
10679
  });
9766
- gitCommitRevisionSchema = z10.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
10680
+ gitCommitRevisionSchema = z12.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
9767
10681
  GIT_BACKGROUND_FETCH_TIMEOUT_MS = 30 * 1e3;
9768
10682
  registerCommand(
9769
10683
  "git.status",
9770
- z10.object({
9771
- workspaceId: z10.string()
10684
+ z12.object({
10685
+ workspaceId: z12.string()
9772
10686
  }),
9773
10687
  async (args, ctx) => {
9774
10688
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9780,9 +10694,9 @@ var init_git2 = __esm({
9780
10694
  );
9781
10695
  registerCommand(
9782
10696
  "git.stage",
9783
- z10.object({
9784
- workspaceId: z10.string(),
9785
- paths: z10.array(z10.string())
10697
+ z12.object({
10698
+ workspaceId: z12.string(),
10699
+ paths: z12.array(z12.string())
9786
10700
  }),
9787
10701
  async (args, ctx) => {
9788
10702
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9796,10 +10710,10 @@ var init_git2 = __esm({
9796
10710
  );
9797
10711
  registerCommand(
9798
10712
  "git.diff",
9799
- z10.object({
9800
- workspaceId: z10.string(),
9801
- path: z10.string(),
9802
- staged: z10.boolean().optional()
10713
+ z12.object({
10714
+ workspaceId: z12.string(),
10715
+ path: z12.string(),
10716
+ staged: z12.boolean().optional()
9803
10717
  }),
9804
10718
  async (args, ctx) => {
9805
10719
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9813,9 +10727,9 @@ var init_git2 = __esm({
9813
10727
  );
9814
10728
  registerCommand(
9815
10729
  "git.log",
9816
- z10.object({
9817
- workspaceId: z10.string(),
9818
- limit: z10.number().int().min(1).max(50).optional()
10730
+ z12.object({
10731
+ workspaceId: z12.string(),
10732
+ limit: z12.number().int().min(1).max(50).optional()
9819
10733
  }),
9820
10734
  async (args, ctx) => {
9821
10735
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9829,8 +10743,8 @@ var init_git2 = __esm({
9829
10743
  );
9830
10744
  registerCommand(
9831
10745
  "git.show",
9832
- z10.object({
9833
- workspaceId: z10.string(),
10746
+ z12.object({
10747
+ workspaceId: z12.string(),
9834
10748
  sha: gitCommitRevisionSchema
9835
10749
  }),
9836
10750
  async (args, ctx) => {
@@ -9845,9 +10759,9 @@ var init_git2 = __esm({
9845
10759
  );
9846
10760
  registerCommand(
9847
10761
  "git.unstage",
9848
- z10.object({
9849
- workspaceId: z10.string(),
9850
- paths: z10.array(z10.string())
10762
+ z12.object({
10763
+ workspaceId: z12.string(),
10764
+ paths: z12.array(z12.string())
9851
10765
  }),
9852
10766
  async (args, ctx) => {
9853
10767
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9861,9 +10775,9 @@ var init_git2 = __esm({
9861
10775
  );
9862
10776
  registerCommand(
9863
10777
  "git.discard",
9864
- z10.object({
9865
- workspaceId: z10.string(),
9866
- paths: z10.array(z10.string())
10778
+ z12.object({
10779
+ workspaceId: z12.string(),
10780
+ paths: z12.array(z12.string())
9867
10781
  }),
9868
10782
  async (args, ctx) => {
9869
10783
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9879,9 +10793,9 @@ var init_git2 = __esm({
9879
10793
  );
9880
10794
  registerCommand(
9881
10795
  "git.commit",
9882
- z10.object({
9883
- workspaceId: z10.string(),
9884
- message: z10.string()
10796
+ z12.object({
10797
+ workspaceId: z12.string(),
10798
+ message: z12.string()
9885
10799
  }),
9886
10800
  async (args, ctx) => {
9887
10801
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9898,11 +10812,11 @@ var init_git2 = __esm({
9898
10812
  );
9899
10813
  registerCommand(
9900
10814
  "git.push",
9901
- z10.object({
9902
- workspaceId: z10.string(),
9903
- remote: z10.string().optional(),
9904
- branch: z10.string().optional(),
9905
- force: z10.boolean().optional(),
10815
+ z12.object({
10816
+ workspaceId: z12.string(),
10817
+ remote: z12.string().optional(),
10818
+ branch: z12.string().optional(),
10819
+ force: z12.boolean().optional(),
9906
10820
  auth: gitHttpAuthSchema.optional()
9907
10821
  }),
9908
10822
  async (args, ctx) => {
@@ -9929,10 +10843,10 @@ var init_git2 = __esm({
9929
10843
  );
9930
10844
  registerCommand(
9931
10845
  "git.pull",
9932
- z10.object({
9933
- workspaceId: z10.string(),
9934
- remote: z10.string().optional(),
9935
- branch: z10.string().optional(),
10846
+ z12.object({
10847
+ workspaceId: z12.string(),
10848
+ remote: z12.string().optional(),
10849
+ branch: z12.string().optional(),
9936
10850
  auth: gitHttpAuthSchema.optional()
9937
10851
  }),
9938
10852
  async (args, ctx) => {
@@ -9960,12 +10874,12 @@ var init_git2 = __esm({
9960
10874
  );
9961
10875
  registerCommand(
9962
10876
  "git.fetch",
9963
- z10.object({
9964
- workspaceId: z10.string(),
9965
- remote: z10.string().optional(),
9966
- prune: z10.boolean().optional(),
10877
+ z12.object({
10878
+ workspaceId: z12.string(),
10879
+ remote: z12.string().optional(),
10880
+ prune: z12.boolean().optional(),
9967
10881
  auth: gitHttpAuthSchema.optional(),
9968
- background: z10.boolean().optional()
10882
+ background: z12.boolean().optional()
9969
10883
  }),
9970
10884
  async (args, ctx, clientId) => {
9971
10885
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -9994,10 +10908,10 @@ var init_git2 = __esm({
9994
10908
  );
9995
10909
  registerCommand(
9996
10910
  "git.checkout",
9997
- z10.object({
9998
- workspaceId: z10.string(),
9999
- ref: z10.string(),
10000
- createBranch: z10.boolean().optional()
10911
+ z12.object({
10912
+ workspaceId: z12.string(),
10913
+ ref: z12.string(),
10914
+ createBranch: z12.boolean().optional()
10001
10915
  }),
10002
10916
  async (args, ctx) => {
10003
10917
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -10019,10 +10933,10 @@ var init_git2 = __esm({
10019
10933
  );
10020
10934
  registerCommand(
10021
10935
  "git.branch",
10022
- z10.object({
10023
- workspaceId: z10.string(),
10024
- name: z10.string(),
10025
- startPoint: z10.string().optional()
10936
+ z12.object({
10937
+ workspaceId: z12.string(),
10938
+ name: z12.string(),
10939
+ startPoint: z12.string().optional()
10026
10940
  }),
10027
10941
  async (args, ctx) => {
10028
10942
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -10041,8 +10955,8 @@ var init_git2 = __esm({
10041
10955
  );
10042
10956
  registerCommand(
10043
10957
  "git.branches",
10044
- z10.object({
10045
- workspaceId: z10.string()
10958
+ z12.object({
10959
+ workspaceId: z12.string()
10046
10960
  }),
10047
10961
  async (args, ctx) => {
10048
10962
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -10056,37 +10970,37 @@ var init_git2 = __esm({
10056
10970
  });
10057
10971
 
10058
10972
  // packages/server/src/config/config-io.ts
10059
- import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync4 } from "node:fs";
10060
- import { homedir as homedir4 } from "node:os";
10061
- import { basename as basename3, dirname as dirname5, join as join8 } from "node:path";
10973
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
10974
+ import { homedir as homedir3 } from "node:os";
10975
+ import { basename as basename2, dirname as dirname4, join as join7 } from "node:path";
10062
10976
  function resolveConfigPath(configType) {
10063
10977
  if (configType === "codex") {
10064
10978
  const testHome = process.env.CODER_STUDIO_CODEX_HOME;
10065
10979
  if (testHome && testHome.trim()) {
10066
- return join8(testHome, "config.toml");
10980
+ return join7(testHome, "config.toml");
10067
10981
  }
10068
10982
  const codexHome = process.env.CODEX_HOME;
10069
10983
  if (codexHome && codexHome.trim()) {
10070
- return join8(codexHome, "config.toml");
10984
+ return join7(codexHome, "config.toml");
10071
10985
  }
10072
- return join8(homedir4(), ".codex", "config.toml");
10986
+ return join7(homedir3(), ".codex", "config.toml");
10073
10987
  }
10074
10988
  if (configType === "claude") {
10075
10989
  const testHome = process.env.CODER_STUDIO_CLAUDE_HOME;
10076
10990
  if (testHome && testHome.trim()) {
10077
- return join8(testHome, "settings.json");
10991
+ return join7(testHome, "settings.json");
10078
10992
  }
10079
- return join8(homedir4(), ".claude", "settings.json");
10993
+ return join7(homedir3(), ".claude", "settings.json");
10080
10994
  }
10081
10995
  throw new Error(`Unknown config type: ${configType}`);
10082
10996
  }
10083
10997
  function readConfigFile(configType) {
10084
10998
  const configPath = resolveConfigPath(configType);
10085
- if (!existsSync9(configPath)) {
10999
+ if (!existsSync6(configPath)) {
10086
11000
  return { configPath, content: "", exists: false };
10087
11001
  }
10088
11002
  try {
10089
- const content = readFileSync8(configPath, "utf-8");
11003
+ const content = readFileSync6(configPath, "utf-8");
10090
11004
  return { configPath, content, exists: true };
10091
11005
  } catch {
10092
11006
  return { configPath, content: "", exists: false };
@@ -10095,16 +11009,16 @@ function readConfigFile(configType) {
10095
11009
  function writeConfigFile(configType, content) {
10096
11010
  try {
10097
11011
  const configPath = resolveConfigPath(configType);
10098
- const parentDir = dirname5(configPath);
10099
- if (!existsSync9(parentDir)) {
10100
- mkdirSync4(parentDir, { recursive: true });
11012
+ const parentDir = dirname4(configPath);
11013
+ if (!existsSync6(parentDir)) {
11014
+ mkdirSync3(parentDir, { recursive: true });
10101
11015
  }
10102
11016
  let backupPath = null;
10103
- if (existsSync9(configPath)) {
11017
+ if (existsSync6(configPath)) {
10104
11018
  backupPath = createBackup(configPath);
10105
11019
  }
10106
11020
  const tempPath = `${configPath}.tmp`;
10107
- writeFileSync4(tempPath, content, "utf-8");
11021
+ writeFileSync3(tempPath, content, "utf-8");
10108
11022
  renameSync(tempPath, configPath);
10109
11023
  return { success: true, backupPath };
10110
11024
  } catch (error) {
@@ -10116,13 +11030,13 @@ function writeConfigFile(configType, content) {
10116
11030
  }
10117
11031
  }
10118
11032
  function createBackup(filePath) {
10119
- const original = readFileSync8(filePath, "utf-8");
11033
+ const original = readFileSync6(filePath, "utf-8");
10120
11034
  const ext = filePath.split(".").pop() ?? "";
10121
- const base = basename3(filePath, `.${ext}`);
10122
- const dir = dirname5(filePath);
11035
+ const base = basename2(filePath, `.${ext}`);
11036
+ const dir = dirname4(filePath);
10123
11037
  const ts = formatTimestamp(/* @__PURE__ */ new Date());
10124
- const backupPath = join8(dir, `${base}.bak.${ts}.${ext}`);
10125
- writeFileSync4(backupPath, original, "utf-8");
11038
+ const backupPath = join7(dir, `${base}.bak.${ts}.${ext}`);
11039
+ writeFileSync3(backupPath, original, "utf-8");
10126
11040
  return backupPath;
10127
11041
  }
10128
11042
  function formatTimestamp(d) {
@@ -10136,7 +11050,7 @@ var init_config_io = __esm({
10136
11050
  });
10137
11051
 
10138
11052
  // packages/server/src/commands/settings.ts
10139
- import { z as z11 } from "zod";
11053
+ import { z as z13 } from "zod";
10140
11054
  function flattenSettings(obj, prefix = "") {
10141
11055
  const result = {};
10142
11056
  for (const [key, value] of Object.entries(obj)) {
@@ -10159,27 +11073,34 @@ var init_settings2 = __esm({
10159
11073
  init_provider_config_repo();
10160
11074
  init_settings();
10161
11075
  init_dispatch();
10162
- SettingsSchema = z11.object({
10163
- defaultProviderId: z11.string().optional(),
10164
- notifications: z11.object({
10165
- enabled: z11.boolean().optional(),
10166
- soundEnabled: z11.boolean().optional(),
11076
+ SettingsSchema = z13.object({
11077
+ defaultProviderId: z13.string().optional(),
11078
+ notifications: z13.object({
11079
+ enabled: z13.boolean().optional(),
11080
+ soundEnabled: z13.boolean().optional(),
10167
11081
  // Legacy field — accepted for backward compat with older clients but
10168
11082
  // no longer surfaced in the UI. The web client now picks the channel
10169
11083
  // automatically based on workspace focus + page visibility.
10170
- onlyWhenBackgrounded: z11.boolean().optional()
11084
+ onlyWhenBackgrounded: z13.boolean().optional()
10171
11085
  }).optional(),
10172
- supervisor: z11.object({
10173
- evaluationTimeoutSec: z11.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional()
11086
+ supervisor: z13.object({
11087
+ evaluationTimeoutSec: z13.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional(),
11088
+ retryEnabled: z13.boolean().optional(),
11089
+ retryMaxCount: z13.number().int().min(0).max(MAX_SUPERVISOR_RETRY_MAX_COUNT).optional(),
11090
+ retryDelaySec: z13.number().int().min(1).max(MAX_SUPERVISOR_RETRY_DELAY_SEC).optional(),
11091
+ retryOnTimeout: z13.boolean().optional(),
11092
+ retryOnEvaluatorError: z13.boolean().optional()
10174
11093
  }).optional(),
10175
- appearance: z11.object({
10176
- theme: z11.enum(["dark"]).optional(),
10177
- terminalRenderer: z11.enum(["standard", "compatibility"]).optional(),
10178
- locale: z11.enum(["zh", "en"]).optional()
11094
+ appearance: z13.object({
11095
+ theme: z13.enum(["dark", "light"]).optional(),
11096
+ themeId: z13.string().optional(),
11097
+ terminalRenderer: z13.enum(["standard", "compatibility"]).optional(),
11098
+ terminalCopyOnSelect: z13.boolean().optional(),
11099
+ locale: z13.enum(["zh", "en"]).optional()
10179
11100
  }).optional(),
10180
11101
  providers: ProviderSettingsSchema.optional()
10181
11102
  });
10182
- registerCommand("settings.get", z11.object({}), async (_args, ctx) => {
11103
+ registerCommand("settings.get", z13.object({}), async (_args, ctx) => {
10183
11104
  const row = ctx.db.prepare("SELECT key, value FROM user_settings").all();
10184
11105
  const settings = {};
10185
11106
  for (const { key, value } of row) {
@@ -10208,11 +11129,36 @@ var init_settings2 = __esm({
10208
11129
  settings[SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY]
10209
11130
  );
10210
11131
  }
11132
+ if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_ENABLED_SETTING_KEY)) {
11133
+ settings[SUPERVISOR_RETRY_ENABLED_SETTING_KEY] = resolveSupervisorRetryEnabled(
11134
+ settings[SUPERVISOR_RETRY_ENABLED_SETTING_KEY]
11135
+ );
11136
+ }
11137
+ if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY)) {
11138
+ settings[SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY] = resolveSupervisorRetryMaxCount(
11139
+ settings[SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY]
11140
+ );
11141
+ }
11142
+ if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY)) {
11143
+ settings[SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY] = resolveSupervisorRetryDelaySec(
11144
+ settings[SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY]
11145
+ );
11146
+ }
11147
+ if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY)) {
11148
+ settings[SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY] = resolveSupervisorRetryOnTimeout(
11149
+ settings[SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY]
11150
+ );
11151
+ }
11152
+ if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY)) {
11153
+ settings[SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY] = resolveSupervisorRetryOnEvaluatorError(
11154
+ settings[SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY]
11155
+ );
11156
+ }
10211
11157
  return settings;
10212
11158
  });
10213
11159
  registerCommand(
10214
11160
  "settings.update",
10215
- z11.object({
11161
+ z13.object({
10216
11162
  settings: SettingsSchema
10217
11163
  }),
10218
11164
  async (args, ctx) => {
@@ -10244,10 +11190,10 @@ var init_settings2 = __esm({
10244
11190
  );
10245
11191
  registerCommand(
10246
11192
  "settings.previewCommand",
10247
- z11.object({
10248
- providerId: z11.string(),
11193
+ z13.object({
11194
+ providerId: z13.string(),
10249
11195
  config: ProviderLaunchConfigInputSchema,
10250
- workspacePath: z11.string().optional()
11196
+ workspacePath: z13.string().optional()
10251
11197
  }),
10252
11198
  async (args, ctx) => {
10253
11199
  const provider = ctx.providerRegistry.find((item) => item.id === args.providerId);
@@ -10268,8 +11214,8 @@ var init_settings2 = __esm({
10268
11214
  );
10269
11215
  registerCommand(
10270
11216
  "settings.readConfigFile",
10271
- z11.object({
10272
- configType: z11.enum(["codex", "claude"])
11217
+ z13.object({
11218
+ configType: z13.enum(["codex", "claude"])
10273
11219
  }),
10274
11220
  async (args) => {
10275
11221
  const result = readConfigFile(args.configType);
@@ -10278,9 +11224,9 @@ var init_settings2 = __esm({
10278
11224
  );
10279
11225
  registerCommand(
10280
11226
  "settings.writeConfigFile",
10281
- z11.object({
10282
- configType: z11.enum(["codex", "claude"]),
10283
- content: z11.string()
11227
+ z13.object({
11228
+ configType: z13.enum(["codex", "claude"]),
11229
+ content: z13.string()
10284
11230
  }),
10285
11231
  async (args) => {
10286
11232
  const result = writeConfigFile(args.configType, args.content);
@@ -10291,19 +11237,19 @@ var init_settings2 = __esm({
10291
11237
  });
10292
11238
 
10293
11239
  // packages/server/src/commands/provider.ts
10294
- import { z as z12 } from "zod";
11240
+ import { z as z14 } from "zod";
10295
11241
  var init_provider = __esm({
10296
11242
  "packages/server/src/commands/provider.ts"() {
10297
11243
  "use strict";
10298
11244
  init_runtime_status();
10299
11245
  init_dispatch();
10300
- registerCommand("provider.runtimeStatus", z12.object({}), async (_args, ctx) => {
11246
+ registerCommand("provider.runtimeStatus", z14.object({}), async (_args, ctx) => {
10301
11247
  return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
10302
11248
  });
10303
11249
  registerCommand(
10304
11250
  "provider.install.start",
10305
- z12.object({
10306
- providerId: z12.string()
11251
+ z14.object({
11252
+ providerId: z14.string()
10307
11253
  }),
10308
11254
  async (args, ctx) => {
10309
11255
  if (!ctx.providerInstallMgr) {
@@ -10317,8 +11263,8 @@ var init_provider = __esm({
10317
11263
  );
10318
11264
  registerCommand(
10319
11265
  "provider.install.get",
10320
- z12.object({
10321
- jobId: z12.string()
11266
+ z14.object({
11267
+ jobId: z14.string()
10322
11268
  }),
10323
11269
  async (args, ctx) => {
10324
11270
  if (!ctx.providerInstallMgr) {
@@ -10341,36 +11287,45 @@ var init_provider = __esm({
10341
11287
  });
10342
11288
 
10343
11289
  // packages/server/src/commands/supervisor.ts
10344
- import { z as z13 } from "zod";
11290
+ import { z as z15 } from "zod";
10345
11291
  var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, supervisorIdSchema;
10346
11292
  var init_supervisor2 = __esm({
10347
11293
  "packages/server/src/commands/supervisor.ts"() {
10348
11294
  "use strict";
10349
11295
  init_dispatch();
10350
- supervisorObjectiveSchema = z13.string().trim().min(1).max(4e3);
10351
- createSupervisorSchema = z13.object({
10352
- sessionId: z13.string(),
10353
- workspaceId: z13.string(),
11296
+ supervisorObjectiveSchema = z15.string().trim().min(1).max(4e3);
11297
+ createSupervisorSchema = z15.object({
11298
+ sessionId: z15.string(),
11299
+ workspaceId: z15.string(),
10354
11300
  objective: supervisorObjectiveSchema,
10355
- evaluatorProviderId: z13.string()
11301
+ evaluatorProviderId: z15.string(),
11302
+ evaluatorModel: z15.string().trim().min(1).max(200).optional(),
11303
+ maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
11304
+ scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
10356
11305
  }).strict();
10357
- updateSupervisorSchema = z13.object({
10358
- id: z13.string(),
11306
+ updateSupervisorSchema = z15.object({
11307
+ id: z15.string(),
10359
11308
  objective: supervisorObjectiveSchema.optional(),
10360
- evaluatorProviderId: z13.string().optional()
11309
+ evaluatorProviderId: z15.string().optional(),
11310
+ evaluatorModel: z15.string().trim().min(1).max(200).nullable().optional(),
11311
+ maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
11312
+ scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
10361
11313
  }).strict().refine(
10362
- (input) => input.objective !== void 0 || input.evaluatorProviderId !== void 0,
10363
- "objective or evaluatorProviderId is required"
11314
+ (input) => input.objective !== void 0 || input.evaluatorProviderId !== void 0 || input.evaluatorModel !== void 0 || input.maxSupervisionCount !== void 0 || input.scheduledAt !== void 0,
11315
+ "at least one supervisor field is required"
10364
11316
  );
10365
- sessionIdSchema = z13.object({ sessionId: z13.string() });
10366
- supervisorIdSchema = z13.object({ id: z13.string() });
11317
+ sessionIdSchema = z15.object({ sessionId: z15.string() });
11318
+ supervisorIdSchema = z15.object({ id: z15.string() });
10367
11319
  registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
10368
11320
  return {
10369
11321
  supervisor: await ctx.supervisorMgr.create({
10370
11322
  sessionId: args.sessionId,
10371
11323
  workspaceId: args.workspaceId,
10372
11324
  objective: args.objective,
10373
- evaluatorProviderId: args.evaluatorProviderId
11325
+ evaluatorProviderId: args.evaluatorProviderId,
11326
+ evaluatorModel: args.evaluatorModel,
11327
+ maxSupervisionCount: args.maxSupervisionCount,
11328
+ scheduledAt: args.scheduledAt
10374
11329
  })
10375
11330
  };
10376
11331
  });
@@ -10381,7 +11336,10 @@ var init_supervisor2 = __esm({
10381
11336
  return {
10382
11337
  supervisor: await ctx.supervisorMgr.update(args.id, {
10383
11338
  objective: args.objective,
10384
- evaluatorProviderId: args.evaluatorProviderId
11339
+ evaluatorProviderId: args.evaluatorProviderId,
11340
+ evaluatorModel: args.evaluatorModel,
11341
+ maxSupervisionCount: args.maxSupervisionCount,
11342
+ scheduledAt: args.scheduledAt
10385
11343
  })
10386
11344
  };
10387
11345
  });
@@ -10541,7 +11499,7 @@ var init_worktree = __esm({
10541
11499
 
10542
11500
  // packages/server/src/commands/worktree.ts
10543
11501
  import path9 from "node:path";
10544
- import { z as z14 } from "zod";
11502
+ import { z as z16 } from "zod";
10545
11503
  async function findRelatedWorkspaceIds(ctx, workspacePath) {
10546
11504
  const targetCommonDir = await getGitCommonDirPath(workspacePath);
10547
11505
  const relatedWorkspaceIds = await Promise.all(
@@ -10574,7 +11532,7 @@ var init_worktree2 = __esm({
10574
11532
  init_worktree();
10575
11533
  init_dispatch();
10576
11534
  init_git_events();
10577
- registerCommand("worktree.list", z14.object({ workspaceId: z14.string() }), async (args, ctx) => {
11535
+ registerCommand("worktree.list", z16.object({ workspaceId: z16.string() }), async (args, ctx) => {
10578
11536
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
10579
11537
  if (!workspace) {
10580
11538
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
@@ -10583,7 +11541,7 @@ var init_worktree2 = __esm({
10583
11541
  });
10584
11542
  registerCommand(
10585
11543
  "worktree.status",
10586
- z14.object({ workspaceId: z14.string(), worktreePath: z14.string() }),
11544
+ z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
10587
11545
  async (args, ctx) => {
10588
11546
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
10589
11547
  if (!workspace) {
@@ -10595,10 +11553,10 @@ var init_worktree2 = __esm({
10595
11553
  );
10596
11554
  registerCommand(
10597
11555
  "worktree.diff",
10598
- z14.object({
10599
- workspaceId: z14.string(),
10600
- worktreePath: z14.string(),
10601
- staged: z14.boolean().optional().default(false)
11556
+ z16.object({
11557
+ workspaceId: z16.string(),
11558
+ worktreePath: z16.string(),
11559
+ staged: z16.boolean().optional().default(false)
10602
11560
  }),
10603
11561
  async (args, ctx) => {
10604
11562
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -10611,7 +11569,7 @@ var init_worktree2 = __esm({
10611
11569
  );
10612
11570
  registerCommand(
10613
11571
  "worktree.tree",
10614
- z14.object({ workspaceId: z14.string(), worktreePath: z14.string() }),
11572
+ z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
10615
11573
  async (args, ctx) => {
10616
11574
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
10617
11575
  if (!workspace) {
@@ -10623,10 +11581,10 @@ var init_worktree2 = __esm({
10623
11581
  );
10624
11582
  registerCommand(
10625
11583
  "worktree.create",
10626
- z14.object({
10627
- workspaceId: z14.string(),
10628
- branch: z14.string(),
10629
- path: z14.string()
11584
+ z16.object({
11585
+ workspaceId: z16.string(),
11586
+ branch: z16.string(),
11587
+ path: z16.string()
10630
11588
  }),
10631
11589
  async (args, ctx) => {
10632
11590
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -10641,10 +11599,10 @@ var init_worktree2 = __esm({
10641
11599
  );
10642
11600
  registerCommand(
10643
11601
  "worktree.remove",
10644
- z14.object({
10645
- workspaceId: z14.string(),
10646
- worktreePath: z14.string(),
10647
- force: z14.boolean().optional().default(false)
11602
+ z16.object({
11603
+ workspaceId: z16.string(),
11604
+ worktreePath: z16.string(),
11605
+ force: z16.boolean().optional().default(false)
10648
11606
  }),
10649
11607
  async (args, ctx) => {
10650
11608
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -10668,7 +11626,7 @@ var init_worktree2 = __esm({
10668
11626
  });
10669
11627
 
10670
11628
  // packages/server/src/commands/fencing.ts
10671
- import { z as z15 } from "zod";
11629
+ import { z as z17 } from "zod";
10672
11630
  function createMockFencingRequest() {
10673
11631
  return {
10674
11632
  ip: "127.0.0.1",
@@ -10681,9 +11639,9 @@ var init_fencing2 = __esm({
10681
11639
  init_dispatch();
10682
11640
  registerCommand(
10683
11641
  "fencing.request",
10684
- z15.object({
10685
- workspaceId: z15.string(),
10686
- tabId: z15.string()
11642
+ z17.object({
11643
+ workspaceId: z17.string(),
11644
+ tabId: z17.string()
10687
11645
  }),
10688
11646
  async (args, ctx, clientId) => {
10689
11647
  return ctx.fencingMgr.requestControl(
@@ -10696,7 +11654,7 @@ var init_fencing2 = __esm({
10696
11654
  );
10697
11655
  registerCommand(
10698
11656
  "fencing.heartbeat",
10699
- z15.object({ workspaceId: z15.string() }),
11657
+ z17.object({ workspaceId: z17.string() }),
10700
11658
  async (args, ctx, clientId) => {
10701
11659
  const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
10702
11660
  return { success };
@@ -10704,13 +11662,13 @@ var init_fencing2 = __esm({
10704
11662
  );
10705
11663
  registerCommand(
10706
11664
  "fencing.release",
10707
- z15.object({ workspaceId: z15.string() }),
11665
+ z17.object({ workspaceId: z17.string() }),
10708
11666
  async (args, ctx, clientId) => {
10709
11667
  ctx.fencingMgr.release(args.workspaceId, clientId);
10710
11668
  return {};
10711
11669
  }
10712
11670
  );
10713
- registerCommand("fencing.status", z15.object({ workspaceId: z15.string() }), async (args, ctx) => {
11671
+ registerCommand("fencing.status", z17.object({ workspaceId: z17.string() }), async (args, ctx) => {
10714
11672
  const controller = ctx.fencingMgr.getController(args.workspaceId);
10715
11673
  const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
10716
11674
  return {
@@ -10721,9 +11679,9 @@ var init_fencing2 = __esm({
10721
11679
  });
10722
11680
  registerCommand(
10723
11681
  "fencing.takeover",
10724
- z15.object({
10725
- workspaceId: z15.string(),
10726
- tabId: z15.string()
11682
+ z17.object({
11683
+ workspaceId: z17.string(),
11684
+ tabId: z17.string()
10727
11685
  }),
10728
11686
  async (args, ctx, clientId) => {
10729
11687
  return ctx.fencingMgr.forceTakeover(
@@ -10743,6 +11701,8 @@ var init_commands = __esm({
10743
11701
  "use strict";
10744
11702
  init_workspace();
10745
11703
  init_workspace_activity();
11704
+ init_activation2();
11705
+ init_connection();
10746
11706
  init_session();
10747
11707
  init_terminal();
10748
11708
  init_file();
@@ -10761,6 +11721,7 @@ async function createServer(configOverrides) {
10761
11721
  ensureDataDir(config);
10762
11722
  const db = openDatabase(config.dataDir);
10763
11723
  const eventBus = new EventBus();
11724
+ const activationMgr = new ActivationManager();
10764
11725
  const fencingMgr = new FencingManager();
10765
11726
  const wsHub = new WsHub({ eventBus, commandContext: null, config, fencingMgr });
10766
11727
  let workspaceMgr;
@@ -10851,6 +11812,7 @@ async function createServer(configOverrides) {
10851
11812
  wsHub.setLogger(app.log);
10852
11813
  const supervisorRepo = new SupervisorRepo(db);
10853
11814
  const cycleRepo = new SupervisorCycleRepo(db);
11815
+ const cycleAttemptRepo = new SupervisorCycleAttemptRepo(db);
10854
11816
  supervisorMgr = new SupervisorManager({
10855
11817
  eventBus,
10856
11818
  broadcaster: wsHub,
@@ -10862,6 +11824,7 @@ async function createServer(configOverrides) {
10862
11824
  settingsRepo,
10863
11825
  supervisorRepo,
10864
11826
  cycleRepo,
11827
+ cycleAttemptRepo,
10865
11828
  logger: app.log
10866
11829
  });
10867
11830
  await sessionMgr.hydrate();
@@ -10886,7 +11849,8 @@ async function createServer(configOverrides) {
10886
11849
  supervisorMgr,
10887
11850
  autoFetch,
10888
11851
  providerRuntimeDeps,
10889
- providerInstallMgr
11852
+ providerInstallMgr,
11853
+ activationMgr
10890
11854
  };
10891
11855
  wsHub.setCommandContext(commandContext);
10892
11856
  await app.listen({
@@ -10911,11 +11875,16 @@ async function createServer(configOverrides) {
10911
11875
  );
10912
11876
  }, STARTUP_GC_DELAY_MS);
10913
11877
  gcTimer.unref();
11878
+ const wsKeepaliveTimer = setInterval(() => {
11879
+ wsHub.pingAll();
11880
+ }, WS_KEEPALIVE_INTERVAL_MS);
11881
+ wsKeepaliveTimer.unref();
10914
11882
  let stopped = false;
10915
11883
  const stopServer = async () => {
10916
11884
  if (stopped) return;
10917
11885
  stopped = true;
10918
11886
  clearTimeout(gcTimer);
11887
+ clearInterval(wsKeepaliveTimer);
10919
11888
  await app.close();
10920
11889
  autoFetch.stop();
10921
11890
  supervisorMgr.stop();
@@ -11031,6 +12000,7 @@ function createSessionDatabase(db) {
11031
12000
  }
11032
12001
  };
11033
12002
  }
12003
+ var WS_KEEPALIVE_INTERVAL_MS;
11034
12004
  var init_server = __esm({
11035
12005
  async "packages/server/src/server.ts"() {
11036
12006
  "use strict";
@@ -11051,6 +12021,7 @@ var init_server = __esm({
11051
12021
  init_provider_config_repo();
11052
12022
  init_session_repo();
11053
12023
  init_settings_repo();
12024
+ init_supervisor_cycle_attempt_repo();
11054
12025
  init_supervisor_cycle_repo();
11055
12026
  init_supervisor_repo();
11056
12027
  init_manager2();
@@ -11059,10 +12030,12 @@ var init_server = __esm({
11059
12030
  init_cleanup();
11060
12031
  init_constants();
11061
12032
  init_manager4();
12033
+ init_activation();
11062
12034
  init_dispatch();
11063
12035
  init_fencing();
11064
12036
  init_hub();
11065
12037
  init_commands();
12038
+ WS_KEEPALIVE_INTERVAL_MS = 15e3;
11066
12039
  if (isDirectExecution(import.meta.url)) {
11067
12040
  const server = await createServer();
11068
12041
  process.on("SIGINT", async () => {
@@ -11285,6 +12258,7 @@ var init_storage = __esm({
11285
12258
  init_provider_config_repo();
11286
12259
  init_session_repo();
11287
12260
  init_settings_repo();
12261
+ init_supervisor_cycle_attempt_repo();
11288
12262
  init_supervisor_cycle_repo();
11289
12263
  init_supervisor_repo();
11290
12264
  init_terminal_repo();
@@ -11315,6 +12289,7 @@ __export(src_exports, {
11315
12289
  RingBuffer: () => RingBuffer,
11316
12290
  SessionRepo: () => SessionRepo,
11317
12291
  SettingsRepo: () => SettingsRepo,
12292
+ SupervisorCycleAttemptRepo: () => SupervisorCycleAttemptRepo,
11318
12293
  SupervisorCycleRepo: () => SupervisorCycleRepo,
11319
12294
  SupervisorRepo: () => SupervisorRepo,
11320
12295
  TerminalManager: () => TerminalManager,
@@ -11349,22 +12324,25 @@ var init_src4 = __esm({
11349
12324
  });
11350
12325
 
11351
12326
  // packages/cli/src/server-runner.ts
12327
+ await init_src4();
12328
+ import { mkdirSync as mkdirSync5 } from "fs";
12329
+ import { dirname as dirname6 } from "path";
11352
12330
  import { fileURLToPath as fileURLToPath2 } from "url";
11353
12331
 
11354
12332
  // packages/cli/src/config-store.ts
11355
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
11356
- import { homedir } from "os";
11357
- import { basename, join } from "path";
12333
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
12334
+ import { homedir as homedir4 } from "os";
12335
+ import { basename as basename3, join as join8 } from "path";
11358
12336
  function getCliConfigPath() {
11359
- return join(homedir(), ".coder-studio", "config.json");
12337
+ return join8(homedir4(), ".coder-studio", "config.json");
11360
12338
  }
11361
12339
  function readCliConfig() {
11362
12340
  const path10 = getCliConfigPath();
11363
- if (!existsSync(path10)) {
12341
+ if (!existsSync7(path10)) {
11364
12342
  return null;
11365
12343
  }
11366
12344
  try {
11367
- const parsed = JSON.parse(readFileSync(path10, "utf-8"));
12345
+ const parsed = JSON.parse(readFileSync7(path10, "utf-8"));
11368
12346
  if (parsed.host !== void 0 && typeof parsed.host !== "string" || parsed.port !== void 0 && typeof parsed.port !== "number" || parsed.dataDir !== void 0 && typeof parsed.dataDir !== "string" || parsed.password !== void 0 && typeof parsed.password !== "string") {
11369
12347
  return null;
11370
12348
  }
@@ -11375,17 +12353,17 @@ function readCliConfig() {
11375
12353
  }
11376
12354
 
11377
12355
  // packages/cli/src/embed.ts
11378
- import { existsSync as existsSync2 } from "fs";
11379
- import { dirname, resolve } from "path";
12356
+ import { existsSync as existsSync8 } from "fs";
12357
+ import { dirname as dirname5, resolve as resolve3 } from "path";
11380
12358
  import { fileURLToPath } from "url";
11381
12359
  var __filename = fileURLToPath(import.meta.url);
11382
- var __dirname = dirname(__filename);
11383
- var WEB_ASSETS_DIR = resolve(__dirname, "../web");
12360
+ var __dirname = dirname5(__filename);
12361
+ var WEB_ASSETS_DIR = resolve3(__dirname, "../web");
11384
12362
  function getStaticAssetsDir() {
11385
12363
  return WEB_ASSETS_DIR;
11386
12364
  }
11387
12365
  function hasWebAssets() {
11388
- return existsSync2(WEB_ASSETS_DIR);
12366
+ return existsSync8(WEB_ASSETS_DIR);
11389
12367
  }
11390
12368
 
11391
12369
  // packages/cli/src/node-version.ts
@@ -11419,12 +12397,12 @@ function assertSupportedNodeVersion(version = process.versions.node) {
11419
12397
  }
11420
12398
 
11421
12399
  // packages/cli/src/package-manifest.ts
11422
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
12400
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
11423
12401
  function resolveCliPackageManifestUrl(importMetaUrl) {
11424
12402
  const manifestUrl = [
11425
12403
  new URL("../package.json", importMetaUrl),
11426
12404
  new URL("../../package.json", importMetaUrl)
11427
- ].find((candidate) => existsSync3(candidate));
12405
+ ].find((candidate) => existsSync9(candidate));
11428
12406
  if (!manifestUrl) {
11429
12407
  throw new Error("Unable to locate CLI package.json");
11430
12408
  }
@@ -11432,7 +12410,7 @@ function resolveCliPackageManifestUrl(importMetaUrl) {
11432
12410
  }
11433
12411
  function getCliPackageManifest(importMetaUrl) {
11434
12412
  return JSON.parse(
11435
- readFileSync2(resolveCliPackageManifestUrl(importMetaUrl), "utf-8")
12413
+ readFileSync8(resolveCliPackageManifestUrl(importMetaUrl), "utf-8")
11436
12414
  );
11437
12415
  }
11438
12416
  function getCliVersion(importMetaUrl) {
@@ -11464,6 +12442,14 @@ var buildServerConfig = () => {
11464
12442
  console.warn(MISSING_WEB_ASSETS_WARNING);
11465
12443
  return config;
11466
12444
  };
12445
+ var verifyLocalDatabaseCompatibility = () => {
12446
+ const config = parseServerConfig(buildServerConfig());
12447
+ if (config.dataDir !== ":memory:") {
12448
+ mkdirSync5(dirname6(config.dataDir), { recursive: true });
12449
+ }
12450
+ const db = openDatabase(config.dataDir);
12451
+ closeDatabase(db);
12452
+ };
11467
12453
  var createShutdownHandler = (server) => async () => {
11468
12454
  await server.stop();
11469
12455
  process.exit(0);
@@ -11498,6 +12484,7 @@ void runServerEntrypoint(import.meta.url, process.argv[1]);
11498
12484
  export {
11499
12485
  buildServerConfig,
11500
12486
  runServerEntrypoint,
11501
- startServer
12487
+ startServer,
12488
+ verifyLocalDatabaseCompatibility
11502
12489
  };
11503
12490
  //# sourceMappingURL=server-runner.mjs.map