@spencer-kit/coder-studio 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/esm/bin.mjs +1374 -316
- package/dist/esm/bin.mjs.map +4 -4
- package/dist/esm/migrations/001_init.sql +15 -1
- package/dist/esm/server-runner.mjs +1401 -390
- package/dist/esm/server-runner.mjs.map +4 -4
- package/dist/web/assets/index-CoNo6FuB.css +1 -0
- package/dist/web/assets/index-DdIyj_YE.js +111 -0
- package/dist/web/assets/index-DdIyj_YE.js.map +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/bin.test.ts +70 -0
- package/src/cli.ts +67 -3
- package/src/server-runner.test.ts +45 -2
- package/src/server-runner.ts +13 -0
- package/dist/web/assets/index-B3PO5hz_.js +0 -111
- package/dist/web/assets/index-B3PO5hz_.js.map +0 -1
- package/dist/web/assets/index-BbpuXQCm.css +0 -1
package/dist/esm/bin.mjs
CHANGED
|
@@ -615,6 +615,7 @@ var init_config_schema2 = __esm({
|
|
|
615
615
|
"packages/providers/src/codex/config-schema.ts"() {
|
|
616
616
|
"use strict";
|
|
617
617
|
codexConfigSchema = z2.object({
|
|
618
|
+
model: z2.string().min(1).optional(),
|
|
618
619
|
additionalArgs: z2.array(z2.string()).default([]),
|
|
619
620
|
envVars: z2.record(z2.string(), z2.string()).default({})
|
|
620
621
|
});
|
|
@@ -661,6 +662,7 @@ function buildCodexSupervisorEvalCommand(config, req) {
|
|
|
661
662
|
"-s",
|
|
662
663
|
"read-only",
|
|
663
664
|
"--skip-git-repo-check",
|
|
665
|
+
...req.model ? ["-m", req.model] : [],
|
|
664
666
|
...cfg.additionalArgs,
|
|
665
667
|
req.prompt
|
|
666
668
|
],
|
|
@@ -2727,12 +2729,46 @@ function resolveSupervisorEvaluationTimeoutSec(value) {
|
|
|
2727
2729
|
}
|
|
2728
2730
|
return value;
|
|
2729
2731
|
}
|
|
2730
|
-
|
|
2732
|
+
function resolveSupervisorRetryEnabled(value) {
|
|
2733
|
+
return typeof value === "boolean" ? value : DEFAULT_SUPERVISOR_RETRY_ENABLED;
|
|
2734
|
+
}
|
|
2735
|
+
function resolveSupervisorRetryMaxCount(value) {
|
|
2736
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isSafeInteger(value)) {
|
|
2737
|
+
return DEFAULT_SUPERVISOR_RETRY_MAX_COUNT;
|
|
2738
|
+
}
|
|
2739
|
+
if (value < 0 || value > MAX_SUPERVISOR_RETRY_MAX_COUNT) {
|
|
2740
|
+
return DEFAULT_SUPERVISOR_RETRY_MAX_COUNT;
|
|
2741
|
+
}
|
|
2742
|
+
return value;
|
|
2743
|
+
}
|
|
2744
|
+
function resolveSupervisorRetryDelaySec(value) {
|
|
2745
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isSafeInteger(value)) {
|
|
2746
|
+
return DEFAULT_SUPERVISOR_RETRY_DELAY_SEC;
|
|
2747
|
+
}
|
|
2748
|
+
if (value < 1 || value > MAX_SUPERVISOR_RETRY_DELAY_SEC) {
|
|
2749
|
+
return DEFAULT_SUPERVISOR_RETRY_DELAY_SEC;
|
|
2750
|
+
}
|
|
2751
|
+
return value;
|
|
2752
|
+
}
|
|
2753
|
+
function resolveSupervisorRetryOnTimeout(value) {
|
|
2754
|
+
return typeof value === "boolean" ? value : DEFAULT_SUPERVISOR_RETRY_ON_TIMEOUT;
|
|
2755
|
+
}
|
|
2756
|
+
function resolveSupervisorRetryOnEvaluatorError(value) {
|
|
2757
|
+
return typeof value === "boolean" ? value : DEFAULT_SUPERVISOR_RETRY_ON_EVALUATOR_ERROR;
|
|
2758
|
+
}
|
|
2759
|
+
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;
|
|
2731
2760
|
var init_supervisor = __esm({
|
|
2732
2761
|
"packages/core/src/domain/supervisor.ts"() {
|
|
2733
2762
|
"use strict";
|
|
2734
2763
|
DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC = 600;
|
|
2735
2764
|
MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC = 86400;
|
|
2765
|
+
DEFAULT_SUPERVISOR_RETRY_ENABLED = false;
|
|
2766
|
+
DEFAULT_SUPERVISOR_RETRY_MAX_COUNT = 0;
|
|
2767
|
+
MAX_SUPERVISOR_RETRY_MAX_COUNT = 20;
|
|
2768
|
+
DEFAULT_SUPERVISOR_RETRY_DELAY_SEC = 10;
|
|
2769
|
+
MAX_SUPERVISOR_RETRY_DELAY_SEC = 3600;
|
|
2770
|
+
DEFAULT_SUPERVISOR_RETRY_ON_TIMEOUT = true;
|
|
2771
|
+
DEFAULT_SUPERVISOR_RETRY_ON_EVALUATOR_ERROR = false;
|
|
2736
2772
|
DEFAULT_SUPERVISOR_CONFIG = {
|
|
2737
2773
|
maxCyclesPerSession: 100,
|
|
2738
2774
|
terminalLinesForEvaluation: 500,
|
|
@@ -3760,7 +3796,7 @@ var init_database = __esm({
|
|
|
3760
3796
|
}
|
|
3761
3797
|
});
|
|
3762
3798
|
|
|
3763
|
-
// packages/server/src/storage/
|
|
3799
|
+
// packages/server/src/storage/schema-version.ts
|
|
3764
3800
|
import { DatabaseSync } from "node:sqlite";
|
|
3765
3801
|
import { readFileSync as readFileSync4 } from "fs";
|
|
3766
3802
|
import { join as join3 } from "path";
|
|
@@ -3784,15 +3820,229 @@ function listSchemaEntries(db) {
|
|
|
3784
3820
|
sql: normalizeSql(row.sql)
|
|
3785
3821
|
}));
|
|
3786
3822
|
}
|
|
3787
|
-
function
|
|
3823
|
+
function schemaEntrySignature(entry) {
|
|
3824
|
+
return `${entry.type}:${entry.name}:${entry.tableName}:${entry.sql}`;
|
|
3825
|
+
}
|
|
3826
|
+
function buildSchemaEntries(schemaSql) {
|
|
3788
3827
|
const db = new DatabaseSync(":memory:");
|
|
3789
3828
|
try {
|
|
3790
|
-
db.exec(
|
|
3829
|
+
db.exec(schemaSql);
|
|
3791
3830
|
return listSchemaEntries(db);
|
|
3792
3831
|
} finally {
|
|
3793
3832
|
db.close();
|
|
3794
3833
|
}
|
|
3795
3834
|
}
|
|
3835
|
+
function hasExactFingerprint(actualEntries, expectedEntries) {
|
|
3836
|
+
if (actualEntries.length !== expectedEntries.length) {
|
|
3837
|
+
return false;
|
|
3838
|
+
}
|
|
3839
|
+
return actualEntries.every(
|
|
3840
|
+
(entry, index) => schemaEntrySignature(entry) === schemaEntrySignature(expectedEntries[index])
|
|
3841
|
+
);
|
|
3842
|
+
}
|
|
3843
|
+
function describeSchemaMismatch(expected, actual) {
|
|
3844
|
+
const expectedByName = new Map(expected.map((entry) => [`${entry.type}:${entry.name}`, entry]));
|
|
3845
|
+
const actualByName = new Map(actual.map((entry) => [`${entry.type}:${entry.name}`, entry]));
|
|
3846
|
+
const keys = /* @__PURE__ */ new Set([...expectedByName.keys(), ...actualByName.keys()]);
|
|
3847
|
+
for (const key of keys) {
|
|
3848
|
+
const expectedEntry = expectedByName.get(key);
|
|
3849
|
+
const actualEntry = actualByName.get(key);
|
|
3850
|
+
if (!expectedEntry) {
|
|
3851
|
+
return `unexpected ${actualEntry?.type ?? "schema object"} ${actualEntry?.name ?? key}`;
|
|
3852
|
+
}
|
|
3853
|
+
if (!actualEntry) {
|
|
3854
|
+
return `missing ${expectedEntry.type} ${expectedEntry.name}`;
|
|
3855
|
+
}
|
|
3856
|
+
if (schemaEntrySignature(expectedEntry) !== schemaEntrySignature(actualEntry)) {
|
|
3857
|
+
return `definition mismatch for ${expectedEntry.type} ${expectedEntry.name}`;
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
return "unknown schema drift";
|
|
3861
|
+
}
|
|
3862
|
+
function detectSchema(db) {
|
|
3863
|
+
const actualEntries = listSchemaEntries(db);
|
|
3864
|
+
const userVersionRow = db.prepare("PRAGMA user_version").get();
|
|
3865
|
+
const userVersion = userVersionRow?.user_version ?? 0;
|
|
3866
|
+
if (actualEntries.length === 0) {
|
|
3867
|
+
return {
|
|
3868
|
+
state: "empty",
|
|
3869
|
+
userVersion,
|
|
3870
|
+
mismatch: null
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3873
|
+
if (hasExactFingerprint(actualEntries, CURRENT_SCHEMA_ENTRIES)) {
|
|
3874
|
+
return {
|
|
3875
|
+
state: "current",
|
|
3876
|
+
userVersion,
|
|
3877
|
+
mismatch: null
|
|
3878
|
+
};
|
|
3879
|
+
}
|
|
3880
|
+
if (hasExactFingerprint(actualEntries, V1_SCHEMA_ENTRIES)) {
|
|
3881
|
+
return {
|
|
3882
|
+
state: "v1",
|
|
3883
|
+
userVersion,
|
|
3884
|
+
mismatch: null
|
|
3885
|
+
};
|
|
3886
|
+
}
|
|
3887
|
+
return {
|
|
3888
|
+
state: "incompatible",
|
|
3889
|
+
userVersion,
|
|
3890
|
+
mismatch: describeSchemaMismatch(CURRENT_SCHEMA_ENTRIES, actualEntries)
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
function stampCurrentSchemaVersion(db) {
|
|
3894
|
+
db.exec(`PRAGMA user_version = ${CURRENT_SCHEMA_VERSION}`);
|
|
3895
|
+
}
|
|
3896
|
+
var CURRENT_SCHEMA_VERSION, CURRENT_SCHEMA_PATH, CURRENT_SCHEMA_SQL, V1_SCHEMA_SQL, CURRENT_SCHEMA_ENTRIES, V1_SCHEMA_ENTRIES, IncompatibleSchemaError;
|
|
3897
|
+
var init_schema_version = __esm({
|
|
3898
|
+
"packages/server/src/storage/schema-version.ts"() {
|
|
3899
|
+
"use strict";
|
|
3900
|
+
CURRENT_SCHEMA_VERSION = 2;
|
|
3901
|
+
CURRENT_SCHEMA_PATH = join3(import.meta.dirname, "migrations", "001_init.sql");
|
|
3902
|
+
CURRENT_SCHEMA_SQL = readFileSync4(CURRENT_SCHEMA_PATH, "utf-8");
|
|
3903
|
+
V1_SCHEMA_SQL = `
|
|
3904
|
+
CREATE TABLE workspaces (
|
|
3905
|
+
id TEXT PRIMARY KEY,
|
|
3906
|
+
path TEXT NOT NULL UNIQUE,
|
|
3907
|
+
target_runtime TEXT NOT NULL,
|
|
3908
|
+
wsl_distro TEXT,
|
|
3909
|
+
opened_at INTEGER NOT NULL,
|
|
3910
|
+
last_active_at INTEGER NOT NULL,
|
|
3911
|
+
ui_state TEXT
|
|
3912
|
+
);
|
|
3913
|
+
|
|
3914
|
+
CREATE TABLE terminals (
|
|
3915
|
+
id TEXT PRIMARY KEY,
|
|
3916
|
+
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
3917
|
+
kind TEXT NOT NULL,
|
|
3918
|
+
cwd TEXT NOT NULL,
|
|
3919
|
+
argv TEXT NOT NULL,
|
|
3920
|
+
env TEXT,
|
|
3921
|
+
title TEXT,
|
|
3922
|
+
cols INTEGER NOT NULL,
|
|
3923
|
+
rows INTEGER NOT NULL,
|
|
3924
|
+
created_at INTEGER NOT NULL,
|
|
3925
|
+
ended_at INTEGER,
|
|
3926
|
+
exit_code INTEGER
|
|
3927
|
+
);
|
|
3928
|
+
|
|
3929
|
+
CREATE INDEX idx_terminals_workspace ON terminals(workspace_id);
|
|
3930
|
+
CREATE INDEX idx_terminals_kind ON terminals(workspace_id, kind);
|
|
3931
|
+
|
|
3932
|
+
CREATE TABLE sessions (
|
|
3933
|
+
id TEXT PRIMARY KEY,
|
|
3934
|
+
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
3935
|
+
terminal_id TEXT NOT NULL REFERENCES terminals(id) ON DELETE CASCADE,
|
|
3936
|
+
provider_id TEXT NOT NULL,
|
|
3937
|
+
capability TEXT NOT NULL,
|
|
3938
|
+
state TEXT NOT NULL,
|
|
3939
|
+
started_at INTEGER NOT NULL,
|
|
3940
|
+
ended_at INTEGER,
|
|
3941
|
+
last_active_at INTEGER NOT NULL,
|
|
3942
|
+
completion_percent INTEGER,
|
|
3943
|
+
error_reason TEXT,
|
|
3944
|
+
archived BOOLEAN DEFAULT 0,
|
|
3945
|
+
title TEXT
|
|
3946
|
+
);
|
|
3947
|
+
|
|
3948
|
+
CREATE INDEX idx_sessions_workspace ON sessions(workspace_id);
|
|
3949
|
+
CREATE UNIQUE INDEX idx_sessions_terminal ON sessions(terminal_id);
|
|
3950
|
+
CREATE UNIQUE INDEX idx_sessions_id_workspace ON sessions(id, workspace_id);
|
|
3951
|
+
|
|
3952
|
+
CREATE TABLE provider_configs (
|
|
3953
|
+
provider_id TEXT PRIMARY KEY,
|
|
3954
|
+
config TEXT NOT NULL
|
|
3955
|
+
);
|
|
3956
|
+
|
|
3957
|
+
CREATE TABLE user_settings (
|
|
3958
|
+
key TEXT PRIMARY KEY,
|
|
3959
|
+
value TEXT NOT NULL
|
|
3960
|
+
);
|
|
3961
|
+
|
|
3962
|
+
CREATE TABLE auth_sessions (
|
|
3963
|
+
token TEXT PRIMARY KEY,
|
|
3964
|
+
created_at INTEGER NOT NULL,
|
|
3965
|
+
last_seen_at INTEGER NOT NULL
|
|
3966
|
+
);
|
|
3967
|
+
|
|
3968
|
+
CREATE INDEX idx_auth_sessions_last_seen_at ON auth_sessions(last_seen_at);
|
|
3969
|
+
|
|
3970
|
+
CREATE TABLE supervisors (
|
|
3971
|
+
id TEXT PRIMARY KEY,
|
|
3972
|
+
session_id TEXT NOT NULL UNIQUE,
|
|
3973
|
+
workspace_id TEXT NOT NULL,
|
|
3974
|
+
state TEXT NOT NULL,
|
|
3975
|
+
objective TEXT NOT NULL,
|
|
3976
|
+
evaluator_provider_id TEXT NOT NULL,
|
|
3977
|
+
last_cycle_at INTEGER,
|
|
3978
|
+
last_evaluated_turn_id TEXT,
|
|
3979
|
+
error_reason TEXT,
|
|
3980
|
+
created_at INTEGER NOT NULL,
|
|
3981
|
+
updated_at INTEGER NOT NULL,
|
|
3982
|
+
FOREIGN KEY (session_id, workspace_id) REFERENCES sessions(id, workspace_id) ON DELETE CASCADE,
|
|
3983
|
+
FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
|
|
3984
|
+
);
|
|
3985
|
+
|
|
3986
|
+
CREATE INDEX idx_supervisors_workspace ON supervisors(workspace_id);
|
|
3987
|
+
CREATE INDEX idx_supervisors_session ON supervisors(session_id);
|
|
3988
|
+
CREATE UNIQUE INDEX idx_supervisors_id_session ON supervisors(id, session_id);
|
|
3989
|
+
|
|
3990
|
+
CREATE TABLE supervisor_cycles (
|
|
3991
|
+
id TEXT PRIMARY KEY,
|
|
3992
|
+
supervisor_id TEXT NOT NULL,
|
|
3993
|
+
session_id TEXT NOT NULL,
|
|
3994
|
+
status TEXT NOT NULL,
|
|
3995
|
+
trigger TEXT NOT NULL,
|
|
3996
|
+
evidence_source TEXT NOT NULL,
|
|
3997
|
+
objective TEXT NOT NULL,
|
|
3998
|
+
evaluator_provider_id TEXT NOT NULL,
|
|
3999
|
+
turn_id TEXT,
|
|
4000
|
+
progress INTEGER,
|
|
4001
|
+
result TEXT,
|
|
4002
|
+
injected_guidance TEXT,
|
|
4003
|
+
error_reason TEXT,
|
|
4004
|
+
created_at INTEGER NOT NULL,
|
|
4005
|
+
completed_at INTEGER,
|
|
4006
|
+
FOREIGN KEY (supervisor_id, session_id) REFERENCES supervisors(id, session_id) ON DELETE CASCADE,
|
|
4007
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
4008
|
+
);
|
|
4009
|
+
|
|
4010
|
+
CREATE INDEX idx_supervisor_cycles_supervisor ON supervisor_cycles(supervisor_id, created_at DESC);
|
|
4011
|
+
CREATE INDEX idx_supervisor_cycles_session ON supervisor_cycles(session_id, created_at DESC);
|
|
4012
|
+
|
|
4013
|
+
CREATE TABLE auth_login_blocks (
|
|
4014
|
+
ip TEXT PRIMARY KEY,
|
|
4015
|
+
failed_count INTEGER NOT NULL,
|
|
4016
|
+
first_failed_at INTEGER NOT NULL,
|
|
4017
|
+
last_failed_at INTEGER NOT NULL,
|
|
4018
|
+
blocked_until INTEGER
|
|
4019
|
+
);
|
|
4020
|
+
|
|
4021
|
+
CREATE INDEX idx_auth_login_blocks_blocked_until ON auth_login_blocks(blocked_until);
|
|
4022
|
+
|
|
4023
|
+
CREATE TABLE auth_login_failures (
|
|
4024
|
+
ip TEXT NOT NULL,
|
|
4025
|
+
failed_at INTEGER NOT NULL
|
|
4026
|
+
);
|
|
4027
|
+
|
|
4028
|
+
CREATE INDEX idx_auth_login_failures_ip_failed_at ON auth_login_failures(ip, failed_at);
|
|
4029
|
+
`;
|
|
4030
|
+
CURRENT_SCHEMA_ENTRIES = buildSchemaEntries(CURRENT_SCHEMA_SQL);
|
|
4031
|
+
V1_SCHEMA_ENTRIES = buildSchemaEntries(V1_SCHEMA_SQL);
|
|
4032
|
+
IncompatibleSchemaError = class extends Error {
|
|
4033
|
+
code = "db_incompatible_schema";
|
|
4034
|
+
constructor(dbPath, mismatch) {
|
|
4035
|
+
super(
|
|
4036
|
+
`db_incompatible_schema: Database schema mismatch detected at ${dbPath}: ${mismatch}. This build requires the current baseline schema. Delete the local database file and restart.`
|
|
4037
|
+
);
|
|
4038
|
+
this.name = "IncompatibleSchemaError";
|
|
4039
|
+
}
|
|
4040
|
+
};
|
|
4041
|
+
}
|
|
4042
|
+
});
|
|
4043
|
+
|
|
4044
|
+
// packages/server/src/storage/db.ts
|
|
4045
|
+
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
3796
4046
|
function hasTable(db, tableName) {
|
|
3797
4047
|
const row = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(tableName);
|
|
3798
4048
|
return row?.name === tableName;
|
|
@@ -3819,68 +4069,75 @@ function detectLegacySchema(db) {
|
|
|
3819
4069
|
}
|
|
3820
4070
|
return reasons;
|
|
3821
4071
|
}
|
|
3822
|
-
function
|
|
3823
|
-
return `${entry.type}:${entry.name}:${entry.tableName}:${entry.sql}`;
|
|
3824
|
-
}
|
|
3825
|
-
function isSchemaEmpty(db) {
|
|
3826
|
-
return listSchemaEntries(db).length === 0;
|
|
3827
|
-
}
|
|
3828
|
-
function assertNoLegacySchema(db, dbPath) {
|
|
4072
|
+
function throwIfLegacySchema(db, dbPath) {
|
|
3829
4073
|
const reasons = detectLegacySchema(db);
|
|
3830
4074
|
if (reasons.length === 0) {
|
|
3831
4075
|
return;
|
|
3832
4076
|
}
|
|
3833
|
-
throw new
|
|
3834
|
-
`Legacy database schema detected at ${dbPath}: ${reasons.join(", ")}. This build no longer supports automatic database upgrades. Delete the local database file and restart.`
|
|
3835
|
-
);
|
|
3836
|
-
}
|
|
3837
|
-
function describeSchemaMismatch(expected, actual) {
|
|
3838
|
-
const expectedByName = new Map(expected.map((entry) => [`${entry.type}:${entry.name}`, entry]));
|
|
3839
|
-
const actualByName = new Map(actual.map((entry) => [`${entry.type}:${entry.name}`, entry]));
|
|
3840
|
-
const keys = /* @__PURE__ */ new Set([...expectedByName.keys(), ...actualByName.keys()]);
|
|
3841
|
-
for (const key of keys) {
|
|
3842
|
-
const expectedEntry = expectedByName.get(key);
|
|
3843
|
-
const actualEntry = actualByName.get(key);
|
|
3844
|
-
if (!expectedEntry) {
|
|
3845
|
-
return `unexpected ${actualEntry?.type ?? "schema object"} ${actualEntry?.name ?? key}`;
|
|
3846
|
-
}
|
|
3847
|
-
if (!actualEntry) {
|
|
3848
|
-
return `missing ${expectedEntry.type} ${expectedEntry.name}`;
|
|
3849
|
-
}
|
|
3850
|
-
if (schemaEntrySignature(expectedEntry) !== schemaEntrySignature(actualEntry)) {
|
|
3851
|
-
return `definition mismatch for ${expectedEntry.type} ${expectedEntry.name}`;
|
|
3852
|
-
}
|
|
3853
|
-
}
|
|
3854
|
-
return "unknown schema drift";
|
|
3855
|
-
}
|
|
3856
|
-
function assertSchemaMatchesBaseline(db, dbPath) {
|
|
3857
|
-
const actualEntries = listSchemaEntries(db);
|
|
3858
|
-
const expectedSignatures = EXPECTED_SCHEMA_ENTRIES.map(schemaEntrySignature);
|
|
3859
|
-
const actualSignatures = actualEntries.map(schemaEntrySignature);
|
|
3860
|
-
if (actualSignatures.length === expectedSignatures.length && actualSignatures.every((signature, index) => signature === expectedSignatures[index])) {
|
|
3861
|
-
return;
|
|
3862
|
-
}
|
|
3863
|
-
const mismatch = describeSchemaMismatch(EXPECTED_SCHEMA_ENTRIES, actualEntries);
|
|
3864
|
-
throw new Error(
|
|
3865
|
-
`Database schema mismatch detected at ${dbPath}: ${mismatch}. This build requires the current baseline schema. Delete the local database file and restart.`
|
|
3866
|
-
);
|
|
4077
|
+
throw new IncompatibleSchemaError(dbPath, `legacy schema detected (${reasons.join(", ")})`);
|
|
3867
4078
|
}
|
|
3868
4079
|
function initializeSchema(db) {
|
|
3869
4080
|
withTransaction(db, () => {
|
|
3870
|
-
db.exec(
|
|
4081
|
+
db.exec(CURRENT_SCHEMA_SQL);
|
|
3871
4082
|
});
|
|
3872
4083
|
}
|
|
3873
|
-
function
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
4084
|
+
function upgradeSchemaV1ToV2(db) {
|
|
4085
|
+
withTransaction(db, () => {
|
|
4086
|
+
db.exec("ALTER TABLE supervisors ADD COLUMN evaluator_model TEXT");
|
|
4087
|
+
db.exec("ALTER TABLE supervisors ADD COLUMN max_supervision_count INTEGER NOT NULL DEFAULT 0");
|
|
4088
|
+
db.exec(
|
|
4089
|
+
"ALTER TABLE supervisors ADD COLUMN completed_supervision_count INTEGER NOT NULL DEFAULT 0"
|
|
4090
|
+
);
|
|
4091
|
+
db.exec("ALTER TABLE supervisors ADD COLUMN scheduled_at INTEGER");
|
|
4092
|
+
db.exec("ALTER TABLE supervisors ADD COLUMN stop_reason TEXT");
|
|
4093
|
+
db.exec(`
|
|
4094
|
+
CREATE TABLE supervisor_cycle_attempts (
|
|
4095
|
+
id TEXT PRIMARY KEY,
|
|
4096
|
+
cycle_id TEXT NOT NULL REFERENCES supervisor_cycles(id) ON DELETE CASCADE,
|
|
4097
|
+
attempt_index INTEGER NOT NULL,
|
|
4098
|
+
status TEXT NOT NULL,
|
|
4099
|
+
started_at INTEGER NOT NULL,
|
|
4100
|
+
completed_at INTEGER,
|
|
4101
|
+
error_reason TEXT,
|
|
4102
|
+
provider_model TEXT
|
|
4103
|
+
)
|
|
4104
|
+
`);
|
|
4105
|
+
db.exec(
|
|
4106
|
+
"CREATE INDEX idx_supervisor_cycle_attempts_cycle ON supervisor_cycle_attempts(cycle_id, attempt_index)"
|
|
4107
|
+
);
|
|
4108
|
+
stampCurrentSchemaVersion(db);
|
|
4109
|
+
});
|
|
4110
|
+
}
|
|
4111
|
+
function assertCurrentSchema(db, dbPath) {
|
|
4112
|
+
const detection = detectSchema(db);
|
|
4113
|
+
if (detection.state !== "current") {
|
|
4114
|
+
throw new IncompatibleSchemaError(dbPath, detection.mismatch ?? "unknown schema drift");
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
function initializeOrUpgradeSchema(db, dbPath) {
|
|
4118
|
+
throwIfLegacySchema(db, dbPath);
|
|
4119
|
+
const detection = detectSchema(db);
|
|
4120
|
+
switch (detection.state) {
|
|
4121
|
+
case "empty":
|
|
4122
|
+
initializeSchema(db);
|
|
4123
|
+
assertCurrentSchema(db, dbPath);
|
|
4124
|
+
return;
|
|
4125
|
+
case "current":
|
|
4126
|
+
if (detection.userVersion !== CURRENT_SCHEMA_VERSION) {
|
|
4127
|
+
stampCurrentSchemaVersion(db);
|
|
4128
|
+
}
|
|
4129
|
+
assertCurrentSchema(db, dbPath);
|
|
4130
|
+
return;
|
|
4131
|
+
case "v1":
|
|
4132
|
+
upgradeSchemaV1ToV2(db);
|
|
4133
|
+
assertCurrentSchema(db, dbPath);
|
|
4134
|
+
return;
|
|
4135
|
+
case "incompatible":
|
|
4136
|
+
throw new IncompatibleSchemaError(dbPath, detection.mismatch ?? "unknown schema drift");
|
|
3879
4137
|
}
|
|
3880
|
-
assertSchemaMatchesBaseline(db, dbPath);
|
|
3881
4138
|
}
|
|
3882
4139
|
function openDatabase(dbPath) {
|
|
3883
|
-
const db = new
|
|
4140
|
+
const db = new DatabaseSync2(dbPath);
|
|
3884
4141
|
try {
|
|
3885
4142
|
db.exec("PRAGMA journal_mode = WAL");
|
|
3886
4143
|
db.exec("PRAGMA foreign_keys = ON");
|
|
@@ -3888,7 +4145,7 @@ function openDatabase(dbPath) {
|
|
|
3888
4145
|
if (integrityResult[0]?.integrity_check !== "ok") {
|
|
3889
4146
|
throw new Error(`Database integrity check failed: ${JSON.stringify(integrityResult)}`);
|
|
3890
4147
|
}
|
|
3891
|
-
|
|
4148
|
+
initializeOrUpgradeSchema(db, dbPath);
|
|
3892
4149
|
return db;
|
|
3893
4150
|
} catch (error) {
|
|
3894
4151
|
try {
|
|
@@ -3905,16 +4162,14 @@ function closeDatabase(db) {
|
|
|
3905
4162
|
db.close();
|
|
3906
4163
|
}
|
|
3907
4164
|
}
|
|
3908
|
-
var
|
|
4165
|
+
var LEGACY_TABLES, LEGACY_SESSION_COLUMNS;
|
|
3909
4166
|
var init_db = __esm({
|
|
3910
4167
|
"packages/server/src/storage/db.ts"() {
|
|
3911
4168
|
"use strict";
|
|
3912
4169
|
init_database();
|
|
3913
|
-
|
|
3914
|
-
SCHEMA_SQL = readFileSync4(SCHEMA_PATH, "utf-8");
|
|
4170
|
+
init_schema_version();
|
|
3915
4171
|
LEGACY_TABLES = ["hook_registrations", "_migrations"];
|
|
3916
4172
|
LEGACY_SESSION_COLUMNS = ["resume_id", "transcript_path"];
|
|
3917
|
-
EXPECTED_SCHEMA_ENTRIES = buildExpectedSchemaEntries();
|
|
3918
4173
|
}
|
|
3919
4174
|
});
|
|
3920
4175
|
|
|
@@ -4164,6 +4419,93 @@ var init_settings_repo = __esm({
|
|
|
4164
4419
|
}
|
|
4165
4420
|
});
|
|
4166
4421
|
|
|
4422
|
+
// packages/server/src/storage/repositories/supervisor-cycle-attempt-repo.ts
|
|
4423
|
+
var SupervisorCycleAttemptRepo;
|
|
4424
|
+
var init_supervisor_cycle_attempt_repo = __esm({
|
|
4425
|
+
"packages/server/src/storage/repositories/supervisor-cycle-attempt-repo.ts"() {
|
|
4426
|
+
"use strict";
|
|
4427
|
+
SupervisorCycleAttemptRepo = class {
|
|
4428
|
+
constructor(db) {
|
|
4429
|
+
this.db = db;
|
|
4430
|
+
}
|
|
4431
|
+
db;
|
|
4432
|
+
create(input2) {
|
|
4433
|
+
this.db.prepare(
|
|
4434
|
+
`INSERT INTO supervisor_cycle_attempts (id, cycle_id, attempt_index, status, started_at, completed_at, error_reason, provider_model)
|
|
4435
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
4436
|
+
).run(
|
|
4437
|
+
input2.id,
|
|
4438
|
+
input2.cycleId,
|
|
4439
|
+
input2.attemptIndex,
|
|
4440
|
+
input2.status,
|
|
4441
|
+
input2.startedAt,
|
|
4442
|
+
input2.completedAt ?? null,
|
|
4443
|
+
input2.errorReason ?? null,
|
|
4444
|
+
input2.providerModel ?? null
|
|
4445
|
+
);
|
|
4446
|
+
return this.findById(input2.id);
|
|
4447
|
+
}
|
|
4448
|
+
findById(id) {
|
|
4449
|
+
const row = this.db.prepare("SELECT * FROM supervisor_cycle_attempts WHERE id = ?").get(id);
|
|
4450
|
+
return row ? this.rowToAttempt(row) : void 0;
|
|
4451
|
+
}
|
|
4452
|
+
listForCycle(cycleId) {
|
|
4453
|
+
const rows = this.db.prepare(
|
|
4454
|
+
"SELECT * FROM supervisor_cycle_attempts WHERE cycle_id = ? ORDER BY attempt_index ASC"
|
|
4455
|
+
).all(cycleId);
|
|
4456
|
+
return rows.map((row) => this.rowToAttempt(row));
|
|
4457
|
+
}
|
|
4458
|
+
update(id, patch) {
|
|
4459
|
+
const assignments = [];
|
|
4460
|
+
const params = { id };
|
|
4461
|
+
if (patch.status !== void 0) {
|
|
4462
|
+
assignments.push("status = @status");
|
|
4463
|
+
params.status = patch.status;
|
|
4464
|
+
}
|
|
4465
|
+
if (patch.completedAt !== void 0) {
|
|
4466
|
+
assignments.push("completed_at = @completedAt");
|
|
4467
|
+
params.completedAt = patch.completedAt;
|
|
4468
|
+
}
|
|
4469
|
+
if (patch.errorReason !== void 0) {
|
|
4470
|
+
assignments.push("error_reason = @errorReason");
|
|
4471
|
+
params.errorReason = patch.errorReason;
|
|
4472
|
+
}
|
|
4473
|
+
if (patch.providerModel !== void 0) {
|
|
4474
|
+
assignments.push("provider_model = @providerModel");
|
|
4475
|
+
params.providerModel = patch.providerModel;
|
|
4476
|
+
}
|
|
4477
|
+
if (assignments.length === 0) {
|
|
4478
|
+
const existing = this.findById(id);
|
|
4479
|
+
if (!existing) {
|
|
4480
|
+
throw new Error(`Supervisor cycle attempt not found: ${id}`);
|
|
4481
|
+
}
|
|
4482
|
+
return existing;
|
|
4483
|
+
}
|
|
4484
|
+
const result = this.db.prepare(`UPDATE supervisor_cycle_attempts SET ${assignments.join(", ")} WHERE id = @id`).run(params);
|
|
4485
|
+
if (result.changes === 0) {
|
|
4486
|
+
throw new Error(`Supervisor cycle attempt not found: ${id}`);
|
|
4487
|
+
}
|
|
4488
|
+
return this.findById(id);
|
|
4489
|
+
}
|
|
4490
|
+
deleteForCycle(cycleId) {
|
|
4491
|
+
this.db.prepare("DELETE FROM supervisor_cycle_attempts WHERE cycle_id = ?").run(cycleId);
|
|
4492
|
+
}
|
|
4493
|
+
rowToAttempt(row) {
|
|
4494
|
+
return {
|
|
4495
|
+
id: row.id,
|
|
4496
|
+
cycleId: row.cycle_id,
|
|
4497
|
+
attemptIndex: row.attempt_index,
|
|
4498
|
+
status: row.status,
|
|
4499
|
+
startedAt: row.started_at,
|
|
4500
|
+
completedAt: row.completed_at ?? void 0,
|
|
4501
|
+
errorReason: row.error_reason ?? void 0,
|
|
4502
|
+
providerModel: row.provider_model ?? void 0
|
|
4503
|
+
};
|
|
4504
|
+
}
|
|
4505
|
+
};
|
|
4506
|
+
}
|
|
4507
|
+
});
|
|
4508
|
+
|
|
4167
4509
|
// packages/server/src/storage/repositories/supervisor-cycle-repo.ts
|
|
4168
4510
|
var SupervisorCycleRepo;
|
|
4169
4511
|
var init_supervisor_cycle_repo = __esm({
|
|
@@ -4293,8 +4635,8 @@ var init_supervisor_repo = __esm({
|
|
|
4293
4635
|
db;
|
|
4294
4636
|
create(input2) {
|
|
4295
4637
|
this.db.prepare(
|
|
4296
|
-
`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)
|
|
4297
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
4638
|
+
`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)
|
|
4639
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
4298
4640
|
).run(
|
|
4299
4641
|
input2.id,
|
|
4300
4642
|
input2.sessionId,
|
|
@@ -4302,6 +4644,11 @@ var init_supervisor_repo = __esm({
|
|
|
4302
4644
|
input2.state,
|
|
4303
4645
|
input2.objective,
|
|
4304
4646
|
input2.evaluatorProviderId,
|
|
4647
|
+
input2.evaluatorModel ?? null,
|
|
4648
|
+
input2.maxSupervisionCount ?? 0,
|
|
4649
|
+
input2.completedSupervisionCount ?? 0,
|
|
4650
|
+
input2.scheduledAt ?? null,
|
|
4651
|
+
input2.stopReason ?? null,
|
|
4305
4652
|
input2.lastCycleAt ?? null,
|
|
4306
4653
|
input2.lastEvaluatedTurnId ?? null,
|
|
4307
4654
|
input2.errorReason ?? null,
|
|
@@ -4340,6 +4687,26 @@ var init_supervisor_repo = __esm({
|
|
|
4340
4687
|
assignments.push("evaluator_provider_id = @evaluatorProviderId");
|
|
4341
4688
|
params.evaluatorProviderId = patch.evaluatorProviderId;
|
|
4342
4689
|
}
|
|
4690
|
+
if (patch.evaluatorModel !== void 0) {
|
|
4691
|
+
assignments.push("evaluator_model = @evaluatorModel");
|
|
4692
|
+
params.evaluatorModel = patch.evaluatorModel;
|
|
4693
|
+
}
|
|
4694
|
+
if (patch.maxSupervisionCount !== void 0) {
|
|
4695
|
+
assignments.push("max_supervision_count = @maxSupervisionCount");
|
|
4696
|
+
params.maxSupervisionCount = patch.maxSupervisionCount;
|
|
4697
|
+
}
|
|
4698
|
+
if (patch.completedSupervisionCount !== void 0) {
|
|
4699
|
+
assignments.push("completed_supervision_count = @completedSupervisionCount");
|
|
4700
|
+
params.completedSupervisionCount = patch.completedSupervisionCount;
|
|
4701
|
+
}
|
|
4702
|
+
if (patch.scheduledAt !== void 0) {
|
|
4703
|
+
assignments.push("scheduled_at = @scheduledAt");
|
|
4704
|
+
params.scheduledAt = patch.scheduledAt;
|
|
4705
|
+
}
|
|
4706
|
+
if (patch.stopReason !== void 0) {
|
|
4707
|
+
assignments.push("stop_reason = @stopReason");
|
|
4708
|
+
params.stopReason = patch.stopReason;
|
|
4709
|
+
}
|
|
4343
4710
|
if (patch.lastCycleAt !== void 0) {
|
|
4344
4711
|
assignments.push("last_cycle_at = @lastCycleAt");
|
|
4345
4712
|
params.lastCycleAt = patch.lastCycleAt;
|
|
@@ -4369,6 +4736,11 @@ var init_supervisor_repo = __esm({
|
|
|
4369
4736
|
state: row.state,
|
|
4370
4737
|
objective: row.objective,
|
|
4371
4738
|
evaluatorProviderId: row.evaluator_provider_id,
|
|
4739
|
+
evaluatorModel: row.evaluator_model ?? void 0,
|
|
4740
|
+
maxSupervisionCount: row.max_supervision_count,
|
|
4741
|
+
completedSupervisionCount: row.completed_supervision_count,
|
|
4742
|
+
scheduledAt: row.scheduled_at ?? void 0,
|
|
4743
|
+
stopReason: row.stop_reason ?? void 0,
|
|
4372
4744
|
cycles: [],
|
|
4373
4745
|
lastCycleAt: row.last_cycle_at ?? void 0,
|
|
4374
4746
|
lastEvaluatedTurnId: row.last_evaluated_turn_id ?? void 0,
|
|
@@ -5556,12 +5928,63 @@ function getSupervisorEvaluationTimeoutMs(settingsRepo) {
|
|
|
5556
5928
|
const timeoutSec = resolveSupervisorEvaluationTimeoutSec(storedValue);
|
|
5557
5929
|
return timeoutSec * 1e3;
|
|
5558
5930
|
}
|
|
5559
|
-
|
|
5931
|
+
function getSettingOrDefault(settingsRepo, key, fallback) {
|
|
5932
|
+
try {
|
|
5933
|
+
return settingsRepo?.get(key) ?? fallback;
|
|
5934
|
+
} catch {
|
|
5935
|
+
return fallback;
|
|
5936
|
+
}
|
|
5937
|
+
}
|
|
5938
|
+
function getSupervisorRetrySettings(settingsRepo) {
|
|
5939
|
+
return {
|
|
5940
|
+
retryEnabled: resolveSupervisorRetryEnabled(
|
|
5941
|
+
getSettingOrDefault(
|
|
5942
|
+
settingsRepo,
|
|
5943
|
+
SUPERVISOR_RETRY_ENABLED_SETTING_KEY,
|
|
5944
|
+
DEFAULT_SUPERVISOR_RETRY_ENABLED
|
|
5945
|
+
)
|
|
5946
|
+
),
|
|
5947
|
+
retryMaxCount: resolveSupervisorRetryMaxCount(
|
|
5948
|
+
getSettingOrDefault(
|
|
5949
|
+
settingsRepo,
|
|
5950
|
+
SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY,
|
|
5951
|
+
DEFAULT_SUPERVISOR_RETRY_MAX_COUNT
|
|
5952
|
+
)
|
|
5953
|
+
),
|
|
5954
|
+
retryDelaySec: resolveSupervisorRetryDelaySec(
|
|
5955
|
+
getSettingOrDefault(
|
|
5956
|
+
settingsRepo,
|
|
5957
|
+
SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY,
|
|
5958
|
+
DEFAULT_SUPERVISOR_RETRY_DELAY_SEC
|
|
5959
|
+
)
|
|
5960
|
+
),
|
|
5961
|
+
retryOnTimeout: resolveSupervisorRetryOnTimeout(
|
|
5962
|
+
getSettingOrDefault(
|
|
5963
|
+
settingsRepo,
|
|
5964
|
+
SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY,
|
|
5965
|
+
DEFAULT_SUPERVISOR_RETRY_ON_TIMEOUT
|
|
5966
|
+
)
|
|
5967
|
+
),
|
|
5968
|
+
retryOnEvaluatorError: resolveSupervisorRetryOnEvaluatorError(
|
|
5969
|
+
getSettingOrDefault(
|
|
5970
|
+
settingsRepo,
|
|
5971
|
+
SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY,
|
|
5972
|
+
DEFAULT_SUPERVISOR_RETRY_ON_EVALUATOR_ERROR
|
|
5973
|
+
)
|
|
5974
|
+
)
|
|
5975
|
+
};
|
|
5976
|
+
}
|
|
5977
|
+
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;
|
|
5560
5978
|
var init_settings = __esm({
|
|
5561
5979
|
"packages/server/src/supervisor/settings.ts"() {
|
|
5562
5980
|
"use strict";
|
|
5563
5981
|
init_src3();
|
|
5564
5982
|
SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY = "supervisor.evaluationTimeoutSec";
|
|
5983
|
+
SUPERVISOR_RETRY_ENABLED_SETTING_KEY = "supervisor.retryEnabled";
|
|
5984
|
+
SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY = "supervisor.retryMaxCount";
|
|
5985
|
+
SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY = "supervisor.retryDelaySec";
|
|
5986
|
+
SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY = "supervisor.retryOnTimeout";
|
|
5987
|
+
SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY = "supervisor.retryOnEvaluatorError";
|
|
5565
5988
|
}
|
|
5566
5989
|
});
|
|
5567
5990
|
|
|
@@ -5783,6 +6206,12 @@ function extractSupervisorMessage(output2, providerId) {
|
|
|
5783
6206
|
}
|
|
5784
6207
|
const lines = trimmed.split(/\r?\n/).filter(Boolean);
|
|
5785
6208
|
if (providerId === "codex") {
|
|
6209
|
+
if (trimmed === "[objective complete]") {
|
|
6210
|
+
return trimmed;
|
|
6211
|
+
}
|
|
6212
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
6213
|
+
return stripCodeFence(trimmed);
|
|
6214
|
+
}
|
|
5786
6215
|
const scan = scanCodexStream(lines);
|
|
5787
6216
|
if (scan.turnFailure) {
|
|
5788
6217
|
throw new Error(`Supervisor (codex) failed: ${scan.turnFailure}`);
|
|
@@ -5884,7 +6313,7 @@ var init_evaluator = __esm({
|
|
|
5884
6313
|
prompt,
|
|
5885
6314
|
sessionId: supervisor.sessionId,
|
|
5886
6315
|
workspacePath: context.workspacePath,
|
|
5887
|
-
model: typeof config.model === "string" ? config.model : void 0
|
|
6316
|
+
model: typeof supervisor.evaluatorModel === "string" && supervisor.evaluatorModel.trim() ? supervisor.evaluatorModel.trim() : typeof config.model === "string" ? config.model : void 0
|
|
5888
6317
|
});
|
|
5889
6318
|
if (!command) {
|
|
5890
6319
|
throw {
|
|
@@ -5913,7 +6342,11 @@ var init_evaluator = __esm({
|
|
|
5913
6342
|
);
|
|
5914
6343
|
throw error;
|
|
5915
6344
|
}
|
|
5916
|
-
|
|
6345
|
+
const normalizedMessage = message.slice(0, this.config.guidanceMaxChars);
|
|
6346
|
+
return {
|
|
6347
|
+
message: normalizedMessage,
|
|
6348
|
+
objectiveComplete: normalizedMessage.trim() === "[objective complete]"
|
|
6349
|
+
};
|
|
5917
6350
|
}
|
|
5918
6351
|
};
|
|
5919
6352
|
}
|
|
@@ -5949,7 +6382,13 @@ var init_injector = __esm({
|
|
|
5949
6382
|
}
|
|
5950
6383
|
deps;
|
|
5951
6384
|
config;
|
|
5952
|
-
async inject(supervisor, input2, recentCycles) {
|
|
6385
|
+
async inject(supervisor, input2, recentCycles, options = {}) {
|
|
6386
|
+
if (options.signal?.aborted) {
|
|
6387
|
+
throw {
|
|
6388
|
+
code: "supervisor_eval_aborted",
|
|
6389
|
+
message: "Supervisor evaluator aborted"
|
|
6390
|
+
};
|
|
6391
|
+
}
|
|
5953
6392
|
const session = this.deps.sessionMgr.get(supervisor.sessionId);
|
|
5954
6393
|
if (!session) {
|
|
5955
6394
|
throw {
|
|
@@ -5970,6 +6409,12 @@ var init_injector = __esm({
|
|
|
5970
6409
|
if (duplicate) {
|
|
5971
6410
|
return { injected: false, text };
|
|
5972
6411
|
}
|
|
6412
|
+
if (options.signal?.aborted) {
|
|
6413
|
+
throw {
|
|
6414
|
+
code: "supervisor_eval_aborted",
|
|
6415
|
+
message: "Supervisor evaluator aborted"
|
|
6416
|
+
};
|
|
6417
|
+
}
|
|
5973
6418
|
const BRACKETED_PASTE_START = "\x1B[200~";
|
|
5974
6419
|
const BRACKETED_PASTE_END = "\x1B[201~";
|
|
5975
6420
|
const SUBMIT = "\r";
|
|
@@ -5992,6 +6437,9 @@ var init_scheduler = __esm({
|
|
|
5992
6437
|
}
|
|
5993
6438
|
deps;
|
|
5994
6439
|
unsubscribe = null;
|
|
6440
|
+
scheduledTimer = null;
|
|
6441
|
+
scheduledRetryDelayMs = 1e3;
|
|
6442
|
+
retryAtBySupervisorId = /* @__PURE__ */ new Map();
|
|
5995
6443
|
start() {
|
|
5996
6444
|
this.unsubscribe?.();
|
|
5997
6445
|
this.unsubscribe = this.deps.eventBus.on(
|
|
@@ -6004,9 +6452,64 @@ var init_scheduler = __esm({
|
|
|
6004
6452
|
}
|
|
6005
6453
|
);
|
|
6006
6454
|
}
|
|
6455
|
+
refresh() {
|
|
6456
|
+
this.clearScheduledTimer();
|
|
6457
|
+
const scheduled = this.deps.listScheduledSupervisors?.() ?? [];
|
|
6458
|
+
this.pruneRetryState(scheduled);
|
|
6459
|
+
if (scheduled.length === 0) {
|
|
6460
|
+
return;
|
|
6461
|
+
}
|
|
6462
|
+
const now = Date.now();
|
|
6463
|
+
const nextAt = scheduled.reduce((earliest, item) => {
|
|
6464
|
+
const candidate = this.getNextAttemptAt(item, now);
|
|
6465
|
+
return candidate < earliest ? candidate : earliest;
|
|
6466
|
+
}, Number.POSITIVE_INFINITY);
|
|
6467
|
+
if (!Number.isFinite(nextAt)) {
|
|
6468
|
+
return;
|
|
6469
|
+
}
|
|
6470
|
+
const delayMs = Math.max(nextAt - now, 0);
|
|
6471
|
+
this.scheduledTimer = setTimeout(() => {
|
|
6472
|
+
this.scheduledTimer = null;
|
|
6473
|
+
const current = this.deps.listScheduledSupervisors?.() ?? [];
|
|
6474
|
+
this.pruneRetryState(current);
|
|
6475
|
+
const dueAt = Date.now();
|
|
6476
|
+
const due = current.filter(
|
|
6477
|
+
(item) => item.scheduledAt <= dueAt && (this.retryAtBySupervisorId.get(item.supervisorId) ?? Number.NEGATIVE_INFINITY) <= dueAt
|
|
6478
|
+
);
|
|
6479
|
+
for (const item of due) {
|
|
6480
|
+
this.retryAtBySupervisorId.set(item.supervisorId, dueAt + this.scheduledRetryDelayMs);
|
|
6481
|
+
this.deps.onScheduledDue?.(item.supervisorId);
|
|
6482
|
+
}
|
|
6483
|
+
this.refresh();
|
|
6484
|
+
}, delayMs);
|
|
6485
|
+
this.scheduledTimer.unref?.();
|
|
6486
|
+
}
|
|
6007
6487
|
stop() {
|
|
6008
6488
|
this.unsubscribe?.();
|
|
6009
6489
|
this.unsubscribe = null;
|
|
6490
|
+
this.clearScheduledTimer();
|
|
6491
|
+
this.retryAtBySupervisorId.clear();
|
|
6492
|
+
}
|
|
6493
|
+
clearScheduledTimer() {
|
|
6494
|
+
if (this.scheduledTimer) {
|
|
6495
|
+
clearTimeout(this.scheduledTimer);
|
|
6496
|
+
this.scheduledTimer = null;
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
getNextAttemptAt(item, now) {
|
|
6500
|
+
if (item.scheduledAt > now) {
|
|
6501
|
+
return item.scheduledAt;
|
|
6502
|
+
}
|
|
6503
|
+
const retryAt = this.retryAtBySupervisorId.get(item.supervisorId);
|
|
6504
|
+
return retryAt && retryAt > now ? retryAt : item.scheduledAt;
|
|
6505
|
+
}
|
|
6506
|
+
pruneRetryState(scheduled) {
|
|
6507
|
+
const scheduledIds = new Set(scheduled.map((item) => item.supervisorId));
|
|
6508
|
+
for (const supervisorId of this.retryAtBySupervisorId.keys()) {
|
|
6509
|
+
if (!scheduledIds.has(supervisorId)) {
|
|
6510
|
+
this.retryAtBySupervisorId.delete(supervisorId);
|
|
6511
|
+
}
|
|
6512
|
+
}
|
|
6010
6513
|
}
|
|
6011
6514
|
};
|
|
6012
6515
|
}
|
|
@@ -6027,6 +6530,9 @@ function generateSupervisorId() {
|
|
|
6027
6530
|
function generateCycleId() {
|
|
6028
6531
|
return `cycle_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
6029
6532
|
}
|
|
6533
|
+
function generateAttemptId() {
|
|
6534
|
+
return `attempt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
6535
|
+
}
|
|
6030
6536
|
function messageOf(error, fallback) {
|
|
6031
6537
|
if (error instanceof Error) {
|
|
6032
6538
|
return error.message;
|
|
@@ -6054,6 +6560,7 @@ var init_manager2 = __esm({
|
|
|
6054
6560
|
init_evaluator();
|
|
6055
6561
|
init_injector();
|
|
6056
6562
|
init_scheduler();
|
|
6563
|
+
init_settings();
|
|
6057
6564
|
NOOP_LOGGER3 = {
|
|
6058
6565
|
child: () => NOOP_LOGGER3,
|
|
6059
6566
|
debug: () => {
|
|
@@ -6082,7 +6589,8 @@ var init_manager2 = __esm({
|
|
|
6082
6589
|
sessionMgr: deps.sessionMgr,
|
|
6083
6590
|
terminalMgr: deps.terminalMgr,
|
|
6084
6591
|
providerRegistry: deps.providerRegistry,
|
|
6085
|
-
logger: this.logger
|
|
6592
|
+
logger: this.logger,
|
|
6593
|
+
git: deps.git
|
|
6086
6594
|
});
|
|
6087
6595
|
this.evaluator = new SupervisorEvaluator({
|
|
6088
6596
|
providerRegistry: deps.providerRegistry,
|
|
@@ -6101,10 +6609,19 @@ var init_manager2 = __esm({
|
|
|
6101
6609
|
onTurnCompleted: (sessionId) => {
|
|
6102
6610
|
const supervisorId = this.supervisorsBySession.get(sessionId);
|
|
6103
6611
|
if (supervisorId) {
|
|
6104
|
-
void this.runEvaluation(supervisorId).catch((error) => {
|
|
6612
|
+
void this.runEvaluation(supervisorId, "turn_completed").catch((error) => {
|
|
6105
6613
|
this.logger.warn({ err: error, supervisorId }, "Supervisor auto-evaluation failed");
|
|
6106
6614
|
});
|
|
6107
6615
|
}
|
|
6616
|
+
},
|
|
6617
|
+
listScheduledSupervisors: () => this.listScheduledSupervisors(),
|
|
6618
|
+
onScheduledDue: (supervisorId) => {
|
|
6619
|
+
void this.runEvaluation(supervisorId, "scheduled").catch((error) => {
|
|
6620
|
+
this.logger.warn(
|
|
6621
|
+
{ err: error, supervisorId },
|
|
6622
|
+
"Supervisor scheduled auto-evaluation failed"
|
|
6623
|
+
);
|
|
6624
|
+
});
|
|
6108
6625
|
}
|
|
6109
6626
|
});
|
|
6110
6627
|
}
|
|
@@ -6113,6 +6630,7 @@ var init_manager2 = __esm({
|
|
|
6113
6630
|
supervisorsBySession = /* @__PURE__ */ new Map();
|
|
6114
6631
|
inFlight = /* @__PURE__ */ new Set();
|
|
6115
6632
|
pendingDeletes = /* @__PURE__ */ new Set();
|
|
6633
|
+
pendingPauses = /* @__PURE__ */ new Set();
|
|
6116
6634
|
evaluationAbortControllers = /* @__PURE__ */ new Map();
|
|
6117
6635
|
inFlightCompletions = /* @__PURE__ */ new Map();
|
|
6118
6636
|
scheduler;
|
|
@@ -6165,6 +6683,7 @@ var init_manager2 = __esm({
|
|
|
6165
6683
|
}
|
|
6166
6684
|
);
|
|
6167
6685
|
this.scheduler.start();
|
|
6686
|
+
this.scheduler.refresh();
|
|
6168
6687
|
}
|
|
6169
6688
|
stop() {
|
|
6170
6689
|
this.scheduler.stop();
|
|
@@ -6236,12 +6755,17 @@ var init_manager2 = __esm({
|
|
|
6236
6755
|
state: "idle",
|
|
6237
6756
|
objective: req.objective.trim(),
|
|
6238
6757
|
evaluatorProviderId: req.evaluatorProviderId,
|
|
6758
|
+
evaluatorModel: req.evaluatorModel?.trim() || void 0,
|
|
6759
|
+
maxSupervisionCount: req.maxSupervisionCount ?? 0,
|
|
6760
|
+
completedSupervisionCount: 0,
|
|
6761
|
+
scheduledAt: req.scheduledAt,
|
|
6239
6762
|
createdAt: now,
|
|
6240
6763
|
updatedAt: now
|
|
6241
6764
|
})
|
|
6242
6765
|
);
|
|
6243
6766
|
this.storeSnapshot(supervisor);
|
|
6244
6767
|
this.broadcastState(supervisor, "created");
|
|
6768
|
+
this.scheduler.refresh();
|
|
6245
6769
|
return supervisor;
|
|
6246
6770
|
}
|
|
6247
6771
|
async update(id, patch) {
|
|
@@ -6253,6 +6777,9 @@ var init_manager2 = __esm({
|
|
|
6253
6777
|
this.deps.supervisorRepo.update(id, {
|
|
6254
6778
|
objective: patch.objective !== void 0 ? patch.objective.trim() : current.objective,
|
|
6255
6779
|
evaluatorProviderId: patch.evaluatorProviderId ?? current.evaluatorProviderId,
|
|
6780
|
+
evaluatorModel: patch.evaluatorModel === void 0 ? current.evaluatorModel : patch.evaluatorModel?.trim() || null,
|
|
6781
|
+
maxSupervisionCount: patch.maxSupervisionCount ?? current.maxSupervisionCount,
|
|
6782
|
+
scheduledAt: patch.scheduledAt === void 0 ? current.scheduledAt : patch.scheduledAt,
|
|
6256
6783
|
state: current.state === "error" ? "idle" : current.state,
|
|
6257
6784
|
errorReason: null,
|
|
6258
6785
|
updatedAt: Date.now()
|
|
@@ -6260,9 +6787,14 @@ var init_manager2 = __esm({
|
|
|
6260
6787
|
);
|
|
6261
6788
|
this.storeSnapshot(updated);
|
|
6262
6789
|
this.broadcastState(updated, "updated");
|
|
6790
|
+
this.scheduler.refresh();
|
|
6263
6791
|
return updated;
|
|
6264
6792
|
}
|
|
6265
6793
|
async pause(id) {
|
|
6794
|
+
if (this.inFlight.has(id)) {
|
|
6795
|
+
this.pendingPauses.add(id);
|
|
6796
|
+
this.evaluationAbortControllers.get(id)?.abort();
|
|
6797
|
+
}
|
|
6266
6798
|
const updated = this.attachCycles(
|
|
6267
6799
|
this.deps.supervisorRepo.update(id, {
|
|
6268
6800
|
state: "paused",
|
|
@@ -6271,6 +6803,7 @@ var init_manager2 = __esm({
|
|
|
6271
6803
|
);
|
|
6272
6804
|
this.storeSnapshot(updated);
|
|
6273
6805
|
this.broadcastState(updated, "state_changed");
|
|
6806
|
+
this.scheduler.refresh();
|
|
6274
6807
|
return updated;
|
|
6275
6808
|
}
|
|
6276
6809
|
async resume(id) {
|
|
@@ -6283,6 +6816,7 @@ var init_manager2 = __esm({
|
|
|
6283
6816
|
);
|
|
6284
6817
|
this.storeSnapshot(updated);
|
|
6285
6818
|
this.broadcastState(updated, "state_changed");
|
|
6819
|
+
this.scheduler.refresh();
|
|
6286
6820
|
return updated;
|
|
6287
6821
|
}
|
|
6288
6822
|
async delete(id) {
|
|
@@ -6291,6 +6825,7 @@ var init_manager2 = __esm({
|
|
|
6291
6825
|
this.pendingDeletes.add(id);
|
|
6292
6826
|
this.evaluationAbortControllers.get(id)?.abort();
|
|
6293
6827
|
await this.inFlightCompletions.get(id)?.promise;
|
|
6828
|
+
this.scheduler.refresh();
|
|
6294
6829
|
return;
|
|
6295
6830
|
}
|
|
6296
6831
|
this.deleteNow(supervisor);
|
|
@@ -6324,8 +6859,8 @@ var init_manager2 = __esm({
|
|
|
6324
6859
|
* auto trigger path (scheduler) and for tests that want to observe the
|
|
6325
6860
|
* final cycle outcome.
|
|
6326
6861
|
*/
|
|
6327
|
-
async runEvaluation(supervisorId) {
|
|
6328
|
-
const started = await this.beginCycle(supervisorId,
|
|
6862
|
+
async runEvaluation(supervisorId, trigger = "turn_completed") {
|
|
6863
|
+
const started = await this.beginCycle(supervisorId, trigger);
|
|
6329
6864
|
if (!started) {
|
|
6330
6865
|
return null;
|
|
6331
6866
|
}
|
|
@@ -6369,9 +6904,41 @@ var init_manager2 = __esm({
|
|
|
6369
6904
|
}
|
|
6370
6905
|
return null;
|
|
6371
6906
|
}
|
|
6372
|
-
if (
|
|
6907
|
+
if (supervisor.state === "stopped") {
|
|
6908
|
+
if (trigger === "manual") {
|
|
6909
|
+
throw {
|
|
6910
|
+
code: "supervisor_stopped",
|
|
6911
|
+
message: `Supervisor ${id} is stopped`
|
|
6912
|
+
};
|
|
6913
|
+
}
|
|
6914
|
+
return null;
|
|
6915
|
+
}
|
|
6916
|
+
if ((trigger === "turn_completed" || trigger === "scheduled") && (supervisor.state !== "idle" || session.state !== "running" && session.state !== "idle")) {
|
|
6917
|
+
return null;
|
|
6918
|
+
}
|
|
6919
|
+
if (supervisor.maxSupervisionCount > 0 && supervisor.completedSupervisionCount >= supervisor.maxSupervisionCount) {
|
|
6920
|
+
const stopped = this.attachCycles(
|
|
6921
|
+
this.deps.supervisorRepo.update(id, {
|
|
6922
|
+
state: "stopped",
|
|
6923
|
+
stopReason: "max_supervision_count_reached",
|
|
6924
|
+
updatedAt: Date.now()
|
|
6925
|
+
})
|
|
6926
|
+
);
|
|
6927
|
+
this.storeSnapshot(stopped);
|
|
6928
|
+
this.broadcastState(stopped, "state_changed");
|
|
6929
|
+
this.scheduler.refresh();
|
|
6373
6930
|
return null;
|
|
6374
6931
|
}
|
|
6932
|
+
if (trigger === "turn_completed") {
|
|
6933
|
+
if (supervisor.scheduledAt !== void 0 && supervisor.scheduledAt !== null && supervisor.scheduledAt > Date.now()) {
|
|
6934
|
+
return null;
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
if (trigger === "scheduled") {
|
|
6938
|
+
if (supervisor.scheduledAt === void 0 || supervisor.scheduledAt > Date.now()) {
|
|
6939
|
+
return null;
|
|
6940
|
+
}
|
|
6941
|
+
}
|
|
6375
6942
|
if (trigger === "manual" && !INJECTABLE_SESSION_STATES.has(session.state)) {
|
|
6376
6943
|
throw {
|
|
6377
6944
|
code: "supervisor_session_not_ready",
|
|
@@ -6382,20 +6949,25 @@ var init_manager2 = __esm({
|
|
|
6382
6949
|
this.evaluationAbortControllers.set(id, new AbortController());
|
|
6383
6950
|
this.inFlightCompletions.set(id, createDeferredCompletion());
|
|
6384
6951
|
try {
|
|
6952
|
+
const retrySettings = getSupervisorRetrySettings(this.deps.settingsRepo);
|
|
6385
6953
|
const context = await this.contextBuilder.build(supervisor);
|
|
6386
6954
|
if (trigger === "turn_completed" && context.lastTurnId && context.lastTurnId === supervisor.lastEvaluatedTurnId) {
|
|
6387
6955
|
this.releaseInFlight(id);
|
|
6388
6956
|
return null;
|
|
6389
6957
|
}
|
|
6958
|
+
const shouldConsumeScheduledAt = trigger === "scheduled" || trigger === "turn_completed" && supervisor.scheduledAt !== void 0 && supervisor.scheduledAt !== null && supervisor.scheduledAt <= Date.now();
|
|
6390
6959
|
const evaluatingSupervisor = this.attachCycles(
|
|
6391
6960
|
this.deps.supervisorRepo.update(supervisor.id, {
|
|
6392
6961
|
state: "evaluating",
|
|
6962
|
+
scheduledAt: shouldConsumeScheduledAt ? null : supervisor.scheduledAt ?? void 0,
|
|
6963
|
+
stopReason: null,
|
|
6393
6964
|
errorReason: null,
|
|
6394
6965
|
updatedAt: Date.now()
|
|
6395
6966
|
})
|
|
6396
6967
|
);
|
|
6397
6968
|
this.storeSnapshot(evaluatingSupervisor);
|
|
6398
6969
|
this.broadcastState(evaluatingSupervisor, "state_changed");
|
|
6970
|
+
this.scheduler.refresh();
|
|
6399
6971
|
const activeCycle = this.deps.cycleRepo.create({
|
|
6400
6972
|
id: generateCycleId(),
|
|
6401
6973
|
supervisorId: supervisor.id,
|
|
@@ -6409,7 +6981,18 @@ var init_manager2 = __esm({
|
|
|
6409
6981
|
createdAt: Date.now()
|
|
6410
6982
|
});
|
|
6411
6983
|
this.broadcastCycle(evaluatingSupervisor, activeCycle, "created");
|
|
6412
|
-
return {
|
|
6984
|
+
return {
|
|
6985
|
+
cycle: activeCycle,
|
|
6986
|
+
context,
|
|
6987
|
+
trigger,
|
|
6988
|
+
retry: {
|
|
6989
|
+
retryEnabled: retrySettings.retryEnabled,
|
|
6990
|
+
retryMaxCount: retrySettings.retryMaxCount,
|
|
6991
|
+
retryDelayMs: retrySettings.retryDelaySec * 1e3,
|
|
6992
|
+
retryOnTimeout: retrySettings.retryOnTimeout,
|
|
6993
|
+
retryOnEvaluatorError: retrySettings.retryOnEvaluatorError
|
|
6994
|
+
}
|
|
6995
|
+
};
|
|
6413
6996
|
} catch (error) {
|
|
6414
6997
|
this.releaseInFlight(id);
|
|
6415
6998
|
this.markSupervisorError(id, error);
|
|
@@ -6426,75 +7009,20 @@ var init_manager2 = __esm({
|
|
|
6426
7009
|
const supervisorId = activeCycle.supervisorId;
|
|
6427
7010
|
try {
|
|
6428
7011
|
const supervisorForEval = this.supervisors.get(supervisorId) ?? this.requireSupervisor(supervisorId);
|
|
6429
|
-
const
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
let injected = false;
|
|
6433
|
-
let injectedText;
|
|
6434
|
-
let cycleResult;
|
|
6435
|
-
let injectionError;
|
|
6436
|
-
if (evaluation.message.trim()) {
|
|
6437
|
-
const injectingSupervisor = this.attachCycles(
|
|
6438
|
-
this.deps.supervisorRepo.update(supervisorId, {
|
|
6439
|
-
state: "injecting",
|
|
6440
|
-
updatedAt: Date.now()
|
|
6441
|
-
})
|
|
6442
|
-
);
|
|
6443
|
-
this.storeSnapshot(injectingSupervisor);
|
|
6444
|
-
this.broadcastState(injectingSupervisor, "state_changed");
|
|
6445
|
-
const recentCycles = this.deps.cycleRepo.listRecentForSupervisor(supervisorId, this.config.guidanceDedupeWindow + 1).filter((cycle) => cycle.id !== activeCycle.id);
|
|
6446
|
-
try {
|
|
6447
|
-
const injection = await this.injector.inject(
|
|
6448
|
-
injectingSupervisor,
|
|
6449
|
-
{
|
|
6450
|
-
message: evaluation.message
|
|
6451
|
-
},
|
|
6452
|
-
recentCycles
|
|
6453
|
-
);
|
|
6454
|
-
injected = injection.injected;
|
|
6455
|
-
injectedText = injection.injected ? injection.text : void 0;
|
|
6456
|
-
cycleResult = injection.injected ? injection.text : `Skipped duplicate: ${injection.text}`;
|
|
6457
|
-
} catch (error) {
|
|
6458
|
-
injectionError = messageOf(error, "Injection failed");
|
|
6459
|
-
this.logger.warn(
|
|
6460
|
-
{ err: error, supervisorId, cycleId: activeCycle.id },
|
|
6461
|
-
"Supervisor injection failed"
|
|
6462
|
-
);
|
|
6463
|
-
}
|
|
6464
|
-
}
|
|
6465
|
-
const finalStatus = injectionError ? "failed" : injected ? "injected" : "completed";
|
|
6466
|
-
const finishedCycle = this.deps.cycleRepo.update(activeCycle.id, {
|
|
6467
|
-
status: finalStatus,
|
|
6468
|
-
result: cycleResult ?? null,
|
|
6469
|
-
injectedGuidance: injectedText,
|
|
6470
|
-
errorReason: injectionError ?? null,
|
|
6471
|
-
completedAt: Date.now()
|
|
6472
|
-
});
|
|
6473
|
-
const latestState = this.supervisors.get(supervisorId)?.state;
|
|
6474
|
-
const nextState = latestState === "paused" ? "paused" : injectionError ? "error" : "idle";
|
|
6475
|
-
const finishedSupervisor = this.attachCycles(
|
|
6476
|
-
this.deps.supervisorRepo.update(supervisorId, {
|
|
6477
|
-
state: nextState,
|
|
6478
|
-
lastCycleAt: finishedCycle.completedAt,
|
|
6479
|
-
lastEvaluatedTurnId: context.lastTurnId ?? void 0,
|
|
6480
|
-
errorReason: injectionError ?? null,
|
|
6481
|
-
updatedAt: Date.now()
|
|
6482
|
-
})
|
|
6483
|
-
);
|
|
6484
|
-
this.storeSnapshot(finishedSupervisor);
|
|
6485
|
-
this.broadcastCycle(finishedSupervisor, finishedCycle, "updated");
|
|
6486
|
-
this.broadcastState(finishedSupervisor, "state_changed");
|
|
6487
|
-
this.deps.cycleRepo.pruneOldest(supervisorId, this.config.maxCyclesPerSession);
|
|
7012
|
+
const signal = this.evaluationAbortControllers.get(supervisorId)?.signal;
|
|
7013
|
+
const evaluation = await this.executeCycleWithRetry(started, supervisorForEval, signal);
|
|
7014
|
+
const finalized = this.finalizeSuccessfulCycle(activeCycle, context, evaluation);
|
|
6488
7015
|
if (this.pendingDeletes.has(supervisorId)) {
|
|
6489
7016
|
this.pendingDeletes.delete(supervisorId);
|
|
6490
|
-
this.deleteNow(
|
|
7017
|
+
this.deleteNow(finalized.supervisor);
|
|
6491
7018
|
}
|
|
6492
|
-
return
|
|
7019
|
+
return finalized.cycle;
|
|
6493
7020
|
} catch (error) {
|
|
6494
7021
|
if (isSupervisorEvalAborted(error)) {
|
|
7022
|
+
const cancelled = this.pendingPauses.has(supervisorId);
|
|
6495
7023
|
const abortedCycle = this.deps.cycleRepo.update(activeCycle.id, {
|
|
6496
|
-
status: "failed",
|
|
6497
|
-
errorReason: messageOf(error, "Supervisor evaluator aborted"),
|
|
7024
|
+
status: cancelled ? "cancelled" : "failed",
|
|
7025
|
+
errorReason: cancelled ? null : messageOf(error, "Supervisor evaluator aborted"),
|
|
6498
7026
|
completedAt: Date.now()
|
|
6499
7027
|
});
|
|
6500
7028
|
const currentSupervisor = this.supervisors.get(supervisorId) ?? this.requireSupervisor(supervisorId);
|
|
@@ -6505,10 +7033,11 @@ var init_manager2 = __esm({
|
|
|
6505
7033
|
return abortedCycle;
|
|
6506
7034
|
}
|
|
6507
7035
|
const latestState = this.supervisors.get(supervisorId)?.state;
|
|
6508
|
-
const nextState = latestState === "paused" ? "paused" : "idle";
|
|
7036
|
+
const nextState = cancelled || latestState === "paused" ? "paused" : "idle";
|
|
6509
7037
|
const recoveredSupervisor = this.attachCycles(
|
|
6510
7038
|
this.deps.supervisorRepo.update(supervisorId, {
|
|
6511
7039
|
state: nextState,
|
|
7040
|
+
stopReason: null,
|
|
6512
7041
|
errorReason: null,
|
|
6513
7042
|
updatedAt: Date.now()
|
|
6514
7043
|
})
|
|
@@ -6517,6 +7046,8 @@ var init_manager2 = __esm({
|
|
|
6517
7046
|
this.broadcastCycle(recoveredSupervisor, abortedCycle, "updated");
|
|
6518
7047
|
this.broadcastState(recoveredSupervisor, "state_changed");
|
|
6519
7048
|
this.deps.cycleRepo.pruneOldest(supervisorId, this.config.maxCyclesPerSession);
|
|
7049
|
+
this.scheduler.refresh();
|
|
7050
|
+
this.pendingPauses.delete(supervisorId);
|
|
6520
7051
|
return abortedCycle;
|
|
6521
7052
|
}
|
|
6522
7053
|
logFailure(
|
|
@@ -6534,6 +7065,7 @@ var init_manager2 = __esm({
|
|
|
6534
7065
|
const failedSupervisor = this.attachCycles(
|
|
6535
7066
|
this.deps.supervisorRepo.update(supervisorId, {
|
|
6536
7067
|
state: "error",
|
|
7068
|
+
stopReason: null,
|
|
6537
7069
|
errorReason: reason,
|
|
6538
7070
|
updatedAt: Date.now()
|
|
6539
7071
|
})
|
|
@@ -6547,9 +7079,122 @@ var init_manager2 = __esm({
|
|
|
6547
7079
|
}
|
|
6548
7080
|
throw error;
|
|
6549
7081
|
} finally {
|
|
7082
|
+
this.pendingPauses.delete(supervisorId);
|
|
6550
7083
|
this.releaseInFlight(supervisorId);
|
|
6551
7084
|
}
|
|
6552
7085
|
}
|
|
7086
|
+
async executeCycleWithRetry(started, supervisor, signal) {
|
|
7087
|
+
for (let attemptIndex = 0; ; attemptIndex += 1) {
|
|
7088
|
+
const attempt = this.deps.cycleAttemptRepo.create({
|
|
7089
|
+
id: generateAttemptId(),
|
|
7090
|
+
cycleId: started.cycle.id,
|
|
7091
|
+
attemptIndex,
|
|
7092
|
+
status: "evaluating",
|
|
7093
|
+
startedAt: Date.now()
|
|
7094
|
+
});
|
|
7095
|
+
try {
|
|
7096
|
+
const evaluation = await this.evaluator.evaluate(supervisor, started.context, { signal });
|
|
7097
|
+
this.deps.cycleAttemptRepo.update(attempt.id, {
|
|
7098
|
+
status: "completed",
|
|
7099
|
+
completedAt: Date.now(),
|
|
7100
|
+
providerModel: supervisor.evaluatorModel ?? null
|
|
7101
|
+
});
|
|
7102
|
+
if (evaluation.objectiveComplete) {
|
|
7103
|
+
return {
|
|
7104
|
+
objectiveComplete: true,
|
|
7105
|
+
injected: false,
|
|
7106
|
+
cycleResult: evaluation.message
|
|
7107
|
+
};
|
|
7108
|
+
}
|
|
7109
|
+
if (!evaluation.message.trim()) {
|
|
7110
|
+
return {
|
|
7111
|
+
objectiveComplete: false,
|
|
7112
|
+
injected: false
|
|
7113
|
+
};
|
|
7114
|
+
}
|
|
7115
|
+
if (signal?.aborted || this.pendingPauses.has(supervisor.id)) {
|
|
7116
|
+
throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
|
|
7117
|
+
}
|
|
7118
|
+
const injectingSupervisor = this.attachCycles(
|
|
7119
|
+
this.deps.supervisorRepo.update(supervisor.id, {
|
|
7120
|
+
state: "injecting",
|
|
7121
|
+
updatedAt: Date.now()
|
|
7122
|
+
})
|
|
7123
|
+
);
|
|
7124
|
+
this.storeSnapshot(injectingSupervisor);
|
|
7125
|
+
this.broadcastState(injectingSupervisor, "state_changed");
|
|
7126
|
+
const recentCycles = this.deps.cycleRepo.listRecentForSupervisor(supervisor.id, this.config.guidanceDedupeWindow + 1).filter((cycle) => cycle.id !== started.cycle.id);
|
|
7127
|
+
const injection = await this.injector.inject(
|
|
7128
|
+
injectingSupervisor,
|
|
7129
|
+
{
|
|
7130
|
+
message: evaluation.message
|
|
7131
|
+
},
|
|
7132
|
+
recentCycles,
|
|
7133
|
+
{ signal }
|
|
7134
|
+
);
|
|
7135
|
+
return {
|
|
7136
|
+
objectiveComplete: false,
|
|
7137
|
+
injected: injection.injected,
|
|
7138
|
+
injectedText: injection.injected ? injection.text : void 0,
|
|
7139
|
+
cycleResult: injection.injected ? injection.text : `Skipped duplicate: ${injection.text}`
|
|
7140
|
+
};
|
|
7141
|
+
} catch (error) {
|
|
7142
|
+
if (isSupervisorEvalAborted(error)) {
|
|
7143
|
+
this.deps.cycleAttemptRepo.update(attempt.id, {
|
|
7144
|
+
status: this.pendingPauses.has(supervisor.id) ? "cancelled" : "failed",
|
|
7145
|
+
completedAt: Date.now(),
|
|
7146
|
+
errorReason: this.pendingPauses.has(supervisor.id) ? null : messageOf(error, "Supervisor evaluator aborted")
|
|
7147
|
+
});
|
|
7148
|
+
throw error;
|
|
7149
|
+
}
|
|
7150
|
+
const reason = messageOf(error, "Supervisor evaluation failed");
|
|
7151
|
+
this.deps.cycleAttemptRepo.update(attempt.id, {
|
|
7152
|
+
status: "failed",
|
|
7153
|
+
completedAt: Date.now(),
|
|
7154
|
+
errorReason: reason
|
|
7155
|
+
});
|
|
7156
|
+
if (!this.shouldRetryAttempt(error, attemptIndex, started.retry)) {
|
|
7157
|
+
throw error;
|
|
7158
|
+
}
|
|
7159
|
+
await this.sleep(started.retry.retryDelayMs, signal);
|
|
7160
|
+
const evaluatingSupervisor = this.attachCycles(
|
|
7161
|
+
this.deps.supervisorRepo.update(supervisor.id, {
|
|
7162
|
+
state: "evaluating",
|
|
7163
|
+
updatedAt: Date.now()
|
|
7164
|
+
})
|
|
7165
|
+
);
|
|
7166
|
+
this.storeSnapshot(evaluatingSupervisor);
|
|
7167
|
+
this.broadcastState(evaluatingSupervisor, "state_changed");
|
|
7168
|
+
}
|
|
7169
|
+
}
|
|
7170
|
+
}
|
|
7171
|
+
finalizeSuccessfulCycle(activeCycle, context, result) {
|
|
7172
|
+
const finalStatus = result.injected ? "injected" : result.objectiveComplete ? "completed" : "completed";
|
|
7173
|
+
const finishedCycle = this.deps.cycleRepo.update(activeCycle.id, {
|
|
7174
|
+
status: finalStatus,
|
|
7175
|
+
result: result.cycleResult ?? null,
|
|
7176
|
+
injectedGuidance: result.injectedText ?? null,
|
|
7177
|
+
errorReason: null,
|
|
7178
|
+
completedAt: Date.now()
|
|
7179
|
+
});
|
|
7180
|
+
const finishedSupervisor = this.attachCycles(
|
|
7181
|
+
this.deps.supervisorRepo.update(activeCycle.supervisorId, {
|
|
7182
|
+
state: result.objectiveComplete ? "stopped" : "idle",
|
|
7183
|
+
completedSupervisionCount: (this.supervisors.get(activeCycle.supervisorId)?.completedSupervisionCount ?? 0) + 1,
|
|
7184
|
+
stopReason: result.objectiveComplete ? "objective_complete" : null,
|
|
7185
|
+
lastCycleAt: finishedCycle.completedAt,
|
|
7186
|
+
lastEvaluatedTurnId: context.lastTurnId ?? void 0,
|
|
7187
|
+
errorReason: null,
|
|
7188
|
+
updatedAt: Date.now()
|
|
7189
|
+
})
|
|
7190
|
+
);
|
|
7191
|
+
this.storeSnapshot(finishedSupervisor);
|
|
7192
|
+
this.broadcastCycle(finishedSupervisor, finishedCycle, "updated");
|
|
7193
|
+
this.broadcastState(finishedSupervisor, "state_changed");
|
|
7194
|
+
this.deps.cycleRepo.pruneOldest(activeCycle.supervisorId, this.config.maxCyclesPerSession);
|
|
7195
|
+
this.scheduler.refresh();
|
|
7196
|
+
return { cycle: finishedCycle, supervisor: finishedSupervisor };
|
|
7197
|
+
}
|
|
6553
7198
|
/**
|
|
6554
7199
|
* Flip a supervisor to 'error' state when something blows up before we
|
|
6555
7200
|
* had a chance to create a cycle. Without this the supervisor can get
|
|
@@ -6615,6 +7260,14 @@ var init_manager2 = __esm({
|
|
|
6615
7260
|
cycles: this.deps.cycleRepo.listRecentForSupervisor(supervisor.id, 20)
|
|
6616
7261
|
};
|
|
6617
7262
|
}
|
|
7263
|
+
listScheduledSupervisors() {
|
|
7264
|
+
return Array.from(this.supervisors.values()).filter(
|
|
7265
|
+
(supervisor) => supervisor.state === "idle" && typeof supervisor.scheduledAt === "number" && Number.isFinite(supervisor.scheduledAt)
|
|
7266
|
+
).map((supervisor) => ({
|
|
7267
|
+
supervisorId: supervisor.id,
|
|
7268
|
+
scheduledAt: supervisor.scheduledAt
|
|
7269
|
+
}));
|
|
7270
|
+
}
|
|
6618
7271
|
storeSnapshot(supervisor) {
|
|
6619
7272
|
this.supervisors.set(supervisor.id, supervisor);
|
|
6620
7273
|
this.supervisorsBySession.set(supervisor.sessionId, supervisor.id);
|
|
@@ -6624,7 +7277,9 @@ var init_manager2 = __esm({
|
|
|
6624
7277
|
this.supervisors.delete(supervisor.id);
|
|
6625
7278
|
this.supervisorsBySession.delete(supervisor.sessionId);
|
|
6626
7279
|
this.pendingDeletes.delete(supervisor.id);
|
|
7280
|
+
this.pendingPauses.delete(supervisor.id);
|
|
6627
7281
|
this.releaseInFlight(supervisor.id);
|
|
7282
|
+
this.scheduler.refresh();
|
|
6628
7283
|
this.deps.broadcaster.broadcast(
|
|
6629
7284
|
Topics.supervisorState(supervisor.workspaceId, supervisor.sessionId),
|
|
6630
7285
|
{ supervisorId: supervisor.id, event: "deleted" }
|
|
@@ -6658,6 +7313,43 @@ var init_manager2 = __esm({
|
|
|
6658
7313
|
{ cycle, event }
|
|
6659
7314
|
);
|
|
6660
7315
|
}
|
|
7316
|
+
shouldRetryAttempt(error, attemptIndex, retry) {
|
|
7317
|
+
if (!retry.retryEnabled) {
|
|
7318
|
+
return false;
|
|
7319
|
+
}
|
|
7320
|
+
if (attemptIndex >= retry.retryMaxCount) {
|
|
7321
|
+
return false;
|
|
7322
|
+
}
|
|
7323
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
7324
|
+
if (code === "supervisor_eval_timeout") {
|
|
7325
|
+
return retry.retryOnTimeout;
|
|
7326
|
+
}
|
|
7327
|
+
if (code === "supervisor_eval_failed") {
|
|
7328
|
+
return retry.retryOnEvaluatorError;
|
|
7329
|
+
}
|
|
7330
|
+
return false;
|
|
7331
|
+
}
|
|
7332
|
+
async sleep(delayMs, signal) {
|
|
7333
|
+
if (delayMs <= 0) {
|
|
7334
|
+
return;
|
|
7335
|
+
}
|
|
7336
|
+
if (signal?.aborted) {
|
|
7337
|
+
throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
|
|
7338
|
+
}
|
|
7339
|
+
await new Promise((resolve4, reject) => {
|
|
7340
|
+
const timer = setTimeout(() => {
|
|
7341
|
+
signal?.removeEventListener("abort", onAbort);
|
|
7342
|
+
resolve4();
|
|
7343
|
+
}, delayMs);
|
|
7344
|
+
timer.unref?.();
|
|
7345
|
+
const onAbort = () => {
|
|
7346
|
+
clearTimeout(timer);
|
|
7347
|
+
signal?.removeEventListener("abort", onAbort);
|
|
7348
|
+
reject({ code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" });
|
|
7349
|
+
};
|
|
7350
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
7351
|
+
});
|
|
7352
|
+
}
|
|
6661
7353
|
};
|
|
6662
7354
|
}
|
|
6663
7355
|
});
|
|
@@ -7559,6 +8251,7 @@ var init_watcher = __esm({
|
|
|
7559
8251
|
dirtyTimer = null;
|
|
7560
8252
|
firstDirtyTime = null;
|
|
7561
8253
|
pendingReason = null;
|
|
8254
|
+
pendingWorktreeChanged = false;
|
|
7562
8255
|
DEBOUNCE_MS = 200;
|
|
7563
8256
|
MAX_WAIT_MS = 1e3;
|
|
7564
8257
|
/**
|
|
@@ -7571,6 +8264,9 @@ var init_watcher = __esm({
|
|
|
7571
8264
|
if (this.firstDirtyTime === null) {
|
|
7572
8265
|
this.firstDirtyTime = now;
|
|
7573
8266
|
}
|
|
8267
|
+
if (changedPath && this.isWorktreeMetadataPath(changedPath)) {
|
|
8268
|
+
this.pendingWorktreeChanged = true;
|
|
8269
|
+
}
|
|
7574
8270
|
if (changedPath && !this.isGitMetadataPath(changedPath)) {
|
|
7575
8271
|
this.pendingReason = "fs_change";
|
|
7576
8272
|
} else if (changedPath && this.pendingReason !== "fs_change") {
|
|
@@ -7589,13 +8285,23 @@ var init_watcher = __esm({
|
|
|
7589
8285
|
this.broadcaster?.broadcast(Topics.workspaceFsDirty(this.workspaceId), {
|
|
7590
8286
|
reason: this.pendingReason ?? "fs_change"
|
|
7591
8287
|
});
|
|
8288
|
+
if (this.pendingWorktreeChanged) {
|
|
8289
|
+
this.broadcaster?.broadcast(Topics.workspaceGitState(this.workspaceId), {
|
|
8290
|
+
worktreeChanged: true
|
|
8291
|
+
});
|
|
8292
|
+
}
|
|
7592
8293
|
this.dirtyTimer = null;
|
|
7593
8294
|
this.firstDirtyTime = null;
|
|
7594
8295
|
this.pendingReason = null;
|
|
8296
|
+
this.pendingWorktreeChanged = false;
|
|
7595
8297
|
}
|
|
7596
8298
|
isGitMetadataPath(changedPath) {
|
|
7597
8299
|
return changedPath.replace(/\\/g, "/").includes("/.git/");
|
|
7598
8300
|
}
|
|
8301
|
+
isWorktreeMetadataPath(changedPath) {
|
|
8302
|
+
const normalized = changedPath.replace(/\\/g, "/");
|
|
8303
|
+
return normalized.includes("/.git/worktrees");
|
|
8304
|
+
}
|
|
7599
8305
|
/**
|
|
7600
8306
|
* Stops watching and cleans up resources.
|
|
7601
8307
|
*/
|
|
@@ -7815,17 +8521,93 @@ var init_manager4 = __esm({
|
|
|
7815
8521
|
uiState: JSON.parse(row.ui_state)
|
|
7816
8522
|
};
|
|
7817
8523
|
}
|
|
7818
|
-
/**
|
|
7819
|
-
* Updates workspace last active timestamp.
|
|
7820
|
-
*
|
|
7821
|
-
* @param workspaceId - Workspace ID
|
|
7822
|
-
*/
|
|
7823
|
-
touch(workspaceId) {
|
|
7824
|
-
const now = Date.now();
|
|
7825
|
-
this.deps.db.prepare("UPDATE workspaces SET last_active_at = ? WHERE id = ?").run(now, workspaceId);
|
|
8524
|
+
/**
|
|
8525
|
+
* Updates workspace last active timestamp.
|
|
8526
|
+
*
|
|
8527
|
+
* @param workspaceId - Workspace ID
|
|
8528
|
+
*/
|
|
8529
|
+
touch(workspaceId) {
|
|
8530
|
+
const now = Date.now();
|
|
8531
|
+
this.deps.db.prepare("UPDATE workspaces SET last_active_at = ? WHERE id = ?").run(now, workspaceId);
|
|
8532
|
+
}
|
|
8533
|
+
recordFetch(workspaceId) {
|
|
8534
|
+
this.deps.autoFetch?.recordSuccess(workspaceId);
|
|
8535
|
+
}
|
|
8536
|
+
};
|
|
8537
|
+
}
|
|
8538
|
+
});
|
|
8539
|
+
|
|
8540
|
+
// packages/server/src/ws/activation.ts
|
|
8541
|
+
var DEFAULT_OPTIONS, ActivationManager;
|
|
8542
|
+
var init_activation = __esm({
|
|
8543
|
+
"packages/server/src/ws/activation.ts"() {
|
|
8544
|
+
"use strict";
|
|
8545
|
+
DEFAULT_OPTIONS = {
|
|
8546
|
+
graceMs: 3e3
|
|
8547
|
+
};
|
|
8548
|
+
ActivationManager = class {
|
|
8549
|
+
options;
|
|
8550
|
+
lease = null;
|
|
8551
|
+
generation = 0;
|
|
8552
|
+
constructor(options) {
|
|
8553
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
8554
|
+
}
|
|
8555
|
+
claim(clientInstanceId, wsClientId, request) {
|
|
8556
|
+
const now = Date.now();
|
|
8557
|
+
const activeLease = this.getLease();
|
|
8558
|
+
if (activeLease && activeLease.clientInstanceId === clientInstanceId) {
|
|
8559
|
+
const isGraceRecovery = activeLease.graceUntil !== null && now <= activeLease.graceUntil;
|
|
8560
|
+
const displacedWsClientId2 = isGraceRecovery || activeLease.wsClientId === wsClientId ? null : activeLease.wsClientId;
|
|
8561
|
+
activeLease.wsClientId = wsClientId;
|
|
8562
|
+
activeLease.graceUntil = null;
|
|
8563
|
+
return {
|
|
8564
|
+
active: true,
|
|
8565
|
+
generation: activeLease.generation,
|
|
8566
|
+
recoveryMode: "grace_recover",
|
|
8567
|
+
displacedWsClientId: displacedWsClientId2
|
|
8568
|
+
};
|
|
8569
|
+
}
|
|
8570
|
+
const displacedWsClientId = activeLease && activeLease.clientInstanceId !== clientInstanceId ? activeLease.wsClientId : null;
|
|
8571
|
+
const recoveryMode = displacedWsClientId === null ? "fresh" : "takeover";
|
|
8572
|
+
this.generation += 1;
|
|
8573
|
+
this.lease = {
|
|
8574
|
+
clientInstanceId,
|
|
8575
|
+
wsClientId,
|
|
8576
|
+
generation: this.generation,
|
|
8577
|
+
issuedAt: now,
|
|
8578
|
+
graceUntil: null,
|
|
8579
|
+
ip: request.ip,
|
|
8580
|
+
userAgent: request.headers["user-agent"] ?? ""
|
|
8581
|
+
};
|
|
8582
|
+
return {
|
|
8583
|
+
active: true,
|
|
8584
|
+
generation: this.lease.generation,
|
|
8585
|
+
recoveryMode,
|
|
8586
|
+
displacedWsClientId
|
|
8587
|
+
};
|
|
8588
|
+
}
|
|
8589
|
+
release(clientInstanceId, generation) {
|
|
8590
|
+
const lease = this.getLease();
|
|
8591
|
+
if (!lease) {
|
|
8592
|
+
return;
|
|
8593
|
+
}
|
|
8594
|
+
if (lease.clientInstanceId !== clientInstanceId || lease.generation !== generation) {
|
|
8595
|
+
return;
|
|
8596
|
+
}
|
|
8597
|
+
this.lease = null;
|
|
7826
8598
|
}
|
|
7827
|
-
|
|
7828
|
-
this.
|
|
8599
|
+
onSocketClosed(wsClientId) {
|
|
8600
|
+
const lease = this.getLease();
|
|
8601
|
+
if (!lease || lease.wsClientId !== wsClientId) {
|
|
8602
|
+
return;
|
|
8603
|
+
}
|
|
8604
|
+
lease.graceUntil = Date.now() + this.options.graceMs;
|
|
8605
|
+
}
|
|
8606
|
+
getLease() {
|
|
8607
|
+
if (!this.lease) {
|
|
8608
|
+
return null;
|
|
8609
|
+
}
|
|
8610
|
+
return this.lease;
|
|
7829
8611
|
}
|
|
7830
8612
|
};
|
|
7831
8613
|
}
|
|
@@ -7837,6 +8619,21 @@ function registerCommand(op, schema, handler) {
|
|
|
7837
8619
|
schemas.set(op, schema);
|
|
7838
8620
|
}
|
|
7839
8621
|
async function dispatch(msg, ctx, clientId) {
|
|
8622
|
+
const isWsDispatch = clientId !== void 0 && typeof ctx.broadcaster.getRequestMetadata === "function";
|
|
8623
|
+
if (isWsDispatch && !ACTIVATION_ALLOWLIST.has(msg.op)) {
|
|
8624
|
+
const active = ctx.activationMgr.getLease();
|
|
8625
|
+
if (!active || active.wsClientId !== clientId) {
|
|
8626
|
+
return {
|
|
8627
|
+
kind: "result",
|
|
8628
|
+
id: msg.id,
|
|
8629
|
+
ok: false,
|
|
8630
|
+
error: {
|
|
8631
|
+
code: "activation_required",
|
|
8632
|
+
message: "This tab is no longer the active session"
|
|
8633
|
+
}
|
|
8634
|
+
};
|
|
8635
|
+
}
|
|
8636
|
+
}
|
|
7840
8637
|
const handler = handlers.get(msg.op);
|
|
7841
8638
|
if (!handler) {
|
|
7842
8639
|
return {
|
|
@@ -7893,21 +8690,26 @@ function normalizeError(error) {
|
|
|
7893
8690
|
message: candidate.message || "An internal error occurred"
|
|
7894
8691
|
};
|
|
7895
8692
|
}
|
|
7896
|
-
var handlers, schemas;
|
|
8693
|
+
var handlers, schemas, ACTIVATION_ALLOWLIST;
|
|
7897
8694
|
var init_dispatch = __esm({
|
|
7898
8695
|
"packages/server/src/ws/dispatch.ts"() {
|
|
7899
8696
|
"use strict";
|
|
7900
8697
|
handlers = /* @__PURE__ */ new Map();
|
|
7901
8698
|
schemas = /* @__PURE__ */ new Map();
|
|
8699
|
+
ACTIVATION_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
8700
|
+
"activation.claim",
|
|
8701
|
+
"activation.release",
|
|
8702
|
+
"connection.probe"
|
|
8703
|
+
]);
|
|
7902
8704
|
}
|
|
7903
8705
|
});
|
|
7904
8706
|
|
|
7905
8707
|
// packages/server/src/ws/fencing.ts
|
|
7906
|
-
var
|
|
8708
|
+
var DEFAULT_OPTIONS2, FencingManager;
|
|
7907
8709
|
var init_fencing = __esm({
|
|
7908
8710
|
"packages/server/src/ws/fencing.ts"() {
|
|
7909
8711
|
"use strict";
|
|
7910
|
-
|
|
8712
|
+
DEFAULT_OPTIONS2 = {
|
|
7911
8713
|
visibleHeartbeatMs: 1e4,
|
|
7912
8714
|
// 10 seconds
|
|
7913
8715
|
hiddenHeartbeatMs: 2e4,
|
|
@@ -7926,7 +8728,7 @@ var init_fencing = __esm({
|
|
|
7926
8728
|
// workspaceId -> { clientId, closedAt, ip, ua } (for grace period)
|
|
7927
8729
|
lastWriter = /* @__PURE__ */ new Map();
|
|
7928
8730
|
constructor(options) {
|
|
7929
|
-
this.options = { ...
|
|
8731
|
+
this.options = { ...DEFAULT_OPTIONS2, ...options };
|
|
7930
8732
|
}
|
|
7931
8733
|
/**
|
|
7932
8734
|
* Request controller status for a workspace.
|
|
@@ -8500,6 +9302,20 @@ var init_client = __esm({
|
|
|
8500
9302
|
return false;
|
|
8501
9303
|
}
|
|
8502
9304
|
}
|
|
9305
|
+
sendControlAndClose(msg, code, reason) {
|
|
9306
|
+
if (this.socket.readyState !== WebSocket.OPEN) {
|
|
9307
|
+
return false;
|
|
9308
|
+
}
|
|
9309
|
+
try {
|
|
9310
|
+
this.socket.send(JSON.stringify(msg), () => {
|
|
9311
|
+
this.socket.close(code, reason);
|
|
9312
|
+
});
|
|
9313
|
+
return true;
|
|
9314
|
+
} catch (error) {
|
|
9315
|
+
console.error(`Failed to send message to client ${this.id}:`, error);
|
|
9316
|
+
return false;
|
|
9317
|
+
}
|
|
9318
|
+
}
|
|
8503
9319
|
sendBinary(data) {
|
|
8504
9320
|
if (this.socket.readyState !== WebSocket.OPEN) {
|
|
8505
9321
|
return false;
|
|
@@ -8664,6 +9480,16 @@ var init_client = __esm({
|
|
|
8664
9480
|
};
|
|
8665
9481
|
return this.send(event);
|
|
8666
9482
|
}
|
|
9483
|
+
sendEventAndClose(topic, data, code, reason, seq = 0) {
|
|
9484
|
+
const event = {
|
|
9485
|
+
kind: "event",
|
|
9486
|
+
topic,
|
|
9487
|
+
seq,
|
|
9488
|
+
timestamp: Date.now(),
|
|
9489
|
+
data
|
|
9490
|
+
};
|
|
9491
|
+
return this.sendControlAndClose(event, code, reason);
|
|
9492
|
+
}
|
|
8667
9493
|
/**
|
|
8668
9494
|
* Check if client subscribes to a topic (supports glob patterns)
|
|
8669
9495
|
*/
|
|
@@ -8773,6 +9599,7 @@ var init_hub = __esm({
|
|
|
8773
9599
|
}
|
|
8774
9600
|
deps;
|
|
8775
9601
|
clients = /* @__PURE__ */ new Map();
|
|
9602
|
+
clientRequests = /* @__PURE__ */ new Map();
|
|
8776
9603
|
eventUnsubscribers = [];
|
|
8777
9604
|
nextStreamId = 1;
|
|
8778
9605
|
// Per-client queue of waiters for the next inbound binary frame. The
|
|
@@ -8789,9 +9616,10 @@ var init_hub = __esm({
|
|
|
8789
9616
|
/**
|
|
8790
9617
|
* Handle a new WebSocket connection
|
|
8791
9618
|
*/
|
|
8792
|
-
handleConnection(socket,
|
|
9619
|
+
handleConnection(socket, req) {
|
|
8793
9620
|
const client = new WsClient(socket, uuidv4(), this.deps.logger);
|
|
8794
9621
|
this.clients.set(client.id, client);
|
|
9622
|
+
this.clientRequests.set(client.id, req);
|
|
8795
9623
|
client.sendEvent("connection.status", {
|
|
8796
9624
|
status: "connected",
|
|
8797
9625
|
clientId: client.id,
|
|
@@ -8925,8 +9753,10 @@ var init_hub = __esm({
|
|
|
8925
9753
|
*/
|
|
8926
9754
|
handleClose(client) {
|
|
8927
9755
|
this.clients.delete(client.id);
|
|
9756
|
+
this.clientRequests.delete(client.id);
|
|
8928
9757
|
this.discardPendingBinaryWaiters(client.id);
|
|
8929
9758
|
this.deps.commandContext?.autoFetch.unregisterViewer(client.id);
|
|
9759
|
+
this.deps.commandContext?.activationMgr.onSocketClosed(client.id);
|
|
8930
9760
|
}
|
|
8931
9761
|
/**
|
|
8932
9762
|
* Takeover: Force close existing writer and accept new one
|
|
@@ -8967,6 +9797,24 @@ var init_hub = __esm({
|
|
|
8967
9797
|
if (!client) return false;
|
|
8968
9798
|
return client.sendBinary(data);
|
|
8969
9799
|
}
|
|
9800
|
+
revokeAndCloseClient(clientId, generation) {
|
|
9801
|
+
const client = this.clients.get(clientId);
|
|
9802
|
+
if (!client) {
|
|
9803
|
+
return;
|
|
9804
|
+
}
|
|
9805
|
+
client.sendEventAndClose(
|
|
9806
|
+
"activation.revoked",
|
|
9807
|
+
{
|
|
9808
|
+
reason: "displaced",
|
|
9809
|
+
generation
|
|
9810
|
+
},
|
|
9811
|
+
4001,
|
|
9812
|
+
"single_active_displaced"
|
|
9813
|
+
);
|
|
9814
|
+
}
|
|
9815
|
+
getRequestMetadata(clientId) {
|
|
9816
|
+
return this.clientRequests.get(clientId);
|
|
9817
|
+
}
|
|
8970
9818
|
/**
|
|
8971
9819
|
* Get the current writer client
|
|
8972
9820
|
* DEPRECATED: Writer tracking now handled by FencingManager
|
|
@@ -8994,6 +9842,7 @@ var init_hub = __esm({
|
|
|
8994
9842
|
client.close();
|
|
8995
9843
|
}
|
|
8996
9844
|
this.clients.clear();
|
|
9845
|
+
this.clientRequests.clear();
|
|
8997
9846
|
}
|
|
8998
9847
|
/**
|
|
8999
9848
|
* Subscribe to domain events and broadcast them
|
|
@@ -9214,10 +10063,26 @@ var init_workspace = __esm({
|
|
|
9214
10063
|
|
|
9215
10064
|
// packages/server/src/commands/workspace-activity.ts
|
|
9216
10065
|
import { z as z7 } from "zod";
|
|
10066
|
+
function parseWorkspaceLastViewedTarget(value) {
|
|
10067
|
+
try {
|
|
10068
|
+
const parsed = JSON.parse(value);
|
|
10069
|
+
const result = workspaceLastViewedTargetSchema.safeParse(parsed);
|
|
10070
|
+
return result.success ? result.data : null;
|
|
10071
|
+
} catch {
|
|
10072
|
+
return null;
|
|
10073
|
+
}
|
|
10074
|
+
}
|
|
10075
|
+
var WORKSPACE_LAST_VIEWED_TARGET_KEY, workspaceLastViewedTargetSchema;
|
|
9217
10076
|
var init_workspace_activity = __esm({
|
|
9218
10077
|
"packages/server/src/commands/workspace-activity.ts"() {
|
|
9219
10078
|
"use strict";
|
|
9220
10079
|
init_dispatch();
|
|
10080
|
+
WORKSPACE_LAST_VIEWED_TARGET_KEY = "workspace.lastViewedTarget";
|
|
10081
|
+
workspaceLastViewedTargetSchema = z7.object({
|
|
10082
|
+
workspaceId: z7.string(),
|
|
10083
|
+
sessionId: z7.string().optional(),
|
|
10084
|
+
updatedAt: z7.number()
|
|
10085
|
+
});
|
|
9221
10086
|
registerCommand(
|
|
9222
10087
|
"workspace.activate",
|
|
9223
10088
|
z7.object({
|
|
@@ -9238,16 +10103,98 @@ var init_workspace_activity = __esm({
|
|
|
9238
10103
|
ctx.autoFetch.unregisterViewer(clientId);
|
|
9239
10104
|
return {};
|
|
9240
10105
|
});
|
|
10106
|
+
registerCommand("workspace.lastViewedTarget.get", z7.object({}), async (_args, ctx) => {
|
|
10107
|
+
const row = ctx.db.prepare("SELECT value FROM user_settings WHERE key = ?").get(WORKSPACE_LAST_VIEWED_TARGET_KEY);
|
|
10108
|
+
if (!row) {
|
|
10109
|
+
return null;
|
|
10110
|
+
}
|
|
10111
|
+
return parseWorkspaceLastViewedTarget(row.value);
|
|
10112
|
+
});
|
|
10113
|
+
registerCommand(
|
|
10114
|
+
"workspace.lastViewedTarget.set",
|
|
10115
|
+
z7.object({
|
|
10116
|
+
workspaceId: z7.string(),
|
|
10117
|
+
sessionId: z7.string().optional()
|
|
10118
|
+
}),
|
|
10119
|
+
async (args, ctx) => {
|
|
10120
|
+
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10121
|
+
if (!workspace) {
|
|
10122
|
+
throw {
|
|
10123
|
+
code: "workspace_not_found",
|
|
10124
|
+
message: `Workspace not found: ${args.workspaceId}`
|
|
10125
|
+
};
|
|
10126
|
+
}
|
|
10127
|
+
const session = args.sessionId ? ctx.sessionMgr.get(args.sessionId) : void 0;
|
|
10128
|
+
const nextTarget = {
|
|
10129
|
+
workspaceId: args.workspaceId,
|
|
10130
|
+
sessionId: session && session.workspaceId === args.workspaceId ? session.id : void 0,
|
|
10131
|
+
updatedAt: Date.now()
|
|
10132
|
+
};
|
|
10133
|
+
ctx.db.prepare(
|
|
10134
|
+
`
|
|
10135
|
+
INSERT INTO user_settings (key, value)
|
|
10136
|
+
VALUES (?, ?)
|
|
10137
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
10138
|
+
`
|
|
10139
|
+
).run(WORKSPACE_LAST_VIEWED_TARGET_KEY, JSON.stringify(nextTarget));
|
|
10140
|
+
return nextTarget;
|
|
10141
|
+
}
|
|
10142
|
+
);
|
|
9241
10143
|
}
|
|
9242
10144
|
});
|
|
9243
10145
|
|
|
9244
|
-
// packages/server/src/commands/
|
|
10146
|
+
// packages/server/src/commands/activation.ts
|
|
9245
10147
|
import { z as z8 } from "zod";
|
|
10148
|
+
var init_activation2 = __esm({
|
|
10149
|
+
"packages/server/src/commands/activation.ts"() {
|
|
10150
|
+
"use strict";
|
|
10151
|
+
init_dispatch();
|
|
10152
|
+
registerCommand(
|
|
10153
|
+
"activation.claim",
|
|
10154
|
+
z8.object({ clientInstanceId: z8.string().min(1) }),
|
|
10155
|
+
async (args, ctx, clientId) => {
|
|
10156
|
+
if (!clientId) {
|
|
10157
|
+
throw {
|
|
10158
|
+
code: "activation_request_unavailable",
|
|
10159
|
+
message: "Activation claim requires websocket request metadata"
|
|
10160
|
+
};
|
|
10161
|
+
}
|
|
10162
|
+
const request = ctx.broadcaster.getRequestMetadata?.(clientId);
|
|
10163
|
+
if (!request) {
|
|
10164
|
+
throw {
|
|
10165
|
+
code: "activation_request_unavailable",
|
|
10166
|
+
message: "Activation claim requires websocket request metadata"
|
|
10167
|
+
};
|
|
10168
|
+
}
|
|
10169
|
+
const claim = ctx.activationMgr.claim(args.clientInstanceId, clientId, request);
|
|
10170
|
+
if (claim.displacedWsClientId) {
|
|
10171
|
+
ctx.broadcaster.revokeAndCloseClient?.(claim.displacedWsClientId, claim.generation);
|
|
10172
|
+
}
|
|
10173
|
+
return claim;
|
|
10174
|
+
}
|
|
10175
|
+
);
|
|
10176
|
+
registerCommand(
|
|
10177
|
+
"activation.release",
|
|
10178
|
+
z8.object({ clientInstanceId: z8.string(), generation: z8.number().int().positive() }),
|
|
10179
|
+
async (args, ctx, clientId) => {
|
|
10180
|
+
const lease = ctx.activationMgr.getLease();
|
|
10181
|
+
if (!clientId || !lease || lease.wsClientId !== clientId) {
|
|
10182
|
+
return { ok: false };
|
|
10183
|
+
}
|
|
10184
|
+
ctx.activationMgr.release(args.clientInstanceId, args.generation);
|
|
10185
|
+
return { ok: true };
|
|
10186
|
+
}
|
|
10187
|
+
);
|
|
10188
|
+
}
|
|
10189
|
+
});
|
|
10190
|
+
|
|
10191
|
+
// packages/server/src/commands/connection.ts
|
|
10192
|
+
import { z as z9 } from "zod";
|
|
9246
10193
|
var init_connection = __esm({
|
|
9247
10194
|
"packages/server/src/commands/connection.ts"() {
|
|
9248
10195
|
"use strict";
|
|
9249
10196
|
init_dispatch();
|
|
9250
|
-
registerCommand("connection.probe",
|
|
10197
|
+
registerCommand("connection.probe", z9.object({}).default({}), async () => {
|
|
9251
10198
|
return { ok: true };
|
|
9252
10199
|
});
|
|
9253
10200
|
}
|
|
@@ -9347,7 +10294,7 @@ var init_runtime_status = __esm({
|
|
|
9347
10294
|
});
|
|
9348
10295
|
|
|
9349
10296
|
// packages/server/src/commands/session.ts
|
|
9350
|
-
import { z as
|
|
10297
|
+
import { z as z10 } from "zod";
|
|
9351
10298
|
function getProviderFromRegistry(providerId, registry) {
|
|
9352
10299
|
return registry.find((provider) => provider.id === providerId);
|
|
9353
10300
|
}
|
|
@@ -9358,8 +10305,8 @@ var init_session = __esm({
|
|
|
9358
10305
|
init_dispatch();
|
|
9359
10306
|
registerCommand(
|
|
9360
10307
|
"session.list",
|
|
9361
|
-
|
|
9362
|
-
workspaceId:
|
|
10308
|
+
z10.object({
|
|
10309
|
+
workspaceId: z10.string()
|
|
9363
10310
|
}),
|
|
9364
10311
|
async (args, ctx) => {
|
|
9365
10312
|
return ctx.sessionMgr.getForWorkspace(args.workspaceId);
|
|
@@ -9367,10 +10314,10 @@ var init_session = __esm({
|
|
|
9367
10314
|
);
|
|
9368
10315
|
registerCommand(
|
|
9369
10316
|
"session.create",
|
|
9370
|
-
|
|
9371
|
-
workspaceId:
|
|
9372
|
-
providerId:
|
|
9373
|
-
draft:
|
|
10317
|
+
z10.object({
|
|
10318
|
+
workspaceId: z10.string(),
|
|
10319
|
+
providerId: z10.string(),
|
|
10320
|
+
draft: z10.string().optional()
|
|
9374
10321
|
}),
|
|
9375
10322
|
async (args, ctx) => {
|
|
9376
10323
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9404,8 +10351,8 @@ var init_session = __esm({
|
|
|
9404
10351
|
);
|
|
9405
10352
|
registerCommand(
|
|
9406
10353
|
"session.stop",
|
|
9407
|
-
|
|
9408
|
-
sessionId:
|
|
10354
|
+
z10.object({
|
|
10355
|
+
sessionId: z10.string()
|
|
9409
10356
|
}),
|
|
9410
10357
|
async (args, ctx) => {
|
|
9411
10358
|
await ctx.sessionMgr.stop(args.sessionId);
|
|
@@ -9413,8 +10360,8 @@ var init_session = __esm({
|
|
|
9413
10360
|
);
|
|
9414
10361
|
registerCommand(
|
|
9415
10362
|
"session.remove",
|
|
9416
|
-
|
|
9417
|
-
sessionId:
|
|
10363
|
+
z10.object({
|
|
10364
|
+
sessionId: z10.string()
|
|
9418
10365
|
}),
|
|
9419
10366
|
async (args, ctx) => {
|
|
9420
10367
|
const session = ctx.sessionMgr.get(args.sessionId);
|
|
@@ -9579,7 +10526,7 @@ var init_tree = __esm({
|
|
|
9579
10526
|
});
|
|
9580
10527
|
|
|
9581
10528
|
// packages/server/src/commands/file.ts
|
|
9582
|
-
import { z as
|
|
10529
|
+
import { z as z11 } from "zod";
|
|
9583
10530
|
var init_file = __esm({
|
|
9584
10531
|
"packages/server/src/commands/file.ts"() {
|
|
9585
10532
|
"use strict";
|
|
@@ -9588,9 +10535,9 @@ var init_file = __esm({
|
|
|
9588
10535
|
init_dispatch();
|
|
9589
10536
|
registerCommand(
|
|
9590
10537
|
"file.readTree",
|
|
9591
|
-
|
|
9592
|
-
workspaceId:
|
|
9593
|
-
subPath:
|
|
10538
|
+
z11.object({
|
|
10539
|
+
workspaceId: z11.string(),
|
|
10540
|
+
subPath: z11.string().optional()
|
|
9594
10541
|
}),
|
|
9595
10542
|
async (args, ctx) => {
|
|
9596
10543
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9602,10 +10549,10 @@ var init_file = __esm({
|
|
|
9602
10549
|
);
|
|
9603
10550
|
registerCommand(
|
|
9604
10551
|
"file.search",
|
|
9605
|
-
|
|
9606
|
-
workspaceId:
|
|
9607
|
-
query:
|
|
9608
|
-
limit:
|
|
10552
|
+
z11.object({
|
|
10553
|
+
workspaceId: z11.string(),
|
|
10554
|
+
query: z11.string(),
|
|
10555
|
+
limit: z11.number().int().positive().max(50).optional()
|
|
9609
10556
|
}),
|
|
9610
10557
|
async (args, ctx) => {
|
|
9611
10558
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9617,9 +10564,9 @@ var init_file = __esm({
|
|
|
9617
10564
|
);
|
|
9618
10565
|
registerCommand(
|
|
9619
10566
|
"file.read",
|
|
9620
|
-
|
|
9621
|
-
workspaceId:
|
|
9622
|
-
path:
|
|
10567
|
+
z11.object({
|
|
10568
|
+
workspaceId: z11.string(),
|
|
10569
|
+
path: z11.string()
|
|
9623
10570
|
}),
|
|
9624
10571
|
async (args, ctx) => {
|
|
9625
10572
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9631,9 +10578,9 @@ var init_file = __esm({
|
|
|
9631
10578
|
);
|
|
9632
10579
|
registerCommand(
|
|
9633
10580
|
"file.create",
|
|
9634
|
-
|
|
9635
|
-
workspaceId:
|
|
9636
|
-
path:
|
|
10581
|
+
z11.object({
|
|
10582
|
+
workspaceId: z11.string(),
|
|
10583
|
+
path: z11.string()
|
|
9637
10584
|
}),
|
|
9638
10585
|
async (args, ctx) => {
|
|
9639
10586
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9651,9 +10598,9 @@ var init_file = __esm({
|
|
|
9651
10598
|
);
|
|
9652
10599
|
registerCommand(
|
|
9653
10600
|
"file.mkdir",
|
|
9654
|
-
|
|
9655
|
-
workspaceId:
|
|
9656
|
-
path:
|
|
10601
|
+
z11.object({
|
|
10602
|
+
workspaceId: z11.string(),
|
|
10603
|
+
path: z11.string()
|
|
9657
10604
|
}),
|
|
9658
10605
|
async (args, ctx) => {
|
|
9659
10606
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9671,9 +10618,9 @@ var init_file = __esm({
|
|
|
9671
10618
|
);
|
|
9672
10619
|
registerCommand(
|
|
9673
10620
|
"file.delete",
|
|
9674
|
-
|
|
9675
|
-
workspaceId:
|
|
9676
|
-
path:
|
|
10621
|
+
z11.object({
|
|
10622
|
+
workspaceId: z11.string(),
|
|
10623
|
+
path: z11.string()
|
|
9677
10624
|
}),
|
|
9678
10625
|
async (args, ctx) => {
|
|
9679
10626
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9691,11 +10638,11 @@ var init_file = __esm({
|
|
|
9691
10638
|
);
|
|
9692
10639
|
registerCommand(
|
|
9693
10640
|
"file.write",
|
|
9694
|
-
|
|
9695
|
-
workspaceId:
|
|
9696
|
-
path:
|
|
9697
|
-
content:
|
|
9698
|
-
baseHash:
|
|
10641
|
+
z11.object({
|
|
10642
|
+
workspaceId: z11.string(),
|
|
10643
|
+
path: z11.string(),
|
|
10644
|
+
content: z11.string(),
|
|
10645
|
+
baseHash: z11.string().optional()
|
|
9699
10646
|
// For conflict detection
|
|
9700
10647
|
}),
|
|
9701
10648
|
async (args, ctx) => {
|
|
@@ -9786,7 +10733,7 @@ var init_git_events = __esm({
|
|
|
9786
10733
|
});
|
|
9787
10734
|
|
|
9788
10735
|
// packages/server/src/commands/git.ts
|
|
9789
|
-
import { z as
|
|
10736
|
+
import { z as z12 } from "zod";
|
|
9790
10737
|
async function runGitNetworkOperation(ctx, workspaceId, op) {
|
|
9791
10738
|
if (!ctx.autoFetch?.runExclusive) {
|
|
9792
10739
|
return op();
|
|
@@ -9801,16 +10748,16 @@ var init_git2 = __esm({
|
|
|
9801
10748
|
init_diff();
|
|
9802
10749
|
init_dispatch();
|
|
9803
10750
|
init_git_events();
|
|
9804
|
-
gitHttpAuthSchema =
|
|
9805
|
-
username:
|
|
9806
|
-
password:
|
|
10751
|
+
gitHttpAuthSchema = z12.object({
|
|
10752
|
+
username: z12.string(),
|
|
10753
|
+
password: z12.string()
|
|
9807
10754
|
});
|
|
9808
|
-
gitCommitRevisionSchema =
|
|
10755
|
+
gitCommitRevisionSchema = z12.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
|
|
9809
10756
|
GIT_BACKGROUND_FETCH_TIMEOUT_MS = 30 * 1e3;
|
|
9810
10757
|
registerCommand(
|
|
9811
10758
|
"git.status",
|
|
9812
|
-
|
|
9813
|
-
workspaceId:
|
|
10759
|
+
z12.object({
|
|
10760
|
+
workspaceId: z12.string()
|
|
9814
10761
|
}),
|
|
9815
10762
|
async (args, ctx) => {
|
|
9816
10763
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9822,9 +10769,9 @@ var init_git2 = __esm({
|
|
|
9822
10769
|
);
|
|
9823
10770
|
registerCommand(
|
|
9824
10771
|
"git.stage",
|
|
9825
|
-
|
|
9826
|
-
workspaceId:
|
|
9827
|
-
paths:
|
|
10772
|
+
z12.object({
|
|
10773
|
+
workspaceId: z12.string(),
|
|
10774
|
+
paths: z12.array(z12.string())
|
|
9828
10775
|
}),
|
|
9829
10776
|
async (args, ctx) => {
|
|
9830
10777
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9838,10 +10785,10 @@ var init_git2 = __esm({
|
|
|
9838
10785
|
);
|
|
9839
10786
|
registerCommand(
|
|
9840
10787
|
"git.diff",
|
|
9841
|
-
|
|
9842
|
-
workspaceId:
|
|
9843
|
-
path:
|
|
9844
|
-
staged:
|
|
10788
|
+
z12.object({
|
|
10789
|
+
workspaceId: z12.string(),
|
|
10790
|
+
path: z12.string(),
|
|
10791
|
+
staged: z12.boolean().optional()
|
|
9845
10792
|
}),
|
|
9846
10793
|
async (args, ctx) => {
|
|
9847
10794
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9855,9 +10802,9 @@ var init_git2 = __esm({
|
|
|
9855
10802
|
);
|
|
9856
10803
|
registerCommand(
|
|
9857
10804
|
"git.log",
|
|
9858
|
-
|
|
9859
|
-
workspaceId:
|
|
9860
|
-
limit:
|
|
10805
|
+
z12.object({
|
|
10806
|
+
workspaceId: z12.string(),
|
|
10807
|
+
limit: z12.number().int().min(1).max(50).optional()
|
|
9861
10808
|
}),
|
|
9862
10809
|
async (args, ctx) => {
|
|
9863
10810
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9871,8 +10818,8 @@ var init_git2 = __esm({
|
|
|
9871
10818
|
);
|
|
9872
10819
|
registerCommand(
|
|
9873
10820
|
"git.show",
|
|
9874
|
-
|
|
9875
|
-
workspaceId:
|
|
10821
|
+
z12.object({
|
|
10822
|
+
workspaceId: z12.string(),
|
|
9876
10823
|
sha: gitCommitRevisionSchema
|
|
9877
10824
|
}),
|
|
9878
10825
|
async (args, ctx) => {
|
|
@@ -9887,9 +10834,9 @@ var init_git2 = __esm({
|
|
|
9887
10834
|
);
|
|
9888
10835
|
registerCommand(
|
|
9889
10836
|
"git.unstage",
|
|
9890
|
-
|
|
9891
|
-
workspaceId:
|
|
9892
|
-
paths:
|
|
10837
|
+
z12.object({
|
|
10838
|
+
workspaceId: z12.string(),
|
|
10839
|
+
paths: z12.array(z12.string())
|
|
9893
10840
|
}),
|
|
9894
10841
|
async (args, ctx) => {
|
|
9895
10842
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9903,9 +10850,9 @@ var init_git2 = __esm({
|
|
|
9903
10850
|
);
|
|
9904
10851
|
registerCommand(
|
|
9905
10852
|
"git.discard",
|
|
9906
|
-
|
|
9907
|
-
workspaceId:
|
|
9908
|
-
paths:
|
|
10853
|
+
z12.object({
|
|
10854
|
+
workspaceId: z12.string(),
|
|
10855
|
+
paths: z12.array(z12.string())
|
|
9909
10856
|
}),
|
|
9910
10857
|
async (args, ctx) => {
|
|
9911
10858
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9921,9 +10868,9 @@ var init_git2 = __esm({
|
|
|
9921
10868
|
);
|
|
9922
10869
|
registerCommand(
|
|
9923
10870
|
"git.commit",
|
|
9924
|
-
|
|
9925
|
-
workspaceId:
|
|
9926
|
-
message:
|
|
10871
|
+
z12.object({
|
|
10872
|
+
workspaceId: z12.string(),
|
|
10873
|
+
message: z12.string()
|
|
9927
10874
|
}),
|
|
9928
10875
|
async (args, ctx) => {
|
|
9929
10876
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9940,11 +10887,11 @@ var init_git2 = __esm({
|
|
|
9940
10887
|
);
|
|
9941
10888
|
registerCommand(
|
|
9942
10889
|
"git.push",
|
|
9943
|
-
|
|
9944
|
-
workspaceId:
|
|
9945
|
-
remote:
|
|
9946
|
-
branch:
|
|
9947
|
-
force:
|
|
10890
|
+
z12.object({
|
|
10891
|
+
workspaceId: z12.string(),
|
|
10892
|
+
remote: z12.string().optional(),
|
|
10893
|
+
branch: z12.string().optional(),
|
|
10894
|
+
force: z12.boolean().optional(),
|
|
9948
10895
|
auth: gitHttpAuthSchema.optional()
|
|
9949
10896
|
}),
|
|
9950
10897
|
async (args, ctx) => {
|
|
@@ -9971,10 +10918,10 @@ var init_git2 = __esm({
|
|
|
9971
10918
|
);
|
|
9972
10919
|
registerCommand(
|
|
9973
10920
|
"git.pull",
|
|
9974
|
-
|
|
9975
|
-
workspaceId:
|
|
9976
|
-
remote:
|
|
9977
|
-
branch:
|
|
10921
|
+
z12.object({
|
|
10922
|
+
workspaceId: z12.string(),
|
|
10923
|
+
remote: z12.string().optional(),
|
|
10924
|
+
branch: z12.string().optional(),
|
|
9978
10925
|
auth: gitHttpAuthSchema.optional()
|
|
9979
10926
|
}),
|
|
9980
10927
|
async (args, ctx) => {
|
|
@@ -10002,12 +10949,12 @@ var init_git2 = __esm({
|
|
|
10002
10949
|
);
|
|
10003
10950
|
registerCommand(
|
|
10004
10951
|
"git.fetch",
|
|
10005
|
-
|
|
10006
|
-
workspaceId:
|
|
10007
|
-
remote:
|
|
10008
|
-
prune:
|
|
10952
|
+
z12.object({
|
|
10953
|
+
workspaceId: z12.string(),
|
|
10954
|
+
remote: z12.string().optional(),
|
|
10955
|
+
prune: z12.boolean().optional(),
|
|
10009
10956
|
auth: gitHttpAuthSchema.optional(),
|
|
10010
|
-
background:
|
|
10957
|
+
background: z12.boolean().optional()
|
|
10011
10958
|
}),
|
|
10012
10959
|
async (args, ctx, clientId) => {
|
|
10013
10960
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10036,10 +10983,10 @@ var init_git2 = __esm({
|
|
|
10036
10983
|
);
|
|
10037
10984
|
registerCommand(
|
|
10038
10985
|
"git.checkout",
|
|
10039
|
-
|
|
10040
|
-
workspaceId:
|
|
10041
|
-
ref:
|
|
10042
|
-
createBranch:
|
|
10986
|
+
z12.object({
|
|
10987
|
+
workspaceId: z12.string(),
|
|
10988
|
+
ref: z12.string(),
|
|
10989
|
+
createBranch: z12.boolean().optional()
|
|
10043
10990
|
}),
|
|
10044
10991
|
async (args, ctx) => {
|
|
10045
10992
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10061,10 +11008,10 @@ var init_git2 = __esm({
|
|
|
10061
11008
|
);
|
|
10062
11009
|
registerCommand(
|
|
10063
11010
|
"git.branch",
|
|
10064
|
-
|
|
10065
|
-
workspaceId:
|
|
10066
|
-
name:
|
|
10067
|
-
startPoint:
|
|
11011
|
+
z12.object({
|
|
11012
|
+
workspaceId: z12.string(),
|
|
11013
|
+
name: z12.string(),
|
|
11014
|
+
startPoint: z12.string().optional()
|
|
10068
11015
|
}),
|
|
10069
11016
|
async (args, ctx) => {
|
|
10070
11017
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10083,8 +11030,8 @@ var init_git2 = __esm({
|
|
|
10083
11030
|
);
|
|
10084
11031
|
registerCommand(
|
|
10085
11032
|
"git.branches",
|
|
10086
|
-
|
|
10087
|
-
workspaceId:
|
|
11033
|
+
z12.object({
|
|
11034
|
+
workspaceId: z12.string()
|
|
10088
11035
|
}),
|
|
10089
11036
|
async (args, ctx) => {
|
|
10090
11037
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10178,7 +11125,7 @@ var init_config_io = __esm({
|
|
|
10178
11125
|
});
|
|
10179
11126
|
|
|
10180
11127
|
// packages/server/src/commands/settings.ts
|
|
10181
|
-
import { z as
|
|
11128
|
+
import { z as z13 } from "zod";
|
|
10182
11129
|
function flattenSettings(obj, prefix = "") {
|
|
10183
11130
|
const result = {};
|
|
10184
11131
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -10201,28 +11148,34 @@ var init_settings2 = __esm({
|
|
|
10201
11148
|
init_provider_config_repo();
|
|
10202
11149
|
init_settings();
|
|
10203
11150
|
init_dispatch();
|
|
10204
|
-
SettingsSchema =
|
|
10205
|
-
defaultProviderId:
|
|
10206
|
-
notifications:
|
|
10207
|
-
enabled:
|
|
10208
|
-
soundEnabled:
|
|
11151
|
+
SettingsSchema = z13.object({
|
|
11152
|
+
defaultProviderId: z13.string().optional(),
|
|
11153
|
+
notifications: z13.object({
|
|
11154
|
+
enabled: z13.boolean().optional(),
|
|
11155
|
+
soundEnabled: z13.boolean().optional(),
|
|
10209
11156
|
// Legacy field — accepted for backward compat with older clients but
|
|
10210
11157
|
// no longer surfaced in the UI. The web client now picks the channel
|
|
10211
11158
|
// automatically based on workspace focus + page visibility.
|
|
10212
|
-
onlyWhenBackgrounded:
|
|
11159
|
+
onlyWhenBackgrounded: z13.boolean().optional()
|
|
10213
11160
|
}).optional(),
|
|
10214
|
-
supervisor:
|
|
10215
|
-
evaluationTimeoutSec:
|
|
11161
|
+
supervisor: z13.object({
|
|
11162
|
+
evaluationTimeoutSec: z13.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional(),
|
|
11163
|
+
retryEnabled: z13.boolean().optional(),
|
|
11164
|
+
retryMaxCount: z13.number().int().min(0).max(MAX_SUPERVISOR_RETRY_MAX_COUNT).optional(),
|
|
11165
|
+
retryDelaySec: z13.number().int().min(1).max(MAX_SUPERVISOR_RETRY_DELAY_SEC).optional(),
|
|
11166
|
+
retryOnTimeout: z13.boolean().optional(),
|
|
11167
|
+
retryOnEvaluatorError: z13.boolean().optional()
|
|
10216
11168
|
}).optional(),
|
|
10217
|
-
appearance:
|
|
10218
|
-
theme:
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
11169
|
+
appearance: z13.object({
|
|
11170
|
+
theme: z13.enum(["dark", "light"]).optional(),
|
|
11171
|
+
themeId: z13.string().optional(),
|
|
11172
|
+
terminalRenderer: z13.enum(["standard", "compatibility"]).optional(),
|
|
11173
|
+
terminalCopyOnSelect: z13.boolean().optional(),
|
|
11174
|
+
locale: z13.enum(["zh", "en"]).optional()
|
|
10222
11175
|
}).optional(),
|
|
10223
11176
|
providers: ProviderSettingsSchema.optional()
|
|
10224
11177
|
});
|
|
10225
|
-
registerCommand("settings.get",
|
|
11178
|
+
registerCommand("settings.get", z13.object({}), async (_args, ctx) => {
|
|
10226
11179
|
const row = ctx.db.prepare("SELECT key, value FROM user_settings").all();
|
|
10227
11180
|
const settings = {};
|
|
10228
11181
|
for (const { key, value } of row) {
|
|
@@ -10251,11 +11204,36 @@ var init_settings2 = __esm({
|
|
|
10251
11204
|
settings[SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY]
|
|
10252
11205
|
);
|
|
10253
11206
|
}
|
|
11207
|
+
if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_ENABLED_SETTING_KEY)) {
|
|
11208
|
+
settings[SUPERVISOR_RETRY_ENABLED_SETTING_KEY] = resolveSupervisorRetryEnabled(
|
|
11209
|
+
settings[SUPERVISOR_RETRY_ENABLED_SETTING_KEY]
|
|
11210
|
+
);
|
|
11211
|
+
}
|
|
11212
|
+
if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY)) {
|
|
11213
|
+
settings[SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY] = resolveSupervisorRetryMaxCount(
|
|
11214
|
+
settings[SUPERVISOR_RETRY_MAX_COUNT_SETTING_KEY]
|
|
11215
|
+
);
|
|
11216
|
+
}
|
|
11217
|
+
if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY)) {
|
|
11218
|
+
settings[SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY] = resolveSupervisorRetryDelaySec(
|
|
11219
|
+
settings[SUPERVISOR_RETRY_DELAY_SEC_SETTING_KEY]
|
|
11220
|
+
);
|
|
11221
|
+
}
|
|
11222
|
+
if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY)) {
|
|
11223
|
+
settings[SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY] = resolveSupervisorRetryOnTimeout(
|
|
11224
|
+
settings[SUPERVISOR_RETRY_ON_TIMEOUT_SETTING_KEY]
|
|
11225
|
+
);
|
|
11226
|
+
}
|
|
11227
|
+
if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY)) {
|
|
11228
|
+
settings[SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY] = resolveSupervisorRetryOnEvaluatorError(
|
|
11229
|
+
settings[SUPERVISOR_RETRY_ON_EVALUATOR_ERROR_SETTING_KEY]
|
|
11230
|
+
);
|
|
11231
|
+
}
|
|
10254
11232
|
return settings;
|
|
10255
11233
|
});
|
|
10256
11234
|
registerCommand(
|
|
10257
11235
|
"settings.update",
|
|
10258
|
-
|
|
11236
|
+
z13.object({
|
|
10259
11237
|
settings: SettingsSchema
|
|
10260
11238
|
}),
|
|
10261
11239
|
async (args, ctx) => {
|
|
@@ -10287,10 +11265,10 @@ var init_settings2 = __esm({
|
|
|
10287
11265
|
);
|
|
10288
11266
|
registerCommand(
|
|
10289
11267
|
"settings.previewCommand",
|
|
10290
|
-
|
|
10291
|
-
providerId:
|
|
11268
|
+
z13.object({
|
|
11269
|
+
providerId: z13.string(),
|
|
10292
11270
|
config: ProviderLaunchConfigInputSchema,
|
|
10293
|
-
workspacePath:
|
|
11271
|
+
workspacePath: z13.string().optional()
|
|
10294
11272
|
}),
|
|
10295
11273
|
async (args, ctx) => {
|
|
10296
11274
|
const provider = ctx.providerRegistry.find((item) => item.id === args.providerId);
|
|
@@ -10311,8 +11289,8 @@ var init_settings2 = __esm({
|
|
|
10311
11289
|
);
|
|
10312
11290
|
registerCommand(
|
|
10313
11291
|
"settings.readConfigFile",
|
|
10314
|
-
|
|
10315
|
-
configType:
|
|
11292
|
+
z13.object({
|
|
11293
|
+
configType: z13.enum(["codex", "claude"])
|
|
10316
11294
|
}),
|
|
10317
11295
|
async (args) => {
|
|
10318
11296
|
const result = readConfigFile(args.configType);
|
|
@@ -10321,9 +11299,9 @@ var init_settings2 = __esm({
|
|
|
10321
11299
|
);
|
|
10322
11300
|
registerCommand(
|
|
10323
11301
|
"settings.writeConfigFile",
|
|
10324
|
-
|
|
10325
|
-
configType:
|
|
10326
|
-
content:
|
|
11302
|
+
z13.object({
|
|
11303
|
+
configType: z13.enum(["codex", "claude"]),
|
|
11304
|
+
content: z13.string()
|
|
10327
11305
|
}),
|
|
10328
11306
|
async (args) => {
|
|
10329
11307
|
const result = writeConfigFile(args.configType, args.content);
|
|
@@ -10334,19 +11312,19 @@ var init_settings2 = __esm({
|
|
|
10334
11312
|
});
|
|
10335
11313
|
|
|
10336
11314
|
// packages/server/src/commands/provider.ts
|
|
10337
|
-
import { z as
|
|
11315
|
+
import { z as z14 } from "zod";
|
|
10338
11316
|
var init_provider = __esm({
|
|
10339
11317
|
"packages/server/src/commands/provider.ts"() {
|
|
10340
11318
|
"use strict";
|
|
10341
11319
|
init_runtime_status();
|
|
10342
11320
|
init_dispatch();
|
|
10343
|
-
registerCommand("provider.runtimeStatus",
|
|
11321
|
+
registerCommand("provider.runtimeStatus", z14.object({}), async (_args, ctx) => {
|
|
10344
11322
|
return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
|
|
10345
11323
|
});
|
|
10346
11324
|
registerCommand(
|
|
10347
11325
|
"provider.install.start",
|
|
10348
|
-
|
|
10349
|
-
providerId:
|
|
11326
|
+
z14.object({
|
|
11327
|
+
providerId: z14.string()
|
|
10350
11328
|
}),
|
|
10351
11329
|
async (args, ctx) => {
|
|
10352
11330
|
if (!ctx.providerInstallMgr) {
|
|
@@ -10360,8 +11338,8 @@ var init_provider = __esm({
|
|
|
10360
11338
|
);
|
|
10361
11339
|
registerCommand(
|
|
10362
11340
|
"provider.install.get",
|
|
10363
|
-
|
|
10364
|
-
jobId:
|
|
11341
|
+
z14.object({
|
|
11342
|
+
jobId: z14.string()
|
|
10365
11343
|
}),
|
|
10366
11344
|
async (args, ctx) => {
|
|
10367
11345
|
if (!ctx.providerInstallMgr) {
|
|
@@ -10384,36 +11362,45 @@ var init_provider = __esm({
|
|
|
10384
11362
|
});
|
|
10385
11363
|
|
|
10386
11364
|
// packages/server/src/commands/supervisor.ts
|
|
10387
|
-
import { z as
|
|
11365
|
+
import { z as z15 } from "zod";
|
|
10388
11366
|
var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, supervisorIdSchema;
|
|
10389
11367
|
var init_supervisor2 = __esm({
|
|
10390
11368
|
"packages/server/src/commands/supervisor.ts"() {
|
|
10391
11369
|
"use strict";
|
|
10392
11370
|
init_dispatch();
|
|
10393
|
-
supervisorObjectiveSchema =
|
|
10394
|
-
createSupervisorSchema =
|
|
10395
|
-
sessionId:
|
|
10396
|
-
workspaceId:
|
|
11371
|
+
supervisorObjectiveSchema = z15.string().trim().min(1).max(4e3);
|
|
11372
|
+
createSupervisorSchema = z15.object({
|
|
11373
|
+
sessionId: z15.string(),
|
|
11374
|
+
workspaceId: z15.string(),
|
|
10397
11375
|
objective: supervisorObjectiveSchema,
|
|
10398
|
-
evaluatorProviderId:
|
|
11376
|
+
evaluatorProviderId: z15.string(),
|
|
11377
|
+
evaluatorModel: z15.string().trim().min(1).max(200).optional(),
|
|
11378
|
+
maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
|
|
11379
|
+
scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
|
|
10399
11380
|
}).strict();
|
|
10400
|
-
updateSupervisorSchema =
|
|
10401
|
-
id:
|
|
11381
|
+
updateSupervisorSchema = z15.object({
|
|
11382
|
+
id: z15.string(),
|
|
10402
11383
|
objective: supervisorObjectiveSchema.optional(),
|
|
10403
|
-
evaluatorProviderId:
|
|
11384
|
+
evaluatorProviderId: z15.string().optional(),
|
|
11385
|
+
evaluatorModel: z15.string().trim().min(1).max(200).nullable().optional(),
|
|
11386
|
+
maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
|
|
11387
|
+
scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
|
|
10404
11388
|
}).strict().refine(
|
|
10405
|
-
(input2) => input2.objective !== void 0 || input2.evaluatorProviderId !== void 0,
|
|
10406
|
-
"
|
|
11389
|
+
(input2) => input2.objective !== void 0 || input2.evaluatorProviderId !== void 0 || input2.evaluatorModel !== void 0 || input2.maxSupervisionCount !== void 0 || input2.scheduledAt !== void 0,
|
|
11390
|
+
"at least one supervisor field is required"
|
|
10407
11391
|
);
|
|
10408
|
-
sessionIdSchema =
|
|
10409
|
-
supervisorIdSchema =
|
|
11392
|
+
sessionIdSchema = z15.object({ sessionId: z15.string() });
|
|
11393
|
+
supervisorIdSchema = z15.object({ id: z15.string() });
|
|
10410
11394
|
registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
|
|
10411
11395
|
return {
|
|
10412
11396
|
supervisor: await ctx.supervisorMgr.create({
|
|
10413
11397
|
sessionId: args.sessionId,
|
|
10414
11398
|
workspaceId: args.workspaceId,
|
|
10415
11399
|
objective: args.objective,
|
|
10416
|
-
evaluatorProviderId: args.evaluatorProviderId
|
|
11400
|
+
evaluatorProviderId: args.evaluatorProviderId,
|
|
11401
|
+
evaluatorModel: args.evaluatorModel,
|
|
11402
|
+
maxSupervisionCount: args.maxSupervisionCount,
|
|
11403
|
+
scheduledAt: args.scheduledAt
|
|
10417
11404
|
})
|
|
10418
11405
|
};
|
|
10419
11406
|
});
|
|
@@ -10424,7 +11411,10 @@ var init_supervisor2 = __esm({
|
|
|
10424
11411
|
return {
|
|
10425
11412
|
supervisor: await ctx.supervisorMgr.update(args.id, {
|
|
10426
11413
|
objective: args.objective,
|
|
10427
|
-
evaluatorProviderId: args.evaluatorProviderId
|
|
11414
|
+
evaluatorProviderId: args.evaluatorProviderId,
|
|
11415
|
+
evaluatorModel: args.evaluatorModel,
|
|
11416
|
+
maxSupervisionCount: args.maxSupervisionCount,
|
|
11417
|
+
scheduledAt: args.scheduledAt
|
|
10428
11418
|
})
|
|
10429
11419
|
};
|
|
10430
11420
|
});
|
|
@@ -10584,7 +11574,7 @@ var init_worktree = __esm({
|
|
|
10584
11574
|
|
|
10585
11575
|
// packages/server/src/commands/worktree.ts
|
|
10586
11576
|
import path9 from "node:path";
|
|
10587
|
-
import { z as
|
|
11577
|
+
import { z as z16 } from "zod";
|
|
10588
11578
|
async function findRelatedWorkspaceIds(ctx, workspacePath) {
|
|
10589
11579
|
const targetCommonDir = await getGitCommonDirPath(workspacePath);
|
|
10590
11580
|
const relatedWorkspaceIds = await Promise.all(
|
|
@@ -10617,7 +11607,7 @@ var init_worktree2 = __esm({
|
|
|
10617
11607
|
init_worktree();
|
|
10618
11608
|
init_dispatch();
|
|
10619
11609
|
init_git_events();
|
|
10620
|
-
registerCommand("worktree.list",
|
|
11610
|
+
registerCommand("worktree.list", z16.object({ workspaceId: z16.string() }), async (args, ctx) => {
|
|
10621
11611
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10622
11612
|
if (!workspace) {
|
|
10623
11613
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
@@ -10626,7 +11616,7 @@ var init_worktree2 = __esm({
|
|
|
10626
11616
|
});
|
|
10627
11617
|
registerCommand(
|
|
10628
11618
|
"worktree.status",
|
|
10629
|
-
|
|
11619
|
+
z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
|
|
10630
11620
|
async (args, ctx) => {
|
|
10631
11621
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10632
11622
|
if (!workspace) {
|
|
@@ -10638,10 +11628,10 @@ var init_worktree2 = __esm({
|
|
|
10638
11628
|
);
|
|
10639
11629
|
registerCommand(
|
|
10640
11630
|
"worktree.diff",
|
|
10641
|
-
|
|
10642
|
-
workspaceId:
|
|
10643
|
-
worktreePath:
|
|
10644
|
-
staged:
|
|
11631
|
+
z16.object({
|
|
11632
|
+
workspaceId: z16.string(),
|
|
11633
|
+
worktreePath: z16.string(),
|
|
11634
|
+
staged: z16.boolean().optional().default(false)
|
|
10645
11635
|
}),
|
|
10646
11636
|
async (args, ctx) => {
|
|
10647
11637
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10654,7 +11644,7 @@ var init_worktree2 = __esm({
|
|
|
10654
11644
|
);
|
|
10655
11645
|
registerCommand(
|
|
10656
11646
|
"worktree.tree",
|
|
10657
|
-
|
|
11647
|
+
z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
|
|
10658
11648
|
async (args, ctx) => {
|
|
10659
11649
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10660
11650
|
if (!workspace) {
|
|
@@ -10666,10 +11656,10 @@ var init_worktree2 = __esm({
|
|
|
10666
11656
|
);
|
|
10667
11657
|
registerCommand(
|
|
10668
11658
|
"worktree.create",
|
|
10669
|
-
|
|
10670
|
-
workspaceId:
|
|
10671
|
-
branch:
|
|
10672
|
-
path:
|
|
11659
|
+
z16.object({
|
|
11660
|
+
workspaceId: z16.string(),
|
|
11661
|
+
branch: z16.string(),
|
|
11662
|
+
path: z16.string()
|
|
10673
11663
|
}),
|
|
10674
11664
|
async (args, ctx) => {
|
|
10675
11665
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10684,10 +11674,10 @@ var init_worktree2 = __esm({
|
|
|
10684
11674
|
);
|
|
10685
11675
|
registerCommand(
|
|
10686
11676
|
"worktree.remove",
|
|
10687
|
-
|
|
10688
|
-
workspaceId:
|
|
10689
|
-
worktreePath:
|
|
10690
|
-
force:
|
|
11677
|
+
z16.object({
|
|
11678
|
+
workspaceId: z16.string(),
|
|
11679
|
+
worktreePath: z16.string(),
|
|
11680
|
+
force: z16.boolean().optional().default(false)
|
|
10691
11681
|
}),
|
|
10692
11682
|
async (args, ctx) => {
|
|
10693
11683
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10711,7 +11701,7 @@ var init_worktree2 = __esm({
|
|
|
10711
11701
|
});
|
|
10712
11702
|
|
|
10713
11703
|
// packages/server/src/commands/fencing.ts
|
|
10714
|
-
import { z as
|
|
11704
|
+
import { z as z17 } from "zod";
|
|
10715
11705
|
function createMockFencingRequest() {
|
|
10716
11706
|
return {
|
|
10717
11707
|
ip: "127.0.0.1",
|
|
@@ -10724,9 +11714,9 @@ var init_fencing2 = __esm({
|
|
|
10724
11714
|
init_dispatch();
|
|
10725
11715
|
registerCommand(
|
|
10726
11716
|
"fencing.request",
|
|
10727
|
-
|
|
10728
|
-
workspaceId:
|
|
10729
|
-
tabId:
|
|
11717
|
+
z17.object({
|
|
11718
|
+
workspaceId: z17.string(),
|
|
11719
|
+
tabId: z17.string()
|
|
10730
11720
|
}),
|
|
10731
11721
|
async (args, ctx, clientId) => {
|
|
10732
11722
|
return ctx.fencingMgr.requestControl(
|
|
@@ -10739,7 +11729,7 @@ var init_fencing2 = __esm({
|
|
|
10739
11729
|
);
|
|
10740
11730
|
registerCommand(
|
|
10741
11731
|
"fencing.heartbeat",
|
|
10742
|
-
|
|
11732
|
+
z17.object({ workspaceId: z17.string() }),
|
|
10743
11733
|
async (args, ctx, clientId) => {
|
|
10744
11734
|
const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
|
|
10745
11735
|
return { success };
|
|
@@ -10747,13 +11737,13 @@ var init_fencing2 = __esm({
|
|
|
10747
11737
|
);
|
|
10748
11738
|
registerCommand(
|
|
10749
11739
|
"fencing.release",
|
|
10750
|
-
|
|
11740
|
+
z17.object({ workspaceId: z17.string() }),
|
|
10751
11741
|
async (args, ctx, clientId) => {
|
|
10752
11742
|
ctx.fencingMgr.release(args.workspaceId, clientId);
|
|
10753
11743
|
return {};
|
|
10754
11744
|
}
|
|
10755
11745
|
);
|
|
10756
|
-
registerCommand("fencing.status",
|
|
11746
|
+
registerCommand("fencing.status", z17.object({ workspaceId: z17.string() }), async (args, ctx) => {
|
|
10757
11747
|
const controller = ctx.fencingMgr.getController(args.workspaceId);
|
|
10758
11748
|
const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
|
|
10759
11749
|
return {
|
|
@@ -10764,9 +11754,9 @@ var init_fencing2 = __esm({
|
|
|
10764
11754
|
});
|
|
10765
11755
|
registerCommand(
|
|
10766
11756
|
"fencing.takeover",
|
|
10767
|
-
|
|
10768
|
-
workspaceId:
|
|
10769
|
-
tabId:
|
|
11757
|
+
z17.object({
|
|
11758
|
+
workspaceId: z17.string(),
|
|
11759
|
+
tabId: z17.string()
|
|
10770
11760
|
}),
|
|
10771
11761
|
async (args, ctx, clientId) => {
|
|
10772
11762
|
return ctx.fencingMgr.forceTakeover(
|
|
@@ -10786,6 +11776,7 @@ var init_commands = __esm({
|
|
|
10786
11776
|
"use strict";
|
|
10787
11777
|
init_workspace();
|
|
10788
11778
|
init_workspace_activity();
|
|
11779
|
+
init_activation2();
|
|
10789
11780
|
init_connection();
|
|
10790
11781
|
init_session();
|
|
10791
11782
|
init_terminal();
|
|
@@ -10805,6 +11796,7 @@ async function createServer(configOverrides) {
|
|
|
10805
11796
|
ensureDataDir(config);
|
|
10806
11797
|
const db = openDatabase(config.dataDir);
|
|
10807
11798
|
const eventBus = new EventBus();
|
|
11799
|
+
const activationMgr = new ActivationManager();
|
|
10808
11800
|
const fencingMgr = new FencingManager();
|
|
10809
11801
|
const wsHub = new WsHub({ eventBus, commandContext: null, config, fencingMgr });
|
|
10810
11802
|
let workspaceMgr;
|
|
@@ -10895,6 +11887,7 @@ async function createServer(configOverrides) {
|
|
|
10895
11887
|
wsHub.setLogger(app.log);
|
|
10896
11888
|
const supervisorRepo = new SupervisorRepo(db);
|
|
10897
11889
|
const cycleRepo = new SupervisorCycleRepo(db);
|
|
11890
|
+
const cycleAttemptRepo = new SupervisorCycleAttemptRepo(db);
|
|
10898
11891
|
supervisorMgr = new SupervisorManager({
|
|
10899
11892
|
eventBus,
|
|
10900
11893
|
broadcaster: wsHub,
|
|
@@ -10906,6 +11899,7 @@ async function createServer(configOverrides) {
|
|
|
10906
11899
|
settingsRepo,
|
|
10907
11900
|
supervisorRepo,
|
|
10908
11901
|
cycleRepo,
|
|
11902
|
+
cycleAttemptRepo,
|
|
10909
11903
|
logger: app.log
|
|
10910
11904
|
});
|
|
10911
11905
|
await sessionMgr.hydrate();
|
|
@@ -10930,7 +11924,8 @@ async function createServer(configOverrides) {
|
|
|
10930
11924
|
supervisorMgr,
|
|
10931
11925
|
autoFetch,
|
|
10932
11926
|
providerRuntimeDeps,
|
|
10933
|
-
providerInstallMgr
|
|
11927
|
+
providerInstallMgr,
|
|
11928
|
+
activationMgr
|
|
10934
11929
|
};
|
|
10935
11930
|
wsHub.setCommandContext(commandContext);
|
|
10936
11931
|
await app.listen({
|
|
@@ -11101,6 +12096,7 @@ var init_server = __esm({
|
|
|
11101
12096
|
init_provider_config_repo();
|
|
11102
12097
|
init_session_repo();
|
|
11103
12098
|
init_settings_repo();
|
|
12099
|
+
init_supervisor_cycle_attempt_repo();
|
|
11104
12100
|
init_supervisor_cycle_repo();
|
|
11105
12101
|
init_supervisor_repo();
|
|
11106
12102
|
init_manager2();
|
|
@@ -11109,6 +12105,7 @@ var init_server = __esm({
|
|
|
11109
12105
|
init_cleanup();
|
|
11110
12106
|
init_constants();
|
|
11111
12107
|
init_manager4();
|
|
12108
|
+
init_activation();
|
|
11112
12109
|
init_dispatch();
|
|
11113
12110
|
init_fencing();
|
|
11114
12111
|
init_hub();
|
|
@@ -11336,6 +12333,7 @@ var init_storage = __esm({
|
|
|
11336
12333
|
init_provider_config_repo();
|
|
11337
12334
|
init_session_repo();
|
|
11338
12335
|
init_settings_repo();
|
|
12336
|
+
init_supervisor_cycle_attempt_repo();
|
|
11339
12337
|
init_supervisor_cycle_repo();
|
|
11340
12338
|
init_supervisor_repo();
|
|
11341
12339
|
init_terminal_repo();
|
|
@@ -11366,6 +12364,7 @@ __export(src_exports, {
|
|
|
11366
12364
|
RingBuffer: () => RingBuffer,
|
|
11367
12365
|
SessionRepo: () => SessionRepo,
|
|
11368
12366
|
SettingsRepo: () => SettingsRepo,
|
|
12367
|
+
SupervisorCycleAttemptRepo: () => SupervisorCycleAttemptRepo,
|
|
11369
12368
|
SupervisorCycleRepo: () => SupervisorCycleRepo,
|
|
11370
12369
|
SupervisorRepo: () => SupervisorRepo,
|
|
11371
12370
|
TerminalManager: () => TerminalManager,
|
|
@@ -11400,8 +12399,8 @@ var init_src4 = __esm({
|
|
|
11400
12399
|
});
|
|
11401
12400
|
|
|
11402
12401
|
// packages/cli/src/cli.ts
|
|
11403
|
-
import { existsSync as existsSync11 } from "fs";
|
|
11404
|
-
import { dirname as
|
|
12402
|
+
import { existsSync as existsSync11, rmSync } from "fs";
|
|
12403
|
+
import { dirname as dirname7, join as join10 } from "path";
|
|
11405
12404
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
11406
12405
|
|
|
11407
12406
|
// packages/cli/src/auth-control.ts
|
|
@@ -12216,6 +13215,9 @@ async function getServerStatus() {
|
|
|
12216
13215
|
}
|
|
12217
13216
|
|
|
12218
13217
|
// packages/cli/src/server-runner.ts
|
|
13218
|
+
await init_src4();
|
|
13219
|
+
import { mkdirSync as mkdirSync6 } from "fs";
|
|
13220
|
+
import { dirname as dirname6 } from "path";
|
|
12219
13221
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12220
13222
|
|
|
12221
13223
|
// packages/cli/src/embed.ts
|
|
@@ -12257,6 +13259,14 @@ var buildServerConfig = () => {
|
|
|
12257
13259
|
console.warn(MISSING_WEB_ASSETS_WARNING);
|
|
12258
13260
|
return config;
|
|
12259
13261
|
};
|
|
13262
|
+
var verifyLocalDatabaseCompatibility = () => {
|
|
13263
|
+
const config = parseServerConfig(buildServerConfig());
|
|
13264
|
+
if (config.dataDir !== ":memory:") {
|
|
13265
|
+
mkdirSync6(dirname6(config.dataDir), { recursive: true });
|
|
13266
|
+
}
|
|
13267
|
+
const db = openDatabase(config.dataDir);
|
|
13268
|
+
closeDatabase(db);
|
|
13269
|
+
};
|
|
12260
13270
|
var createShutdownHandler = (server) => async () => {
|
|
12261
13271
|
await server.stop();
|
|
12262
13272
|
process.exit(0);
|
|
@@ -12431,7 +13441,7 @@ function formatAuthBlocks(blocks) {
|
|
|
12431
13441
|
}
|
|
12432
13442
|
function resolveManagedScriptPath() {
|
|
12433
13443
|
const currentFile = fileURLToPath3(import.meta.url);
|
|
12434
|
-
const currentDir =
|
|
13444
|
+
const currentDir = dirname7(currentFile);
|
|
12435
13445
|
const candidates = [
|
|
12436
13446
|
join10(currentDir, "server-runner.js"),
|
|
12437
13447
|
join10(currentDir, "server-runner.mjs"),
|
|
@@ -12489,6 +13499,44 @@ async function startManagedServerFlow() {
|
|
|
12489
13499
|
waitMs: MANAGED_SERVER_WAIT_MS
|
|
12490
13500
|
});
|
|
12491
13501
|
}
|
|
13502
|
+
function parseIncompatibleSchemaError(error) {
|
|
13503
|
+
if (!error || typeof error !== "object") {
|
|
13504
|
+
return null;
|
|
13505
|
+
}
|
|
13506
|
+
const candidate = error;
|
|
13507
|
+
if (candidate.code !== "db_incompatible_schema" || typeof candidate.dbPath !== "string") {
|
|
13508
|
+
return null;
|
|
13509
|
+
}
|
|
13510
|
+
return {
|
|
13511
|
+
code: "db_incompatible_schema",
|
|
13512
|
+
dbPath: candidate.dbPath
|
|
13513
|
+
};
|
|
13514
|
+
}
|
|
13515
|
+
async function handleIncompatibleSchema(error) {
|
|
13516
|
+
const payload = parseIncompatibleSchemaError(error);
|
|
13517
|
+
if (!payload) {
|
|
13518
|
+
return false;
|
|
13519
|
+
}
|
|
13520
|
+
const approved = isInteractiveSession() ? await confirmYesNo(
|
|
13521
|
+
`Local database is incompatible at ${payload.dbPath}. Delete and rebuild the local database? [y/N] `
|
|
13522
|
+
) : false;
|
|
13523
|
+
if (!approved) {
|
|
13524
|
+
throw error;
|
|
13525
|
+
}
|
|
13526
|
+
rmSync(payload.dbPath, { force: true });
|
|
13527
|
+
return true;
|
|
13528
|
+
}
|
|
13529
|
+
async function verifyManagedDatabaseCompatibility() {
|
|
13530
|
+
try {
|
|
13531
|
+
verifyLocalDatabaseCompatibility();
|
|
13532
|
+
} catch (error) {
|
|
13533
|
+
const rebuilt = await handleIncompatibleSchema(error);
|
|
13534
|
+
if (!rebuilt) {
|
|
13535
|
+
throw error;
|
|
13536
|
+
}
|
|
13537
|
+
verifyLocalDatabaseCompatibility();
|
|
13538
|
+
}
|
|
13539
|
+
}
|
|
12492
13540
|
async function openManagedServerInBrowser(existingStatus) {
|
|
12493
13541
|
const status = existingStatus ?? await getServerStatus();
|
|
12494
13542
|
const browserUrl = getBrowserUrl(status);
|
|
@@ -12560,6 +13608,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12560
13608
|
if (args.command === "open") {
|
|
12561
13609
|
const startup2 = await prepareManagedStartup(args.restart);
|
|
12562
13610
|
if (startup2.existingStatus === null) {
|
|
13611
|
+
await verifyManagedDatabaseCompatibility();
|
|
12563
13612
|
await startManagedServerFlow();
|
|
12564
13613
|
}
|
|
12565
13614
|
await openManagedServerInBrowser(startup2.existingStatus);
|
|
@@ -12574,13 +13623,22 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12574
13623
|
await stopRunningServer();
|
|
12575
13624
|
}
|
|
12576
13625
|
console.log("Starting Coder Studio Server in foreground...");
|
|
12577
|
-
|
|
13626
|
+
try {
|
|
13627
|
+
await startServer();
|
|
13628
|
+
} catch (error) {
|
|
13629
|
+
const rebuilt = await handleIncompatibleSchema(error);
|
|
13630
|
+
if (!rebuilt) {
|
|
13631
|
+
throw error;
|
|
13632
|
+
}
|
|
13633
|
+
await startServer();
|
|
13634
|
+
}
|
|
12578
13635
|
return;
|
|
12579
13636
|
}
|
|
12580
13637
|
const startup = await prepareManagedStartup(args.restart);
|
|
12581
13638
|
if (startup.existingStatus !== null) {
|
|
12582
13639
|
return;
|
|
12583
13640
|
}
|
|
13641
|
+
await verifyManagedDatabaseCompatibility();
|
|
12584
13642
|
await startManagedServerFlow();
|
|
12585
13643
|
console.log("Coder Studio server started in background.");
|
|
12586
13644
|
console.log("Run `coder-studio status` to inspect the server.");
|