codexuse-cli 3.9.7 → 3.9.9
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/dist/index.js +1386 -340
- package/dist/index.js.map +1 -1
- package/dist/server/index.mjs +1730 -613
- package/package.json +2 -2
package/dist/server/index.mjs
CHANGED
|
@@ -48769,8 +48769,10 @@ const WS_METHODS = {
|
|
|
48769
48769
|
officialCodexFocusProfile: "officialCodex.focusProfile",
|
|
48770
48770
|
officialCodexStopProfile: "officialCodex.stopProfile",
|
|
48771
48771
|
officialCodexRestartProfile: "officialCodex.restartProfile",
|
|
48772
|
+
officialCodexUseProfile: "officialCodex.useProfile",
|
|
48772
48773
|
officialCodexLaunchProfiles: "officialCodex.launchProfiles",
|
|
48773
48774
|
officialCodexStopProfiles: "officialCodex.stopProfiles",
|
|
48775
|
+
officialCodexActivateProfiles: "officialCodex.activateProfiles",
|
|
48774
48776
|
cliInfo: "cli.info",
|
|
48775
48777
|
cliStatus: "cli.status",
|
|
48776
48778
|
cliCheckFreshness: "cli.checkFreshness",
|
|
@@ -48936,8 +48938,10 @@ const WebSocketRequestBody = Union([
|
|
|
48936
48938
|
tagRequestBody(WS_METHODS.officialCodexFocusProfile, Struct({ name: TrimmedNonEmptyString })),
|
|
48937
48939
|
tagRequestBody(WS_METHODS.officialCodexStopProfile, Struct({ name: TrimmedNonEmptyString })),
|
|
48938
48940
|
tagRequestBody(WS_METHODS.officialCodexRestartProfile, Struct({ name: TrimmedNonEmptyString })),
|
|
48941
|
+
tagRequestBody(WS_METHODS.officialCodexUseProfile, Struct({ name: TrimmedNonEmptyString })),
|
|
48939
48942
|
tagRequestBody(WS_METHODS.officialCodexLaunchProfiles, Struct({ names: Array$1(TrimmedNonEmptyString) })),
|
|
48940
48943
|
tagRequestBody(WS_METHODS.officialCodexStopProfiles, Struct({ names: Array$1(TrimmedNonEmptyString) })),
|
|
48944
|
+
tagRequestBody(WS_METHODS.officialCodexActivateProfiles, Struct({ names: Array$1(TrimmedNonEmptyString) })),
|
|
48941
48945
|
tagRequestBody(WS_METHODS.cliInfo, Struct({})),
|
|
48942
48946
|
tagRequestBody(WS_METHODS.cliStatus, Struct({})),
|
|
48943
48947
|
tagRequestBody(WS_METHODS.cliCheckFreshness, Struct({})),
|
|
@@ -58299,7 +58303,7 @@ const SQLITE_BUSY_MAX_ATTEMPTS = 3;
|
|
|
58299
58303
|
const SQLITE_BUSY_RETRY_DELAY_MS = 100;
|
|
58300
58304
|
const writeQueueByDbPath = /* @__PURE__ */ new Map();
|
|
58301
58305
|
const initializedDbPaths = /* @__PURE__ */ new Set();
|
|
58302
|
-
function isRecord$
|
|
58306
|
+
function isRecord$9(value) {
|
|
58303
58307
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
58304
58308
|
}
|
|
58305
58309
|
function clone$1(value) {
|
|
@@ -58411,7 +58415,7 @@ function resolveAppStorageDbPath(userDataDir) {
|
|
|
58411
58415
|
async function readDocument(dbPath, namespace, normalize) {
|
|
58412
58416
|
return withDatabase(dbPath, (db) => {
|
|
58413
58417
|
const row = useStatement(db, `SELECT value_json AS valueJson FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`, (statement) => statement.get(namespace));
|
|
58414
|
-
const parsed = isRecord$
|
|
58418
|
+
const parsed = isRecord$9(row) ? safeParseJson(row.valueJson) : null;
|
|
58415
58419
|
if (parsed === null) return null;
|
|
58416
58420
|
return normalize(parsed);
|
|
58417
58421
|
});
|
|
@@ -58442,7 +58446,7 @@ async function updateDocument(input) {
|
|
|
58442
58446
|
beginImmediate(db);
|
|
58443
58447
|
try {
|
|
58444
58448
|
const row = useStatement(db, `SELECT value_json AS valueJson FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`, (statement) => statement.get(input.namespace));
|
|
58445
|
-
const current = isRecord$
|
|
58449
|
+
const current = isRecord$9(row) ? input.normalize(safeParseJson(row.valueJson) ?? input.fallback()) : input.fallback();
|
|
58446
58450
|
const next = input.normalize(input.transform(clone$1(current)));
|
|
58447
58451
|
useStatement(db, `
|
|
58448
58452
|
INSERT INTO ${APP_STORAGE_TABLE} (namespace, value_json, updated_at)
|
|
@@ -58469,7 +58473,7 @@ let configuredUserDataDir = null;
|
|
|
58469
58473
|
let appStateCache = null;
|
|
58470
58474
|
let writeLock = Promise.resolve();
|
|
58471
58475
|
const writeLockContext = new AsyncLocalStorage();
|
|
58472
|
-
function isRecord$
|
|
58476
|
+
function isRecord$8(value) {
|
|
58473
58477
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
58474
58478
|
}
|
|
58475
58479
|
function clone(value) {
|
|
@@ -58516,7 +58520,9 @@ function createDefaultAppState() {
|
|
|
58516
58520
|
lastObservedPid: null,
|
|
58517
58521
|
lastRestartStatus: null,
|
|
58518
58522
|
lastRestartReason: null,
|
|
58519
|
-
|
|
58523
|
+
activity: [],
|
|
58524
|
+
instancesByProfileName: {},
|
|
58525
|
+
pendingRestartDebt: null
|
|
58520
58526
|
},
|
|
58521
58527
|
app: {
|
|
58522
58528
|
lastAppVersion: null,
|
|
@@ -58604,7 +58610,7 @@ function createDefaultAppState() {
|
|
|
58604
58610
|
}
|
|
58605
58611
|
};
|
|
58606
58612
|
}
|
|
58607
|
-
function asString$
|
|
58613
|
+
function asString$10(value) {
|
|
58608
58614
|
if (typeof value !== "string") return null;
|
|
58609
58615
|
const trimmed = value.trim();
|
|
58610
58616
|
return trimmed.length > 0 ? trimmed : null;
|
|
@@ -58612,57 +58618,97 @@ function asString$9(value) {
|
|
|
58612
58618
|
function asNumberOrNull(value) {
|
|
58613
58619
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
58614
58620
|
}
|
|
58621
|
+
function asBooleanOrNull(value) {
|
|
58622
|
+
return typeof value === "boolean" ? value : null;
|
|
58623
|
+
}
|
|
58615
58624
|
function normalizeAppState(raw) {
|
|
58616
58625
|
const defaults = createDefaultAppState();
|
|
58617
|
-
if (!isRecord$
|
|
58618
|
-
const rawAutoRoll = isRecord$
|
|
58626
|
+
if (!isRecord$8(raw)) return defaults;
|
|
58627
|
+
const rawAutoRoll = isRecord$8(raw.autoRoll) ? raw.autoRoll : void 0;
|
|
58619
58628
|
const merged = clone(deepMerge(defaults, raw));
|
|
58620
58629
|
merged.schemaVersion = 1;
|
|
58621
58630
|
merged.autoRoll = normalizeAutoRollSettings(rawAutoRoll);
|
|
58622
|
-
if (!isRecord$
|
|
58631
|
+
if (!isRecord$8(merged.officialCodex)) merged.officialCodex = clone(defaults.officialCodex);
|
|
58623
58632
|
merged.officialCodex.lastProfileSwitchAt = asNumberOrNull(merged.officialCodex.lastProfileSwitchAt);
|
|
58624
|
-
merged.officialCodex.lastProfileSwitchProfileKey = asString$
|
|
58633
|
+
merged.officialCodex.lastProfileSwitchProfileKey = asString$10(merged.officialCodex.lastProfileSwitchProfileKey);
|
|
58625
58634
|
merged.officialCodex.lastVerifiedLaunchAt = asNumberOrNull(merged.officialCodex.lastVerifiedLaunchAt);
|
|
58626
|
-
merged.officialCodex.lastVerifiedLaunchProfileKey = asString$
|
|
58635
|
+
merged.officialCodex.lastVerifiedLaunchProfileKey = asString$10(merged.officialCodex.lastVerifiedLaunchProfileKey);
|
|
58627
58636
|
merged.officialCodex.lastObservedPid = asNumberOrNull(merged.officialCodex.lastObservedPid);
|
|
58628
|
-
merged.officialCodex.lastRestartStatus = asString$
|
|
58629
|
-
merged.officialCodex.lastRestartReason = asString$
|
|
58630
|
-
|
|
58637
|
+
merged.officialCodex.lastRestartStatus = asString$10(merged.officialCodex.lastRestartStatus);
|
|
58638
|
+
merged.officialCodex.lastRestartReason = asString$10(merged.officialCodex.lastRestartReason);
|
|
58639
|
+
merged.officialCodex.activity = Array.isArray(merged.officialCodex.activity) ? merged.officialCodex.activity.filter((entry) => isRecord$8(entry)).map((entry) => ({
|
|
58640
|
+
id: asString$10(entry.id) ?? "",
|
|
58641
|
+
at: asString$10(entry.at) ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
58642
|
+
kind: entry.kind === "auto-roll-eval" || entry.kind === "profile-switch" || entry.kind === "auth-verified" || entry.kind === "official-codex-restart" || entry.kind === "reset-window-activation" || entry.kind === "low-remaining-alert" ? entry.kind : "auto-roll-eval",
|
|
58643
|
+
status: asString$10(entry.status) ?? "unknown",
|
|
58644
|
+
reason: asString$10(entry.reason),
|
|
58645
|
+
decisionId: asString$10(entry.decisionId),
|
|
58646
|
+
profileName: asString$10(entry.profileName),
|
|
58647
|
+
sourceProfileName: asString$10(entry.sourceProfileName),
|
|
58648
|
+
targetProfileName: asString$10(entry.targetProfileName),
|
|
58649
|
+
remainingPercent: asNumberOrNull(entry.remainingPercent),
|
|
58650
|
+
threshold: asNumberOrNull(entry.threshold),
|
|
58651
|
+
snapshotAgeMs: asNumberOrNull(entry.snapshotAgeMs),
|
|
58652
|
+
snapshotSource: asString$10(entry.snapshotSource),
|
|
58653
|
+
phase: asString$10(entry.phase),
|
|
58654
|
+
pid: asNumberOrNull(entry.pid),
|
|
58655
|
+
profileKeyHash: asString$10(entry.profileKeyHash),
|
|
58656
|
+
switchVerified: asBooleanOrNull(entry.switchVerified),
|
|
58657
|
+
restartRequested: asBooleanOrNull(entry.restartRequested),
|
|
58658
|
+
restartResult: asString$10(entry.restartResult),
|
|
58659
|
+
observedProfileName: asString$10(entry.observedProfileName),
|
|
58660
|
+
observedProfileKeyHash: asString$10(entry.observedProfileKeyHash),
|
|
58661
|
+
observedProfileMatchSource: asString$10(entry.observedProfileMatchSource)
|
|
58662
|
+
})).filter((entry) => entry.id && entry.at).slice(-50) : [];
|
|
58663
|
+
if (!isRecord$8(merged.officialCodex.instancesByProfileName)) merged.officialCodex.instancesByProfileName = {};
|
|
58631
58664
|
else {
|
|
58632
58665
|
const nextInstances = {};
|
|
58633
58666
|
for (const [key, value] of Object.entries(merged.officialCodex.instancesByProfileName)) {
|
|
58634
|
-
if (!isRecord$
|
|
58635
|
-
const profileName = asString$
|
|
58667
|
+
if (!isRecord$8(value)) continue;
|
|
58668
|
+
const profileName = asString$10(value.profileName) ?? asString$10(key);
|
|
58636
58669
|
if (!profileName) continue;
|
|
58637
58670
|
nextInstances[profileName] = {
|
|
58638
58671
|
profileName,
|
|
58639
|
-
profileKey: asString$
|
|
58640
|
-
profileHome: asString$
|
|
58641
|
-
appPath: asString$
|
|
58642
|
-
bundleId: asString$
|
|
58672
|
+
profileKey: asString$10(value.profileKey),
|
|
58673
|
+
profileHome: asString$10(value.profileHome),
|
|
58674
|
+
appPath: asString$10(value.appPath),
|
|
58675
|
+
bundleId: asString$10(value.bundleId),
|
|
58643
58676
|
pid: asNumberOrNull(value.pid),
|
|
58644
58677
|
appServerPid: asNumberOrNull(value.appServerPid),
|
|
58645
58678
|
launchedAt: asNumberOrNull(value.launchedAt),
|
|
58646
58679
|
lastVerifiedAt: asNumberOrNull(value.lastVerifiedAt),
|
|
58647
|
-
lastStatus: asString$
|
|
58648
|
-
lastError: asString$
|
|
58680
|
+
lastStatus: asString$10(value.lastStatus),
|
|
58681
|
+
lastError: asString$10(value.lastError)
|
|
58649
58682
|
};
|
|
58650
58683
|
}
|
|
58651
58684
|
merged.officialCodex.instancesByProfileName = nextInstances;
|
|
58652
58685
|
}
|
|
58653
|
-
|
|
58654
|
-
|
|
58655
|
-
|
|
58686
|
+
if (isRecord$8(merged.officialCodex.pendingRestartDebt)) {
|
|
58687
|
+
const debt = merged.officialCodex.pendingRestartDebt;
|
|
58688
|
+
const targetProfileName = asString$10(debt.targetProfileName);
|
|
58689
|
+
merged.officialCodex.pendingRestartDebt = targetProfileName ? {
|
|
58690
|
+
targetProfileName,
|
|
58691
|
+
targetProfileKey: asString$10(debt.targetProfileKey),
|
|
58692
|
+
sourceProfileName: asString$10(debt.sourceProfileName),
|
|
58693
|
+
sourceProfileKey: asString$10(debt.sourceProfileKey),
|
|
58694
|
+
decisionId: asString$10(debt.decisionId),
|
|
58695
|
+
attempts: asNumberOrNull(debt.attempts) ?? 0,
|
|
58696
|
+
lastReason: asString$10(debt.lastReason)
|
|
58697
|
+
} : null;
|
|
58698
|
+
} else merged.officialCodex.pendingRestartDebt = null;
|
|
58699
|
+
merged.app.lastAppVersion = asString$10(merged.app.lastAppVersion);
|
|
58700
|
+
merged.app.pendingUpdateVersion = asString$10(merged.app.pendingUpdateVersion);
|
|
58701
|
+
merged.app.lastProfileName = asString$10(merged.app.lastProfileName);
|
|
58656
58702
|
{
|
|
58657
58703
|
const allowedAppKeys = new Set(Object.keys(defaults.app));
|
|
58658
58704
|
for (const key of Object.keys(merged.app)) if (!allowedAppKeys.has(key)) delete merged.app[key];
|
|
58659
58705
|
}
|
|
58660
|
-
merged.license.licenseKey = asString$
|
|
58661
|
-
merged.license.purchaseEmail = asString$
|
|
58662
|
-
merged.license.lastVerifiedAt = asString$
|
|
58663
|
-
merged.license.nextCheckAt = asString$
|
|
58664
|
-
merged.license.lastVerificationError = asString$
|
|
58665
|
-
merged.license.signature = asString$
|
|
58706
|
+
merged.license.licenseKey = asString$10(merged.license.licenseKey);
|
|
58707
|
+
merged.license.purchaseEmail = asString$10(merged.license.purchaseEmail);
|
|
58708
|
+
merged.license.lastVerifiedAt = asString$10(merged.license.lastVerifiedAt);
|
|
58709
|
+
merged.license.nextCheckAt = asString$10(merged.license.nextCheckAt);
|
|
58710
|
+
merged.license.lastVerificationError = asString$10(merged.license.lastVerificationError);
|
|
58711
|
+
merged.license.signature = asString$10(merged.license.signature);
|
|
58666
58712
|
if (![
|
|
58667
58713
|
"inactive",
|
|
58668
58714
|
"active",
|
|
@@ -58681,63 +58727,63 @@ function normalizeAppState(raw) {
|
|
|
58681
58727
|
const allowedPreferenceKeys = new Set(Object.keys(defaults.preferences));
|
|
58682
58728
|
for (const key of Object.keys(merged.preferences)) if (!allowedPreferenceKeys.has(key)) delete merged.preferences[key];
|
|
58683
58729
|
}
|
|
58684
|
-
if (!isRecord$
|
|
58685
|
-
if (!isRecord$
|
|
58730
|
+
if (!isRecord$8(merged.runtimeSettings)) merged.runtimeSettings = {};
|
|
58731
|
+
if (!isRecord$8(merged.ui)) merged.ui = clone(defaults.ui);
|
|
58686
58732
|
merged.ui.themeMode = merged.ui.themeMode === "light" || merged.ui.themeMode === "dark" ? merged.ui.themeMode : null;
|
|
58687
|
-
if (!isRecord$
|
|
58733
|
+
if (!isRecord$8(merged.ui.layout)) merged.ui.layout = clone(defaults.ui.layout);
|
|
58688
58734
|
if (typeof merged.ui.layout.sidebarCollapsed !== "boolean") merged.ui.layout.sidebarCollapsed = null;
|
|
58689
|
-
if (!isRecord$
|
|
58735
|
+
if (!isRecord$8(merged.ui.profiles)) merged.ui.profiles = clone(defaults.ui.profiles);
|
|
58690
58736
|
merged.ui.profiles.viewMode = merged.ui.profiles.viewMode === "cards" || merged.ui.profiles.viewMode === "compact" ? merged.ui.profiles.viewMode : null;
|
|
58691
|
-
merged.ui.profiles.sortBy = asString$
|
|
58692
|
-
merged.ui.profiles.groupBy = asString$
|
|
58693
|
-
merged.ui.profiles.planFilter = asString$
|
|
58694
|
-
merged.ui.profiles.healthFilter = asString$
|
|
58695
|
-
merged.ui.profiles.customGroupFilter = asString$
|
|
58737
|
+
merged.ui.profiles.sortBy = asString$10(merged.ui.profiles.sortBy);
|
|
58738
|
+
merged.ui.profiles.groupBy = asString$10(merged.ui.profiles.groupBy);
|
|
58739
|
+
merged.ui.profiles.planFilter = asString$10(merged.ui.profiles.planFilter);
|
|
58740
|
+
merged.ui.profiles.healthFilter = asString$10(merged.ui.profiles.healthFilter);
|
|
58741
|
+
merged.ui.profiles.customGroupFilter = asString$10(merged.ui.profiles.customGroupFilter);
|
|
58696
58742
|
if (typeof merged.ui.profiles.toolbarOpen !== "boolean") merged.ui.profiles.toolbarOpen = null;
|
|
58697
|
-
if (!isRecord$
|
|
58743
|
+
if (!isRecord$8(merged.ui.profiles.collapsedSections)) merged.ui.profiles.collapsedSections = {};
|
|
58698
58744
|
else merged.ui.profiles.collapsedSections = Object.fromEntries(Object.entries(merged.ui.profiles.collapsedSections).flatMap(([key, value]) => {
|
|
58699
|
-
const normalizedKey = asString$
|
|
58745
|
+
const normalizedKey = asString$10(key);
|
|
58700
58746
|
if (!normalizedKey || typeof value !== "boolean") return [];
|
|
58701
58747
|
return [[normalizedKey, value]];
|
|
58702
58748
|
}));
|
|
58703
|
-
if (!isRecord$
|
|
58749
|
+
if (!isRecord$8(merged.ui.onboarding)) merged.ui.onboarding = clone(defaults.ui.onboarding);
|
|
58704
58750
|
if (typeof merged.ui.onboarding.welcomeCompleted !== "boolean") merged.ui.onboarding.welcomeCompleted = false;
|
|
58705
58751
|
if (!Number.isFinite(merged.ui.onboarding.welcomeCompletedAt)) merged.ui.onboarding.welcomeCompletedAt = null;
|
|
58706
58752
|
merged.ui.onboarding.welcomeResumeStep = merged.ui.onboarding.welcomeResumeStep === 2 ? 2 : null;
|
|
58707
|
-
if (!isRecord$
|
|
58753
|
+
if (!isRecord$8(merged.ui.onboarding.milestones)) merged.ui.onboarding.milestones = clone(defaults.ui.onboarding.milestones);
|
|
58708
58754
|
if (typeof merged.ui.onboarding.milestones.firstProfileAdded !== "boolean") merged.ui.onboarding.milestones.firstProfileAdded = false;
|
|
58709
58755
|
if (typeof merged.ui.onboarding.milestones.secondProfileAdded !== "boolean") merged.ui.onboarding.milestones.secondProfileAdded = false;
|
|
58710
58756
|
if (!Number.isFinite(merged.ui.onboarding.sessionCount)) merged.ui.onboarding.sessionCount = 0;
|
|
58711
|
-
if (!isRecord$
|
|
58757
|
+
if (!isRecord$8(merged.ui.onboarding.nudgeCooldowns)) merged.ui.onboarding.nudgeCooldowns = {};
|
|
58712
58758
|
else merged.ui.onboarding.nudgeCooldowns = Object.fromEntries(Object.entries(merged.ui.onboarding.nudgeCooldowns).flatMap(([key, value]) => {
|
|
58713
|
-
const normalizedKey = asString$
|
|
58759
|
+
const normalizedKey = asString$10(key);
|
|
58714
58760
|
if (!normalizedKey || !Number.isFinite(value)) return [];
|
|
58715
58761
|
return [[normalizedKey, Number(value)]];
|
|
58716
58762
|
}));
|
|
58717
|
-
if (!isRecord$
|
|
58763
|
+
if (!isRecord$8(merged.ui.onboarding.nudgeDismissCount)) merged.ui.onboarding.nudgeDismissCount = {};
|
|
58718
58764
|
else merged.ui.onboarding.nudgeDismissCount = Object.fromEntries(Object.entries(merged.ui.onboarding.nudgeDismissCount).flatMap(([key, value]) => {
|
|
58719
|
-
const normalizedKey = asString$
|
|
58765
|
+
const normalizedKey = asString$10(key);
|
|
58720
58766
|
if (!normalizedKey || !Number.isFinite(value)) return [];
|
|
58721
58767
|
return [[normalizedKey, Number(value)]];
|
|
58722
58768
|
}));
|
|
58723
58769
|
if (typeof merged.ui.onboarding.proUnlockedCelebrated !== "boolean") merged.ui.onboarding.proUnlockedCelebrated = false;
|
|
58724
|
-
if (!isRecord$
|
|
58770
|
+
if (!isRecord$8(merged.ui.projectThreadSelections)) merged.ui.projectThreadSelections = {};
|
|
58725
58771
|
else merged.ui.projectThreadSelections = Object.fromEntries(Object.entries(merged.ui.projectThreadSelections).flatMap(([projectId, threadId]) => {
|
|
58726
|
-
const normalizedProjectId = asString$
|
|
58772
|
+
const normalizedProjectId = asString$10(projectId);
|
|
58727
58773
|
if (!normalizedProjectId) return [];
|
|
58728
58774
|
return [[normalizedProjectId, typeof threadId === "string" && threadId.trim().length > 0 ? threadId.trim() : null]];
|
|
58729
58775
|
}));
|
|
58730
|
-
merged.ui.duplicateWarningDismissedKey = asString$
|
|
58776
|
+
merged.ui.duplicateWarningDismissedKey = asString$10(merged.ui.duplicateWarningDismissedKey);
|
|
58731
58777
|
if (typeof merged.ui.pendingLicenseActivation !== "boolean") merged.ui.pendingLicenseActivation = false;
|
|
58732
58778
|
{
|
|
58733
58779
|
const allowedUiKeys = new Set(Object.keys(defaults.ui));
|
|
58734
58780
|
for (const key of Object.keys(merged.ui)) if (!allowedUiKeys.has(key)) delete merged.ui[key];
|
|
58735
58781
|
}
|
|
58736
|
-
if (!isRecord$
|
|
58737
|
-
if (!isRecord$
|
|
58782
|
+
if (!isRecord$8(merged.profileDashboard)) merged.profileDashboard = clone(defaults.profileDashboard);
|
|
58783
|
+
if (!isRecord$8(merged.profileDashboard.customGroupsByAccountKey)) merged.profileDashboard.customGroupsByAccountKey = {};
|
|
58738
58784
|
else merged.profileDashboard.customGroupsByAccountKey = Object.fromEntries(Object.entries(merged.profileDashboard.customGroupsByAccountKey).flatMap(([key, value]) => {
|
|
58739
|
-
const normalizedKey = asString$
|
|
58740
|
-
const normalizedValue = asString$
|
|
58785
|
+
const normalizedKey = asString$10(key);
|
|
58786
|
+
const normalizedValue = asString$10(value);
|
|
58741
58787
|
if (!normalizedKey || !normalizedValue) return [];
|
|
58742
58788
|
return [[normalizedKey, normalizedValue]];
|
|
58743
58789
|
}));
|
|
@@ -58745,54 +58791,54 @@ function normalizeAppState(raw) {
|
|
|
58745
58791
|
const allowedProfileDashboardKeys = new Set(Object.keys(defaults.profileDashboard));
|
|
58746
58792
|
for (const key of Object.keys(merged.profileDashboard)) if (!allowedProfileDashboardKeys.has(key)) delete merged.profileDashboard[key];
|
|
58747
58793
|
}
|
|
58748
|
-
const legacyProjectSettingsByPath = isRecord$
|
|
58749
|
-
if (!isRecord$
|
|
58794
|
+
const legacyProjectSettingsByPath = isRecord$8(raw.projectSettingsByPath) ? raw.projectSettingsByPath : null;
|
|
58795
|
+
if (!isRecord$8(merged.workspaceSettingsByPath)) merged.workspaceSettingsByPath = {};
|
|
58750
58796
|
if (legacyProjectSettingsByPath) merged.workspaceSettingsByPath = {
|
|
58751
58797
|
...legacyProjectSettingsByPath,
|
|
58752
58798
|
...merged.workspaceSettingsByPath
|
|
58753
58799
|
};
|
|
58754
58800
|
delete merged.projectSettingsByPath;
|
|
58755
|
-
if (!isRecord$
|
|
58756
|
-
if (!isRecord$
|
|
58757
|
-
if (!isRecord$
|
|
58801
|
+
if (!isRecord$8(merged.conversationCategoriesByCwd)) merged.conversationCategoriesByCwd = {};
|
|
58802
|
+
if (!isRecord$8(merged.conversationCategoryAssignmentsByCwd)) merged.conversationCategoryAssignmentsByCwd = {};
|
|
58803
|
+
if (!isRecord$8(merged.git)) merged.git = clone(defaults.git);
|
|
58758
58804
|
merged.git.commitMessagePrompt = normalizeCommitMessagePrompt(merged.git.commitMessagePrompt) ?? DEFAULT_COMMIT_MESSAGE_PROMPT;
|
|
58759
58805
|
{
|
|
58760
58806
|
const allowedGitKeys = new Set(Object.keys(defaults.git));
|
|
58761
58807
|
for (const key of Object.keys(merged.git)) if (!allowedGitKeys.has(key)) delete merged.git[key];
|
|
58762
58808
|
}
|
|
58763
|
-
if (!isRecord$
|
|
58809
|
+
if (!isRecord$8(merged.skills)) merged.skills = clone(defaults.skills);
|
|
58764
58810
|
if (!Array.isArray(merged.skills.sources)) merged.skills.sources = [];
|
|
58765
|
-
if (!isRecord$
|
|
58766
|
-
if (!isRecord$
|
|
58767
|
-
merged.sync.lastPushAt = asString$
|
|
58768
|
-
merged.sync.lastPullAt = asString$
|
|
58769
|
-
merged.sync.lastError = asString$
|
|
58770
|
-
merged.sync.remoteUpdatedAt = asString$
|
|
58771
|
-
if (!isRecord$
|
|
58772
|
-
merged.analytics.anonymousId = asString$
|
|
58811
|
+
if (!isRecord$8(merged.skills.installsBySlug)) merged.skills.installsBySlug = {};
|
|
58812
|
+
if (!isRecord$8(merged.sync)) merged.sync = clone(defaults.sync);
|
|
58813
|
+
merged.sync.lastPushAt = asString$10(merged.sync.lastPushAt);
|
|
58814
|
+
merged.sync.lastPullAt = asString$10(merged.sync.lastPullAt);
|
|
58815
|
+
merged.sync.lastError = asString$10(merged.sync.lastError);
|
|
58816
|
+
merged.sync.remoteUpdatedAt = asString$10(merged.sync.remoteUpdatedAt);
|
|
58817
|
+
if (!isRecord$8(merged.analytics)) merged.analytics = isRecord$8(merged.telemetry) ? clone(merged.telemetry) : clone(defaults.analytics);
|
|
58818
|
+
merged.analytics.anonymousId = asString$10(merged.analytics.anonymousId);
|
|
58773
58819
|
if (!merged.analytics.anonymousId) {
|
|
58774
|
-
const legacyInstallId = asString$
|
|
58820
|
+
const legacyInstallId = asString$10(merged.telemetry?.installId);
|
|
58775
58821
|
merged.analytics.anonymousId = legacyInstallId;
|
|
58776
58822
|
}
|
|
58777
58823
|
if (typeof merged.analytics.enabled !== "boolean") merged.analytics.enabled = true;
|
|
58778
|
-
merged.analytics.lastFlushAt = asString$
|
|
58779
|
-
merged.analytics.lastError = asString$
|
|
58824
|
+
merged.analytics.lastFlushAt = asString$10(merged.analytics.lastFlushAt);
|
|
58825
|
+
merged.analytics.lastError = asString$10(merged.analytics.lastError);
|
|
58780
58826
|
if ("telemetry" in merged) delete merged.telemetry;
|
|
58781
|
-
if (!isRecord$
|
|
58782
|
-
if (!isRecord$
|
|
58827
|
+
if (!isRecord$8(merged.profilesByName)) merged.profilesByName = {};
|
|
58828
|
+
if (!isRecord$8(merged.migration)) merged.migration = clone(defaults.migration);
|
|
58783
58829
|
if (![
|
|
58784
58830
|
"pending",
|
|
58785
58831
|
"pending_local_storage",
|
|
58786
58832
|
"complete"
|
|
58787
58833
|
].includes(merged.migration.status)) merged.migration.status = "pending";
|
|
58788
|
-
merged.migration.startedAt = asString$
|
|
58789
|
-
merged.migration.completedAt = asString$
|
|
58790
|
-
merged.migration.localStorageImportedAt = asString$
|
|
58791
|
-
merged.migration.lastError = asString$
|
|
58834
|
+
merged.migration.startedAt = asString$10(merged.migration.startedAt);
|
|
58835
|
+
merged.migration.completedAt = asString$10(merged.migration.completedAt);
|
|
58836
|
+
merged.migration.localStorageImportedAt = asString$10(merged.migration.localStorageImportedAt);
|
|
58837
|
+
merged.migration.lastError = asString$10(merged.migration.lastError);
|
|
58792
58838
|
return merged;
|
|
58793
58839
|
}
|
|
58794
58840
|
function deepMerge(base, patch) {
|
|
58795
|
-
if (!isRecord$
|
|
58841
|
+
if (!isRecord$8(base) || !isRecord$8(patch)) return clone(patch ?? base);
|
|
58796
58842
|
const next = { ...base };
|
|
58797
58843
|
for (const [key, patchValue] of Object.entries(patch)) {
|
|
58798
58844
|
if (patchValue === void 0) continue;
|
|
@@ -58801,7 +58847,7 @@ function deepMerge(base, patch) {
|
|
|
58801
58847
|
next[key] = clone(patchValue);
|
|
58802
58848
|
continue;
|
|
58803
58849
|
}
|
|
58804
|
-
if (isRecord$
|
|
58850
|
+
if (isRecord$8(currentValue) && isRecord$8(patchValue)) {
|
|
58805
58851
|
next[key] = deepMerge(currentValue, patchValue);
|
|
58806
58852
|
continue;
|
|
58807
58853
|
}
|
|
@@ -58948,12 +58994,12 @@ function isGeneralChatWorkspaceRoot(workspaceRoot) {
|
|
|
58948
58994
|
}
|
|
58949
58995
|
//#endregion
|
|
58950
58996
|
//#region ../../packages/runtime-codex/src/codex/settings.ts
|
|
58951
|
-
function asString$
|
|
58997
|
+
function asString$9(value) {
|
|
58952
58998
|
if (typeof value !== "string") return null;
|
|
58953
58999
|
const trimmed = value.trim();
|
|
58954
59000
|
return trimmed.length > 0 ? trimmed : null;
|
|
58955
59001
|
}
|
|
58956
|
-
function isRecord$
|
|
59002
|
+
function isRecord$7(value) {
|
|
58957
59003
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
58958
59004
|
}
|
|
58959
59005
|
function parseAutoRoll(raw) {
|
|
@@ -58965,8 +59011,8 @@ function parseAutoRoll(raw) {
|
|
|
58965
59011
|
}
|
|
58966
59012
|
}
|
|
58967
59013
|
function parseStoredLicense(raw) {
|
|
58968
|
-
if (!isRecord$
|
|
58969
|
-
const statusCandidate = asString$
|
|
59014
|
+
if (!isRecord$7(raw)) return null;
|
|
59015
|
+
const statusCandidate = asString$9(raw.status);
|
|
58970
59016
|
const status = [
|
|
58971
59017
|
"inactive",
|
|
58972
59018
|
"active",
|
|
@@ -58974,13 +59020,13 @@ function parseStoredLicense(raw) {
|
|
|
58974
59020
|
"error"
|
|
58975
59021
|
].includes(statusCandidate ?? "") ? statusCandidate : void 0;
|
|
58976
59022
|
const license = {
|
|
58977
|
-
licenseKey: asString$
|
|
58978
|
-
purchaseEmail: asString$
|
|
58979
|
-
lastVerifiedAt: asString$
|
|
58980
|
-
nextCheckAt: asString$
|
|
58981
|
-
lastVerificationError: asString$
|
|
59023
|
+
licenseKey: asString$9(raw.licenseKey ?? raw.license_key),
|
|
59024
|
+
purchaseEmail: asString$9(raw.purchaseEmail ?? raw.purchase_email),
|
|
59025
|
+
lastVerifiedAt: asString$9(raw.lastVerifiedAt ?? raw.last_verified_at),
|
|
59026
|
+
nextCheckAt: asString$9(raw.nextCheckAt ?? raw.next_check_at),
|
|
59027
|
+
lastVerificationError: asString$9(raw.lastVerificationError ?? raw.last_verification_error),
|
|
58982
59028
|
status,
|
|
58983
|
-
signature: asString$
|
|
59029
|
+
signature: asString$9(raw.signature)
|
|
58984
59030
|
};
|
|
58985
59031
|
return Boolean(license.licenseKey || license.purchaseEmail || license.lastVerifiedAt || license.nextCheckAt || license.lastVerificationError || license.status) ? license : null;
|
|
58986
59032
|
}
|
|
@@ -59047,14 +59093,14 @@ async function readCodexSettingsJsonRaw() {
|
|
|
59047
59093
|
};
|
|
59048
59094
|
}
|
|
59049
59095
|
async function writeCodexSettingsJsonRaw(payload) {
|
|
59050
|
-
if (!isRecord$
|
|
59096
|
+
if (!isRecord$7(payload)) return;
|
|
59051
59097
|
const autoRoll = parseAutoRoll(payload.autoRoll ?? payload.auto_roll);
|
|
59052
59098
|
const license = parseStoredLicense(payload.license);
|
|
59053
59099
|
await patchAppState({
|
|
59054
59100
|
app: {
|
|
59055
|
-
lastProfileName: asString$
|
|
59056
|
-
lastAppVersion: asString$
|
|
59057
|
-
pendingUpdateVersion: asString$
|
|
59101
|
+
lastProfileName: asString$9(payload.lastProfileName ?? payload.last_profile_name),
|
|
59102
|
+
lastAppVersion: asString$9(payload.lastAppVersion ?? payload.last_app_version),
|
|
59103
|
+
pendingUpdateVersion: asString$9(payload.pendingUpdateVersion ?? payload.pending_update_version)
|
|
59058
59104
|
},
|
|
59059
59105
|
autoRoll: autoRoll ? {
|
|
59060
59106
|
enabled: autoRoll.enabled,
|
|
@@ -59084,11 +59130,11 @@ async function writeCodexSettingsJsonRaw(payload) {
|
|
|
59084
59130
|
folderHistory: Array.isArray(payload.folderHistory) ? payload.folderHistory : void 0,
|
|
59085
59131
|
pinnedPaths: Array.isArray(payload.pinnedPaths) ? payload.pinnedPaths : void 0
|
|
59086
59132
|
},
|
|
59087
|
-
workspaceSettingsByPath: isRecord$
|
|
59088
|
-
conversationCategoriesByCwd: isRecord$
|
|
59089
|
-
conversationCategoryAssignmentsByCwd: isRecord$
|
|
59090
|
-
git: isRecord$
|
|
59091
|
-
sync: isRecord$
|
|
59133
|
+
workspaceSettingsByPath: isRecord$7(payload.workspaceSettingsByPath) ? payload.workspaceSettingsByPath : isRecord$7(payload.projectSettingsByPath) ? payload.projectSettingsByPath : void 0,
|
|
59134
|
+
conversationCategoriesByCwd: isRecord$7(payload.categoriesByCwd) ? payload.categoriesByCwd : void 0,
|
|
59135
|
+
conversationCategoryAssignmentsByCwd: isRecord$7(payload.conversationCategoryByCwd) ? payload.conversationCategoryByCwd : void 0,
|
|
59136
|
+
git: isRecord$7(payload.git) ? payload.git : void 0,
|
|
59137
|
+
sync: isRecord$7(payload.sync) ? payload.sync : void 0
|
|
59092
59138
|
});
|
|
59093
59139
|
}
|
|
59094
59140
|
//#endregion
|
|
@@ -59964,12 +60010,12 @@ function logError(...args) {
|
|
|
59964
60010
|
console.error(...args);
|
|
59965
60011
|
}
|
|
59966
60012
|
function logInfo(...args) {
|
|
59967
|
-
if (isTestEnv && !isMocked(console.
|
|
59968
|
-
console.
|
|
60013
|
+
if (isTestEnv && !isMocked(console.info)) return;
|
|
60014
|
+
console.info(...args);
|
|
59969
60015
|
}
|
|
59970
60016
|
//#endregion
|
|
59971
60017
|
//#region ../../packages/runtime-codex/src/codex/app-server.ts
|
|
59972
|
-
function isRecord$
|
|
60018
|
+
function isRecord$6(value) {
|
|
59973
60019
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
59974
60020
|
}
|
|
59975
60021
|
function asTrimmedString$2(value) {
|
|
@@ -59990,7 +60036,7 @@ function isThreadNotFoundError$1(error) {
|
|
|
59990
60036
|
const lower = message.toLowerCase();
|
|
59991
60037
|
return lower.includes("thread not found") || lower.includes("rollout");
|
|
59992
60038
|
}
|
|
59993
|
-
function asString$
|
|
60039
|
+
function asString$8(value) {
|
|
59994
60040
|
return typeof value === "string" ? value : value != null ? String(value) : "";
|
|
59995
60041
|
}
|
|
59996
60042
|
function isInlineImageValue(value) {
|
|
@@ -59998,12 +60044,12 @@ function isInlineImageValue(value) {
|
|
|
59998
60044
|
return normalized.startsWith("data:") || normalized.startsWith("http://") || normalized.startsWith("https://");
|
|
59999
60045
|
}
|
|
60000
60046
|
function normalizeSendUserMessageItem(value) {
|
|
60001
|
-
if (!isRecord$
|
|
60002
|
-
const type = asString$
|
|
60047
|
+
if (!isRecord$6(value)) return null;
|
|
60048
|
+
const type = asString$8(value.type).trim();
|
|
60003
60049
|
if (!type) return null;
|
|
60004
|
-
const data = isRecord$
|
|
60050
|
+
const data = isRecord$6(value.data) ? value.data : {};
|
|
60005
60051
|
if (type === "text") {
|
|
60006
|
-
const text = asString$
|
|
60052
|
+
const text = asString$8(data.text ?? value.text);
|
|
60007
60053
|
if (!text.trim()) return null;
|
|
60008
60054
|
return {
|
|
60009
60055
|
type: "text",
|
|
@@ -60011,7 +60057,7 @@ function normalizeSendUserMessageItem(value) {
|
|
|
60011
60057
|
};
|
|
60012
60058
|
}
|
|
60013
60059
|
if (type === "image") {
|
|
60014
|
-
const imageUrl = asString$
|
|
60060
|
+
const imageUrl = asString$8(data.image_url ?? data.imageUrl ?? data.url ?? value.image_url ?? value.imageUrl ?? value.url).trim();
|
|
60015
60061
|
if (!imageUrl) return null;
|
|
60016
60062
|
return {
|
|
60017
60063
|
type: "image",
|
|
@@ -60019,7 +60065,7 @@ function normalizeSendUserMessageItem(value) {
|
|
|
60019
60065
|
};
|
|
60020
60066
|
}
|
|
60021
60067
|
if (type === "localImage") {
|
|
60022
|
-
const path = asString$
|
|
60068
|
+
const path = asString$8(data.path ?? value.path).trim();
|
|
60023
60069
|
if (!path) return null;
|
|
60024
60070
|
return {
|
|
60025
60071
|
type: "localImage",
|
|
@@ -60030,13 +60076,13 @@ function normalizeSendUserMessageItem(value) {
|
|
|
60030
60076
|
}
|
|
60031
60077
|
function normalizeTurnInputParams(params) {
|
|
60032
60078
|
const normalized = { ...params };
|
|
60033
|
-
const threadId = asString$
|
|
60034
|
-
if (threadId && !asString$
|
|
60035
|
-
const expectedTurnId = asString$
|
|
60036
|
-
if (expectedTurnId && !asString$
|
|
60037
|
-
const turnId = asString$
|
|
60038
|
-
if (turnId && !asString$
|
|
60039
|
-
const providedInput = Array.isArray(params.input) ? params.input.filter((entry) => isRecord$
|
|
60079
|
+
const threadId = asString$8(params.threadId ?? params.thread_id ?? params.conversationId ?? params.conversation_id ?? "").trim();
|
|
60080
|
+
if (threadId && !asString$8(params.threadId).trim()) normalized.threadId = threadId;
|
|
60081
|
+
const expectedTurnId = asString$8(params.expectedTurnId ?? params.expected_turn_id ?? params.turnId ?? params.turn_id ?? "").trim();
|
|
60082
|
+
if (expectedTurnId && !asString$8(params.expectedTurnId).trim()) normalized.expectedTurnId = expectedTurnId;
|
|
60083
|
+
const turnId = asString$8(params.turnId ?? params.turn_id ?? expectedTurnId).trim();
|
|
60084
|
+
if (turnId && !asString$8(params.turnId).trim()) normalized.turnId = turnId;
|
|
60085
|
+
const providedInput = Array.isArray(params.input) ? params.input.filter((entry) => isRecord$6(entry)) : [];
|
|
60040
60086
|
if (providedInput.length > 0) {
|
|
60041
60087
|
normalized.input = providedInput;
|
|
60042
60088
|
return normalized;
|
|
@@ -60044,17 +60090,17 @@ function normalizeTurnInputParams(params) {
|
|
|
60044
60090
|
const providedItems = Array.isArray(params.items) ? params.items.map((item) => normalizeSendUserMessageItem(item)).filter((item) => item !== null) : [];
|
|
60045
60091
|
if (providedItems.length > 0) {
|
|
60046
60092
|
const input = providedItems.flatMap((item) => {
|
|
60047
|
-
const type = asString$
|
|
60048
|
-
const data = isRecord$
|
|
60093
|
+
const type = asString$8(item.type).trim();
|
|
60094
|
+
const data = isRecord$6(item.data) ? item.data : item;
|
|
60049
60095
|
if (type === "text") {
|
|
60050
|
-
const text = asString$
|
|
60096
|
+
const text = asString$8(data.text).trim();
|
|
60051
60097
|
return text ? [{
|
|
60052
60098
|
type: "text",
|
|
60053
60099
|
text
|
|
60054
60100
|
}] : [];
|
|
60055
60101
|
}
|
|
60056
60102
|
if (type === "localImage") {
|
|
60057
|
-
const path = asString$
|
|
60103
|
+
const path = asString$8(data.path).trim();
|
|
60058
60104
|
return path ? [{
|
|
60059
60105
|
type: "localImage",
|
|
60060
60106
|
path
|
|
@@ -60068,13 +60114,13 @@ function normalizeTurnInputParams(params) {
|
|
|
60068
60114
|
}
|
|
60069
60115
|
}
|
|
60070
60116
|
const input = [];
|
|
60071
|
-
const text = asString$
|
|
60117
|
+
const text = asString$8(params.text);
|
|
60072
60118
|
if (text.trim()) input.push({
|
|
60073
60119
|
type: "text",
|
|
60074
60120
|
text
|
|
60075
60121
|
});
|
|
60076
60122
|
if (Array.isArray(params.images)) for (const candidate of params.images) {
|
|
60077
|
-
const image = asString$
|
|
60123
|
+
const image = asString$8(candidate).trim();
|
|
60078
60124
|
if (!image || isInlineImageValue(image)) continue;
|
|
60079
60125
|
input.push({
|
|
60080
60126
|
type: "localImage",
|
|
@@ -60088,7 +60134,7 @@ function pickMethodKind(method, params) {
|
|
|
60088
60134
|
const normalized = method.toLowerCase();
|
|
60089
60135
|
if (normalized.includes("requestapproval")) return "approval";
|
|
60090
60136
|
if (normalized.includes("requestuserinput")) return "user_input";
|
|
60091
|
-
if (isRecord$
|
|
60137
|
+
if (isRecord$6(params)) {
|
|
60092
60138
|
if ("file_changes" in params || "fileChanges" in params || "grant_root" in params || "grantRoot" in params) return "patch";
|
|
60093
60139
|
if ("command" in params || "parsed_cmd" in params || "parsedCmd" in params || "cwd" in params) return "exec";
|
|
60094
60140
|
}
|
|
@@ -60125,7 +60171,7 @@ function getRequestTimeoutMs(method) {
|
|
|
60125
60171
|
return DEFAULT_REQUEST_TIMEOUT_MS;
|
|
60126
60172
|
}
|
|
60127
60173
|
function normalizeThreadLiveWorkspaceId(value) {
|
|
60128
|
-
return asString$
|
|
60174
|
+
return asString$8(value).trim() || DEFAULT_THREAD_LIVE_WORKSPACE_ID;
|
|
60129
60175
|
}
|
|
60130
60176
|
function threadLiveKey(workspaceId, threadId) {
|
|
60131
60177
|
return `${workspaceId}:${threadId}`;
|
|
@@ -60290,7 +60336,7 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60290
60336
|
try {
|
|
60291
60337
|
const response = await this.request("addConversationListener", listenerParams);
|
|
60292
60338
|
this.addConversationListenerSupported = true;
|
|
60293
|
-
return isRecord$
|
|
60339
|
+
return isRecord$6(response) ? response : null;
|
|
60294
60340
|
} catch (error) {
|
|
60295
60341
|
if (isMethodUnavailableError(error, "addConversationListener")) {
|
|
60296
60342
|
this.addConversationListenerSupported = false;
|
|
@@ -60305,7 +60351,7 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60305
60351
|
try {
|
|
60306
60352
|
const response = await this.request("addConversationListener", listenerParams);
|
|
60307
60353
|
this.addConversationListenerSupported = true;
|
|
60308
|
-
return isRecord$
|
|
60354
|
+
return isRecord$6(response) ? response : null;
|
|
60309
60355
|
} catch (resumeError) {
|
|
60310
60356
|
if (isMethodUnavailableError(resumeError, "addConversationListener")) {
|
|
60311
60357
|
this.addConversationListenerSupported = false;
|
|
@@ -60329,8 +60375,8 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60329
60375
|
}
|
|
60330
60376
|
async addConversationListener(params) {
|
|
60331
60377
|
if (this.addConversationListenerSupported === false) return {};
|
|
60332
|
-
const conversationId = asString$
|
|
60333
|
-
const workspaceId = asString$
|
|
60378
|
+
const conversationId = asString$8(params.conversationId ?? params.threadId ?? params.thread_id ?? "").trim();
|
|
60379
|
+
const workspaceId = asString$8(params.workspaceId ?? params.workspace_id ?? "").trim();
|
|
60334
60380
|
if (!conversationId) try {
|
|
60335
60381
|
const response = await this.request("addConversationListener", params);
|
|
60336
60382
|
this.addConversationListenerSupported = true;
|
|
@@ -60358,7 +60404,7 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60358
60404
|
}
|
|
60359
60405
|
async threadLiveSubscribe(params) {
|
|
60360
60406
|
const workspaceId = normalizeThreadLiveWorkspaceId(params.workspaceId ?? params.workspace_id);
|
|
60361
|
-
const threadId = asString$
|
|
60407
|
+
const threadId = asString$8(params.threadId ?? params.thread_id ?? params.conversationId).trim();
|
|
60362
60408
|
if (!threadId) return {};
|
|
60363
60409
|
const key = threadLiveKey(workspaceId, threadId);
|
|
60364
60410
|
this.threadLiveModeByKey.set(key, "listener");
|
|
@@ -60367,7 +60413,7 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60367
60413
|
}
|
|
60368
60414
|
async threadLiveUnsubscribe(params) {
|
|
60369
60415
|
const workspaceId = normalizeThreadLiveWorkspaceId(params.workspaceId ?? params.workspace_id);
|
|
60370
|
-
const threadId = asString$
|
|
60416
|
+
const threadId = asString$8(params.threadId ?? params.thread_id ?? params.conversationId).trim();
|
|
60371
60417
|
if (!threadId) return {};
|
|
60372
60418
|
const key = threadLiveKey(workspaceId, threadId);
|
|
60373
60419
|
this.threadLiveModeByKey.delete(key);
|
|
@@ -60515,7 +60561,7 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60515
60561
|
listPendingUserInputRequests() {
|
|
60516
60562
|
return [...this.pendingServerRequests.values()].filter((request) => request.kind === "user_input").map((request) => {
|
|
60517
60563
|
const workspaceId = asTrimmedString$2(request.params.workspace_id ?? request.params.workspaceId);
|
|
60518
|
-
const params = isRecord$
|
|
60564
|
+
const params = isRecord$6(request.params.params) ? request.params.params : request.params;
|
|
60519
60565
|
if (!workspaceId) return null;
|
|
60520
60566
|
return {
|
|
60521
60567
|
workspace_id: workspaceId,
|
|
@@ -60628,7 +60674,7 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60628
60674
|
this.logParseFailure(line, parseError);
|
|
60629
60675
|
return true;
|
|
60630
60676
|
}
|
|
60631
|
-
if (!isRecord$
|
|
60677
|
+
if (!isRecord$6(parsed)) {
|
|
60632
60678
|
logWarn("[app-server] unexpected JSON message", parsed);
|
|
60633
60679
|
return true;
|
|
60634
60680
|
}
|
|
@@ -60717,9 +60763,9 @@ var CodexAppServer = class extends EventEmitter {
|
|
|
60717
60763
|
id: request.id,
|
|
60718
60764
|
kind,
|
|
60719
60765
|
method: request.method,
|
|
60720
|
-
params: isRecord$
|
|
60766
|
+
params: isRecord$6(request.params) ? request.params : {}
|
|
60721
60767
|
});
|
|
60722
|
-
const params = isRecord$
|
|
60768
|
+
const params = isRecord$6(request.params) ? request.params : {};
|
|
60723
60769
|
if (kind === "exec") this.emit("codex:exec-command-request", {
|
|
60724
60770
|
requestToken: token,
|
|
60725
60771
|
params
|
|
@@ -61480,11 +61526,11 @@ function startExternalCodexThreadSyncWatcher(homePath) {
|
|
|
61480
61526
|
function resolveStateDbPath(stateDir) {
|
|
61481
61527
|
return nodePath.join(stateDir, "state.sqlite");
|
|
61482
61528
|
}
|
|
61483
|
-
function asString$
|
|
61529
|
+
function asString$7(value) {
|
|
61484
61530
|
return typeof value === "string" ? value : value == null ? "" : String(value);
|
|
61485
61531
|
}
|
|
61486
61532
|
function asTrimmedString$1(value) {
|
|
61487
|
-
return asString$
|
|
61533
|
+
return asString$7(value).trim();
|
|
61488
61534
|
}
|
|
61489
61535
|
function asFiniteNumber(value) {
|
|
61490
61536
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
@@ -63168,7 +63214,7 @@ function proposedPlanIdFromEvent(event, threadId) {
|
|
|
63168
63214
|
if (event.itemId) return `plan:${threadId}:item:${event.itemId}`;
|
|
63169
63215
|
return `plan:${threadId}:event:${event.eventId}`;
|
|
63170
63216
|
}
|
|
63171
|
-
function asString$
|
|
63217
|
+
function asString$6(value) {
|
|
63172
63218
|
return typeof value === "string" ? value : void 0;
|
|
63173
63219
|
}
|
|
63174
63220
|
function runtimePayloadRecord(event) {
|
|
@@ -63186,13 +63232,13 @@ function normalizeRuntimeTurnState(value) {
|
|
|
63186
63232
|
}
|
|
63187
63233
|
}
|
|
63188
63234
|
function runtimeTurnState(event) {
|
|
63189
|
-
return normalizeRuntimeTurnState(asString$
|
|
63235
|
+
return normalizeRuntimeTurnState(asString$6(runtimePayloadRecord(event)?.state));
|
|
63190
63236
|
}
|
|
63191
63237
|
function runtimeTurnErrorMessage(event) {
|
|
63192
|
-
return asString$
|
|
63238
|
+
return asString$6(runtimePayloadRecord(event)?.errorMessage);
|
|
63193
63239
|
}
|
|
63194
63240
|
function runtimeErrorMessageFromEvent(event) {
|
|
63195
|
-
return asString$
|
|
63241
|
+
return asString$6(runtimePayloadRecord(event)?.message);
|
|
63196
63242
|
}
|
|
63197
63243
|
function shouldTriggerPassiveImportedThreadRecovery(event) {
|
|
63198
63244
|
switch (event.type) {
|
|
@@ -63930,13 +63976,13 @@ function asObject$1(value) {
|
|
|
63930
63976
|
if (!value || typeof value !== "object") return;
|
|
63931
63977
|
return value;
|
|
63932
63978
|
}
|
|
63933
|
-
function asString$
|
|
63979
|
+
function asString$5(value) {
|
|
63934
63980
|
return typeof value === "string" ? value : void 0;
|
|
63935
63981
|
}
|
|
63936
63982
|
function readCodexAccountSnapshot(response) {
|
|
63937
63983
|
const record = asObject$1(response);
|
|
63938
63984
|
const account = asObject$1(record?.account) ?? record;
|
|
63939
|
-
const accountType = asString$
|
|
63985
|
+
const accountType = asString$5(account?.type);
|
|
63940
63986
|
if (accountType === "apiKey") return {
|
|
63941
63987
|
type: "apiKey",
|
|
63942
63988
|
planType: null,
|
|
@@ -65480,7 +65526,7 @@ function asObject(value) {
|
|
|
65480
65526
|
if (!value || typeof value !== "object") return;
|
|
65481
65527
|
return value;
|
|
65482
65528
|
}
|
|
65483
|
-
function asString$
|
|
65529
|
+
function asString$4(value) {
|
|
65484
65530
|
return typeof value === "string" ? value : void 0;
|
|
65485
65531
|
}
|
|
65486
65532
|
function asArray(value) {
|
|
@@ -65499,7 +65545,7 @@ function toTurnStatus(value) {
|
|
|
65499
65545
|
}
|
|
65500
65546
|
}
|
|
65501
65547
|
function normalizeItemType(raw) {
|
|
65502
|
-
const type = asString$
|
|
65548
|
+
const type = asString$4(raw);
|
|
65503
65549
|
if (!type) return "item";
|
|
65504
65550
|
return type.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[._/-]/g, " ").replace(/\s+/g, " ").trim().toLowerCase();
|
|
65505
65551
|
}
|
|
@@ -65541,16 +65587,16 @@ function itemTitle(itemType) {
|
|
|
65541
65587
|
function itemDetail(item, payload) {
|
|
65542
65588
|
const nestedResult = asObject(item.result);
|
|
65543
65589
|
const candidates = [
|
|
65544
|
-
asString$
|
|
65545
|
-
asString$
|
|
65546
|
-
asString$
|
|
65547
|
-
asString$
|
|
65548
|
-
asString$
|
|
65549
|
-
asString$
|
|
65550
|
-
asString$
|
|
65551
|
-
asString$
|
|
65552
|
-
asString$
|
|
65553
|
-
asString$
|
|
65590
|
+
asString$4(item.command),
|
|
65591
|
+
asString$4(item.title),
|
|
65592
|
+
asString$4(item.summary),
|
|
65593
|
+
asString$4(item.text),
|
|
65594
|
+
asString$4(item.path),
|
|
65595
|
+
asString$4(item.prompt),
|
|
65596
|
+
asString$4(nestedResult?.command),
|
|
65597
|
+
asString$4(payload.command),
|
|
65598
|
+
asString$4(payload.message),
|
|
65599
|
+
asString$4(payload.prompt)
|
|
65554
65600
|
];
|
|
65555
65601
|
for (const candidate of candidates) {
|
|
65556
65602
|
if (!candidate) continue;
|
|
@@ -65582,9 +65628,9 @@ function toRequestTypeFromKind(kind) {
|
|
|
65582
65628
|
}
|
|
65583
65629
|
function toRequestTypeFromResolvedPayload(payload) {
|
|
65584
65630
|
const request = asObject(payload?.request);
|
|
65585
|
-
const method = asString$
|
|
65631
|
+
const method = asString$4(request?.method) ?? asString$4(payload?.method);
|
|
65586
65632
|
if (method) return toRequestTypeFromMethod(method);
|
|
65587
|
-
const requestKind = asString$
|
|
65633
|
+
const requestKind = asString$4(request?.kind) ?? asString$4(payload?.requestKind);
|
|
65588
65634
|
if (requestKind) return toRequestTypeFromKind(requestKind);
|
|
65589
65635
|
return "unknown";
|
|
65590
65636
|
}
|
|
@@ -65610,17 +65656,17 @@ function toUserInputQuestions(payload) {
|
|
|
65610
65656
|
const options = asArray(question.options)?.map((option) => {
|
|
65611
65657
|
const optionRecord = asObject(option);
|
|
65612
65658
|
if (!optionRecord) return void 0;
|
|
65613
|
-
const label = asString$
|
|
65614
|
-
const description = asString$
|
|
65659
|
+
const label = asString$4(optionRecord.label)?.trim();
|
|
65660
|
+
const description = asString$4(optionRecord.description)?.trim();
|
|
65615
65661
|
if (!label || !description) return;
|
|
65616
65662
|
return {
|
|
65617
65663
|
label,
|
|
65618
65664
|
description
|
|
65619
65665
|
};
|
|
65620
65666
|
}).filter((option) => option !== void 0);
|
|
65621
|
-
const id = asString$
|
|
65622
|
-
const header = asString$
|
|
65623
|
-
const prompt = asString$
|
|
65667
|
+
const id = asString$4(question.id)?.trim();
|
|
65668
|
+
const header = asString$4(question.header)?.trim();
|
|
65669
|
+
const prompt = asString$4(question.question)?.trim();
|
|
65624
65670
|
const multiSelect = question.multiSelect === true || question.multi_select === true;
|
|
65625
65671
|
if (!id || !header || !prompt || !options || options.length === 0) return;
|
|
65626
65672
|
return {
|
|
@@ -65673,9 +65719,9 @@ function codexEventMessage(payload) {
|
|
|
65673
65719
|
}
|
|
65674
65720
|
function codexEventBase(event, canonicalThreadId) {
|
|
65675
65721
|
const msg = codexEventMessage(asObject(event.payload));
|
|
65676
|
-
const turnId = asString$
|
|
65677
|
-
const itemId = asString$
|
|
65678
|
-
const requestId = asString$
|
|
65722
|
+
const turnId = asString$4(msg?.turn_id) ?? asString$4(msg?.turnId);
|
|
65723
|
+
const itemId = asString$4(msg?.item_id) ?? asString$4(msg?.itemId);
|
|
65724
|
+
const requestId = asString$4(msg?.request_id) ?? asString$4(msg?.requestId);
|
|
65679
65725
|
const base = runtimeEventBase(event, canonicalThreadId);
|
|
65680
65726
|
const providerRefs = base.providerRefs ? {
|
|
65681
65727
|
...base.providerRefs,
|
|
@@ -65768,7 +65814,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65768
65814
|
payload: { questions }
|
|
65769
65815
|
}];
|
|
65770
65816
|
}
|
|
65771
|
-
const detail = asString$
|
|
65817
|
+
const detail = asString$4(payload?.command) ?? asString$4(payload?.reason) ?? asString$4(payload?.prompt);
|
|
65772
65818
|
return [{
|
|
65773
65819
|
...runtimeEventBase(event, canonicalThreadId),
|
|
65774
65820
|
type: "request.opened",
|
|
@@ -65825,7 +65871,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65825
65871
|
}
|
|
65826
65872
|
}];
|
|
65827
65873
|
if (event.method === "thread/started") {
|
|
65828
|
-
const providerThreadId = asString$
|
|
65874
|
+
const providerThreadId = asString$4(asObject(payload?.thread)?.id) ?? asString$4(payload?.threadId);
|
|
65829
65875
|
if (!providerThreadId) return [];
|
|
65830
65876
|
return [{
|
|
65831
65877
|
...runtimeEventBase(event, canonicalThreadId),
|
|
@@ -65841,7 +65887,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65841
65887
|
type: "thread.state.changed",
|
|
65842
65888
|
...runtimeEventBase(event, canonicalThreadId),
|
|
65843
65889
|
payload: {
|
|
65844
|
-
state: event.method === "thread/archived" ? "archived" : event.method === "thread/closed" ? "closed" : event.method === "thread/compacted" ? "compacted" : toThreadState(asString$
|
|
65890
|
+
state: event.method === "thread/archived" ? "archived" : event.method === "thread/closed" ? "closed" : event.method === "thread/compacted" ? "compacted" : toThreadState(asString$4(statusRecord?.type) ?? asString$4(threadStatusRecord?.type) ?? asString$4(threadRecord?.state) ?? payload?.state),
|
|
65845
65891
|
...event.payload !== void 0 ? { detail: event.payload } : {}
|
|
65846
65892
|
}
|
|
65847
65893
|
}];
|
|
@@ -65850,7 +65896,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65850
65896
|
type: "thread.metadata.updated",
|
|
65851
65897
|
...runtimeEventBase(event, canonicalThreadId),
|
|
65852
65898
|
payload: {
|
|
65853
|
-
...asString$
|
|
65899
|
+
...asString$4(payload?.threadName) ? { name: asString$4(payload?.threadName) } : {},
|
|
65854
65900
|
...event.payload !== void 0 ? { metadata: asObject(event.payload) } : {}
|
|
65855
65901
|
}
|
|
65856
65902
|
}];
|
|
@@ -65867,19 +65913,19 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65867
65913
|
turnId,
|
|
65868
65914
|
type: "turn.started",
|
|
65869
65915
|
payload: {
|
|
65870
|
-
...asString$
|
|
65871
|
-
...asString$
|
|
65916
|
+
...asString$4(turn?.model) ? { model: asString$4(turn?.model) } : {},
|
|
65917
|
+
...asString$4(turn?.effort) ? { effort: asString$4(turn?.effort) } : {}
|
|
65872
65918
|
}
|
|
65873
65919
|
}];
|
|
65874
65920
|
}
|
|
65875
65921
|
if (event.method === "turn/completed") {
|
|
65876
|
-
const errorMessage = asString$
|
|
65922
|
+
const errorMessage = asString$4(asObject(turn?.error)?.message);
|
|
65877
65923
|
return [{
|
|
65878
65924
|
...runtimeEventBase(event, canonicalThreadId),
|
|
65879
65925
|
type: "turn.completed",
|
|
65880
65926
|
payload: {
|
|
65881
65927
|
state: toTurnStatus(turn?.status),
|
|
65882
|
-
...asString$
|
|
65928
|
+
...asString$4(turn?.stopReason) ? { stopReason: asString$4(turn?.stopReason) } : {},
|
|
65883
65929
|
...turn?.usage !== void 0 ? { usage: turn.usage } : {},
|
|
65884
65930
|
...asObject(turn?.modelUsage) ? { modelUsage: asObject(turn?.modelUsage) } : {},
|
|
65885
65931
|
...asNumber$2(turn?.totalCostUsd) !== void 0 ? { totalCostUsd: asNumber$2(turn?.totalCostUsd) } : {},
|
|
@@ -65898,9 +65944,9 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65898
65944
|
...runtimeEventBase(event, canonicalThreadId),
|
|
65899
65945
|
type: "turn.plan.updated",
|
|
65900
65946
|
payload: {
|
|
65901
|
-
...asString$
|
|
65947
|
+
...asString$4(payload?.explanation) ? { explanation: asString$4(payload?.explanation) } : {},
|
|
65902
65948
|
plan: steps.map((entry) => asObject(entry)).filter((entry) => entry !== void 0).map((entry) => ({
|
|
65903
|
-
step: asString$
|
|
65949
|
+
step: asString$4(entry.step) ?? "step",
|
|
65904
65950
|
status: entry.status === "completed" || entry.status === "inProgress" ? entry.status : "pending"
|
|
65905
65951
|
}))
|
|
65906
65952
|
}
|
|
@@ -65909,7 +65955,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65909
65955
|
if (event.method === "turn/diff/updated") return [{
|
|
65910
65956
|
...runtimeEventBase(event, canonicalThreadId),
|
|
65911
65957
|
type: "turn.diff.updated",
|
|
65912
|
-
payload: { unifiedDiff: asString$
|
|
65958
|
+
payload: { unifiedDiff: asString$4(payload?.unifiedDiff) ?? asString$4(payload?.diff) ?? asString$4(payload?.patch) ?? "" }
|
|
65913
65959
|
}];
|
|
65914
65960
|
if (event.method === "item/started") {
|
|
65915
65961
|
const started = mapItemLifecycle(event, canonicalThreadId, "item.started");
|
|
@@ -65936,7 +65982,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65936
65982
|
return updated ? [updated] : [];
|
|
65937
65983
|
}
|
|
65938
65984
|
if (event.method === "item/plan/delta") {
|
|
65939
|
-
const delta = event.textDelta ?? asString$
|
|
65985
|
+
const delta = event.textDelta ?? asString$4(payload?.delta) ?? asString$4(payload?.text) ?? asString$4(asObject(payload?.content)?.text);
|
|
65940
65986
|
if (!delta || delta.length === 0) return [];
|
|
65941
65987
|
return [{
|
|
65942
65988
|
...runtimeEventBase(event, canonicalThreadId),
|
|
@@ -65945,7 +65991,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65945
65991
|
}];
|
|
65946
65992
|
}
|
|
65947
65993
|
if (event.method === "item/agentMessage/delta" || event.method === "item/commandExecution/outputDelta" || event.method === "item/fileChange/outputDelta" || event.method === "item/reasoning/summaryTextDelta" || event.method === "item/reasoning/textDelta") {
|
|
65948
|
-
const delta = event.textDelta ?? asString$
|
|
65994
|
+
const delta = event.textDelta ?? asString$4(payload?.delta) ?? asString$4(payload?.text) ?? asString$4(asObject(payload?.content)?.text);
|
|
65949
65995
|
if (!delta || delta.length === 0) return [];
|
|
65950
65996
|
return [{
|
|
65951
65997
|
...runtimeEventBase(event, canonicalThreadId),
|
|
@@ -65962,9 +66008,9 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65962
66008
|
...runtimeEventBase(event, canonicalThreadId),
|
|
65963
66009
|
type: "tool.progress",
|
|
65964
66010
|
payload: {
|
|
65965
|
-
...asString$
|
|
65966
|
-
...asString$
|
|
65967
|
-
...asString$
|
|
66011
|
+
...asString$4(payload?.toolUseId) ? { toolUseId: asString$4(payload?.toolUseId) } : {},
|
|
66012
|
+
...asString$4(payload?.toolName) ? { toolName: asString$4(payload?.toolName) } : {},
|
|
66013
|
+
...asString$4(payload?.summary) ? { summary: asString$4(payload?.summary) } : {},
|
|
65968
66014
|
...asNumber$2(payload?.elapsedSeconds) !== void 0 ? { elapsedSeconds: asNumber$2(payload?.elapsedSeconds) } : {}
|
|
65969
66015
|
}
|
|
65970
66016
|
}];
|
|
@@ -65986,21 +66032,21 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
65986
66032
|
}];
|
|
65987
66033
|
if (event.method === "codex/event/task_started") {
|
|
65988
66034
|
const msg = codexEventMessage(payload);
|
|
65989
|
-
const taskId = asString$
|
|
66035
|
+
const taskId = asString$4(payload?.id) ?? asString$4(msg?.turn_id);
|
|
65990
66036
|
if (!taskId) return [];
|
|
65991
66037
|
return [{
|
|
65992
66038
|
...codexEventBase(event, canonicalThreadId),
|
|
65993
66039
|
type: "task.started",
|
|
65994
66040
|
payload: {
|
|
65995
66041
|
taskId: asRuntimeTaskId(taskId),
|
|
65996
|
-
...asString$
|
|
66042
|
+
...asString$4(msg?.collaboration_mode_kind) ? { taskType: asString$4(msg?.collaboration_mode_kind) } : {}
|
|
65997
66043
|
}
|
|
65998
66044
|
}];
|
|
65999
66045
|
}
|
|
66000
66046
|
if (event.method === "codex/event/task_complete") {
|
|
66001
66047
|
const msg = codexEventMessage(payload);
|
|
66002
|
-
const taskId = asString$
|
|
66003
|
-
const proposedPlanMarkdown = extractProposedPlanMarkdown(asString$
|
|
66048
|
+
const taskId = asString$4(payload?.id) ?? asString$4(msg?.turn_id);
|
|
66049
|
+
const proposedPlanMarkdown = extractProposedPlanMarkdown(asString$4(msg?.last_agent_message));
|
|
66004
66050
|
if (!taskId) {
|
|
66005
66051
|
if (!proposedPlanMarkdown) return [];
|
|
66006
66052
|
return [{
|
|
@@ -66015,7 +66061,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
66015
66061
|
payload: {
|
|
66016
66062
|
taskId: asRuntimeTaskId(taskId),
|
|
66017
66063
|
status: "completed",
|
|
66018
|
-
...asString$
|
|
66064
|
+
...asString$4(msg?.last_agent_message) ? { summary: asString$4(msg?.last_agent_message) } : {}
|
|
66019
66065
|
}
|
|
66020
66066
|
}];
|
|
66021
66067
|
if (proposedPlanMarkdown) events.push({
|
|
@@ -66027,8 +66073,8 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
66027
66073
|
}
|
|
66028
66074
|
if (event.method === "codex/event/agent_reasoning") {
|
|
66029
66075
|
const msg = codexEventMessage(payload);
|
|
66030
|
-
const taskId = asString$
|
|
66031
|
-
const description = asString$
|
|
66076
|
+
const taskId = asString$4(payload?.id);
|
|
66077
|
+
const description = asString$4(msg?.text);
|
|
66032
66078
|
if (!taskId || !description) return [];
|
|
66033
66079
|
return [{
|
|
66034
66080
|
...codexEventBase(event, canonicalThreadId),
|
|
@@ -66041,7 +66087,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
66041
66087
|
}
|
|
66042
66088
|
if (event.method === "codex/event/reasoning_content_delta") {
|
|
66043
66089
|
const msg = codexEventMessage(payload);
|
|
66044
|
-
const delta = asString$
|
|
66090
|
+
const delta = asString$4(msg?.delta);
|
|
66045
66091
|
if (!delta) return [];
|
|
66046
66092
|
return [{
|
|
66047
66093
|
...codexEventBase(event, canonicalThreadId),
|
|
@@ -66057,26 +66103,26 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
66057
66103
|
type: "model.rerouted",
|
|
66058
66104
|
...runtimeEventBase(event, canonicalThreadId),
|
|
66059
66105
|
payload: {
|
|
66060
|
-
fromModel: asString$
|
|
66061
|
-
toModel: asString$
|
|
66062
|
-
reason: asString$
|
|
66106
|
+
fromModel: asString$4(payload?.fromModel) ?? "unknown",
|
|
66107
|
+
toModel: asString$4(payload?.toModel) ?? "unknown",
|
|
66108
|
+
reason: asString$4(payload?.reason) ?? "unknown"
|
|
66063
66109
|
}
|
|
66064
66110
|
}];
|
|
66065
66111
|
if (event.method === "deprecationNotice") return [{
|
|
66066
66112
|
type: "deprecation.notice",
|
|
66067
66113
|
...runtimeEventBase(event, canonicalThreadId),
|
|
66068
66114
|
payload: {
|
|
66069
|
-
summary: asString$
|
|
66070
|
-
...asString$
|
|
66115
|
+
summary: asString$4(payload?.summary) ?? "Deprecation notice",
|
|
66116
|
+
...asString$4(payload?.details) ? { details: asString$4(payload?.details) } : {}
|
|
66071
66117
|
}
|
|
66072
66118
|
}];
|
|
66073
66119
|
if (event.method === "configWarning") return [{
|
|
66074
66120
|
type: "config.warning",
|
|
66075
66121
|
...runtimeEventBase(event, canonicalThreadId),
|
|
66076
66122
|
payload: {
|
|
66077
|
-
summary: asString$
|
|
66078
|
-
...asString$
|
|
66079
|
-
...asString$
|
|
66123
|
+
summary: asString$4(payload?.summary) ?? "Configuration warning",
|
|
66124
|
+
...asString$4(payload?.details) ? { details: asString$4(payload?.details) } : {},
|
|
66125
|
+
...asString$4(payload?.path) ? { path: asString$4(payload?.path) } : {},
|
|
66080
66126
|
...payload?.range !== void 0 ? { range: payload.range } : {}
|
|
66081
66127
|
}
|
|
66082
66128
|
}];
|
|
@@ -66095,12 +66141,12 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
66095
66141
|
...runtimeEventBase(event, canonicalThreadId),
|
|
66096
66142
|
payload: {
|
|
66097
66143
|
success: payload?.success === true,
|
|
66098
|
-
...asString$
|
|
66099
|
-
...asString$
|
|
66144
|
+
...asString$4(payload?.name) ? { name: asString$4(payload?.name) } : {},
|
|
66145
|
+
...asString$4(payload?.error) ? { error: asString$4(payload?.error) } : {}
|
|
66100
66146
|
}
|
|
66101
66147
|
}];
|
|
66102
66148
|
if (event.method === "thread/realtime/started") {
|
|
66103
|
-
const realtimeSessionId = asString$
|
|
66149
|
+
const realtimeSessionId = asString$4(payload?.realtimeSessionId);
|
|
66104
66150
|
return [{
|
|
66105
66151
|
type: "thread.realtime.started",
|
|
66106
66152
|
...runtimeEventBase(event, canonicalThreadId),
|
|
@@ -66118,7 +66164,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
66118
66164
|
payload: { audio: event.payload ?? {} }
|
|
66119
66165
|
}];
|
|
66120
66166
|
if (event.method === "thread/realtime/error") {
|
|
66121
|
-
const message = asString$
|
|
66167
|
+
const message = asString$4(payload?.message) ?? event.message ?? "Realtime error";
|
|
66122
66168
|
return [{
|
|
66123
66169
|
type: "thread.realtime.error",
|
|
66124
66170
|
...runtimeEventBase(event, canonicalThreadId),
|
|
@@ -66131,7 +66177,7 @@ function mapToRuntimeEvents(event, canonicalThreadId) {
|
|
|
66131
66177
|
payload: { reason: event.message }
|
|
66132
66178
|
}];
|
|
66133
66179
|
if (event.method === "error") {
|
|
66134
|
-
const message = asString$
|
|
66180
|
+
const message = asString$4(asObject(payload?.error)?.message) ?? event.message ?? "Provider runtime error";
|
|
66135
66181
|
const willRetry = payload?.willRetry === true;
|
|
66136
66182
|
return [{
|
|
66137
66183
|
type: willRetry ? "runtime.warning" : "runtime.error",
|
|
@@ -66738,12 +66784,12 @@ function decodeProviderKind(providerName, operation) {
|
|
|
66738
66784
|
detail: `Unknown persisted provider '${providerName}'.`
|
|
66739
66785
|
}));
|
|
66740
66786
|
}
|
|
66741
|
-
function isRecord$
|
|
66787
|
+
function isRecord$5(value) {
|
|
66742
66788
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
66743
66789
|
}
|
|
66744
66790
|
function mergeRuntimePayload(existing, next) {
|
|
66745
66791
|
if (next === void 0) return existing ?? null;
|
|
66746
|
-
if (isRecord$
|
|
66792
|
+
if (isRecord$5(existing) && isRecord$5(next)) return {
|
|
66747
66793
|
...existing,
|
|
66748
66794
|
...next
|
|
66749
66795
|
};
|
|
@@ -72761,7 +72807,7 @@ const FALLBACK_FEATURE_KEYS = [
|
|
|
72761
72807
|
];
|
|
72762
72808
|
let metadataCache = null;
|
|
72763
72809
|
let metadataCacheAt = 0;
|
|
72764
|
-
function isRecord$
|
|
72810
|
+
function isRecord$4(value) {
|
|
72765
72811
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
72766
72812
|
}
|
|
72767
72813
|
function uniqueSorted(values) {
|
|
@@ -72832,14 +72878,14 @@ function parseFeatureCatalog(output) {
|
|
|
72832
72878
|
}
|
|
72833
72879
|
function parseSchemaKeys(schemaRaw) {
|
|
72834
72880
|
const parsed = JSON.parse(schemaRaw);
|
|
72835
|
-
if (!isRecord$
|
|
72881
|
+
if (!isRecord$4(parsed)) return {
|
|
72836
72882
|
topLevelKeys: FALLBACK_SCHEMA_TOP_LEVEL_KEYS,
|
|
72837
72883
|
featureKeys: FALLBACK_FEATURE_KEYS
|
|
72838
72884
|
};
|
|
72839
|
-
const properties = isRecord$
|
|
72885
|
+
const properties = isRecord$4(parsed.properties) ? parsed.properties : {};
|
|
72840
72886
|
const topLevelKeys = uniqueSorted(Object.keys(properties));
|
|
72841
|
-
const features = isRecord$
|
|
72842
|
-
const featureProperties = isRecord$
|
|
72887
|
+
const features = isRecord$4(properties.features) ? properties.features : {};
|
|
72888
|
+
const featureProperties = isRecord$4(features.properties) ? features.properties : {};
|
|
72843
72889
|
const featureKeys = uniqueSorted(Object.keys(featureProperties));
|
|
72844
72890
|
return {
|
|
72845
72891
|
topLevelKeys: topLevelKeys.length > 0 ? topLevelKeys : FALLBACK_SCHEMA_TOP_LEVEL_KEYS,
|
|
@@ -73585,8 +73631,116 @@ function resolveProfileIdentityKeyFromProfile(profile) {
|
|
|
73585
73631
|
//#endregion
|
|
73586
73632
|
//#region ../../packages/runtime-codex/src/codex/rpc.ts
|
|
73587
73633
|
const RPC_TIMEOUT_MS = 1e4;
|
|
73634
|
+
const ACTIVATION_TURN_TIMEOUT_MS = 9e4;
|
|
73635
|
+
const ACTIVATION_PROMPT = "Reply with exactly: ok.";
|
|
73636
|
+
const ACTIVATION_MODEL = "gpt-5.1-codex-mini";
|
|
73588
73637
|
const MAX_STDERR_CAPTURE_CHARS = 32768;
|
|
73589
73638
|
const REFRESH_TOKEN_REDEEMED_SNIPPET$1 = "refresh token was already used";
|
|
73639
|
+
function isRecord$3(value) {
|
|
73640
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
73641
|
+
}
|
|
73642
|
+
function asString$3(value) {
|
|
73643
|
+
return typeof value === "string" ? value : value != null ? String(value) : "";
|
|
73644
|
+
}
|
|
73645
|
+
function createRpcMessageReader(rl) {
|
|
73646
|
+
const queue = [];
|
|
73647
|
+
const waiters = [];
|
|
73648
|
+
let closedError = null;
|
|
73649
|
+
const rejectAll = (error) => {
|
|
73650
|
+
closedError = error;
|
|
73651
|
+
while (waiters.length > 0) {
|
|
73652
|
+
const waiter = waiters.shift();
|
|
73653
|
+
clearTimeout(waiter.timer);
|
|
73654
|
+
waiter.reject(error);
|
|
73655
|
+
}
|
|
73656
|
+
};
|
|
73657
|
+
const onLine = (line) => {
|
|
73658
|
+
let parsed;
|
|
73659
|
+
try {
|
|
73660
|
+
parsed = JSON.parse(line);
|
|
73661
|
+
} catch {
|
|
73662
|
+
rejectAll(/* @__PURE__ */ new Error("codex RPC returned malformed JSON"));
|
|
73663
|
+
return;
|
|
73664
|
+
}
|
|
73665
|
+
const waiterIndex = waiters.findIndex((waiter) => waiter.predicate(parsed));
|
|
73666
|
+
if (waiterIndex >= 0) {
|
|
73667
|
+
const [waiter] = waiters.splice(waiterIndex, 1);
|
|
73668
|
+
clearTimeout(waiter.timer);
|
|
73669
|
+
waiter.resolve(parsed);
|
|
73670
|
+
return;
|
|
73671
|
+
}
|
|
73672
|
+
queue.push(parsed);
|
|
73673
|
+
};
|
|
73674
|
+
const onClose = () => {
|
|
73675
|
+
rejectAll(/* @__PURE__ */ new Error("codex RPC stream closed before response"));
|
|
73676
|
+
};
|
|
73677
|
+
rl.on("line", onLine);
|
|
73678
|
+
rl.on("close", onClose);
|
|
73679
|
+
return {
|
|
73680
|
+
read(predicate, timeoutMs) {
|
|
73681
|
+
const queuedIndex = queue.findIndex(predicate);
|
|
73682
|
+
if (queuedIndex >= 0) {
|
|
73683
|
+
const [message] = queue.splice(queuedIndex, 1);
|
|
73684
|
+
return Promise.resolve(message);
|
|
73685
|
+
}
|
|
73686
|
+
if (closedError) return Promise.reject(closedError);
|
|
73687
|
+
return new Promise((resolve, reject) => {
|
|
73688
|
+
const waiter = {
|
|
73689
|
+
predicate,
|
|
73690
|
+
resolve,
|
|
73691
|
+
reject,
|
|
73692
|
+
timer: setTimeout(() => {
|
|
73693
|
+
const index = waiters.indexOf(waiter);
|
|
73694
|
+
if (index >= 0) waiters.splice(index, 1);
|
|
73695
|
+
reject(/* @__PURE__ */ new Error("codex RPC timed out"));
|
|
73696
|
+
}, Math.max(1, timeoutMs))
|
|
73697
|
+
};
|
|
73698
|
+
waiters.push(waiter);
|
|
73699
|
+
});
|
|
73700
|
+
},
|
|
73701
|
+
dispose() {
|
|
73702
|
+
rl.off("line", onLine);
|
|
73703
|
+
rl.off("close", onClose);
|
|
73704
|
+
while (waiters.length > 0) {
|
|
73705
|
+
const waiter = waiters.shift();
|
|
73706
|
+
clearTimeout(waiter.timer);
|
|
73707
|
+
}
|
|
73708
|
+
}
|
|
73709
|
+
};
|
|
73710
|
+
}
|
|
73711
|
+
function readThreadIdFromResult(result) {
|
|
73712
|
+
if (!isRecord$3(result)) return null;
|
|
73713
|
+
const value = asString$3((isRecord$3(result.thread) ? result.thread : {}).id ?? result.threadId).trim();
|
|
73714
|
+
return value.length > 0 ? value : null;
|
|
73715
|
+
}
|
|
73716
|
+
function readTurnIdFromResult(result) {
|
|
73717
|
+
if (!isRecord$3(result)) return null;
|
|
73718
|
+
const value = asString$3((isRecord$3(result.turn) ? result.turn : {}).id ?? result.turnId).trim();
|
|
73719
|
+
return value.length > 0 ? value : null;
|
|
73720
|
+
}
|
|
73721
|
+
function readTurnIdFromNotification(message) {
|
|
73722
|
+
if (!isRecord$3(message.params)) return null;
|
|
73723
|
+
const value = asString$3((isRecord$3(message.params.turn) ? message.params.turn : {}).id ?? message.params.turnId).trim();
|
|
73724
|
+
return value.length > 0 ? value : null;
|
|
73725
|
+
}
|
|
73726
|
+
function readTurnStatusFromNotification(message) {
|
|
73727
|
+
if (!isRecord$3(message.params)) return {
|
|
73728
|
+
status: null,
|
|
73729
|
+
reason: null
|
|
73730
|
+
};
|
|
73731
|
+
const turn = isRecord$3(message.params.turn) ? message.params.turn : {};
|
|
73732
|
+
const error = isRecord$3(turn.error) ? turn.error : null;
|
|
73733
|
+
return {
|
|
73734
|
+
status: asString$3(turn.status).trim() || null,
|
|
73735
|
+
reason: error ? asString$3(error.message).trim() || null : null
|
|
73736
|
+
};
|
|
73737
|
+
}
|
|
73738
|
+
function readLegacyEventTurnId(message) {
|
|
73739
|
+
if (!isRecord$3(message.params)) return null;
|
|
73740
|
+
const msg = isRecord$3(message.params.msg) ? message.params.msg : {};
|
|
73741
|
+
const value = asString$3(message.params.id ?? msg.turn_id ?? msg.turnId).trim();
|
|
73742
|
+
return value.length > 0 ? value : null;
|
|
73743
|
+
}
|
|
73590
73744
|
function parseTimestamp$1(value) {
|
|
73591
73745
|
if (typeof value !== "string" || value.trim().length === 0) return null;
|
|
73592
73746
|
const parsed = Date.parse(value);
|
|
@@ -73825,6 +73979,160 @@ async function fetchRateLimitsViaRpc(envOverride, options = {}) {
|
|
|
73825
73979
|
}).catch(() => {});
|
|
73826
73980
|
}
|
|
73827
73981
|
}
|
|
73982
|
+
async function activateResetWindowViaRpc(envOverride, options = {}) {
|
|
73983
|
+
const binaryPath = options.codexPath ?? await requireCodexCli();
|
|
73984
|
+
const tempHome = await promises.mkdtemp(nodePath.join(nodeOs.tmpdir(), "codex-activation-"));
|
|
73985
|
+
const tempAuthPath = nodePath.join(tempHome, "auth.json");
|
|
73986
|
+
let initialSourceAuth = null;
|
|
73987
|
+
const sourceAuthPath = options.authPath ?? (envOverride?.CODEX_HOME ? nodePath.join(envOverride.CODEX_HOME, "auth.json") : nodePath.join(envOverride?.HOME ?? process.env.HOME ?? process.env.USERPROFILE ?? nodeOs.homedir(), ".codex", "auth.json"));
|
|
73988
|
+
try {
|
|
73989
|
+
initialSourceAuth = await promises.readFile(sourceAuthPath, "utf8").catch(() => null);
|
|
73990
|
+
if (!initialSourceAuth) {
|
|
73991
|
+
await promises.rm(tempHome, {
|
|
73992
|
+
recursive: true,
|
|
73993
|
+
force: true
|
|
73994
|
+
}).catch(() => {});
|
|
73995
|
+
return {
|
|
73996
|
+
status: "skipped",
|
|
73997
|
+
reason: "auth-missing"
|
|
73998
|
+
};
|
|
73999
|
+
}
|
|
74000
|
+
await promises.writeFile(tempAuthPath, initialSourceAuth, "utf8");
|
|
74001
|
+
} catch {
|
|
74002
|
+
await promises.rm(tempHome, {
|
|
74003
|
+
recursive: true,
|
|
74004
|
+
force: true
|
|
74005
|
+
}).catch(() => {});
|
|
74006
|
+
return {
|
|
74007
|
+
status: "skipped",
|
|
74008
|
+
reason: "auth-missing"
|
|
74009
|
+
};
|
|
74010
|
+
}
|
|
74011
|
+
const childEnv = {
|
|
74012
|
+
...process.env,
|
|
74013
|
+
...envOverride ?? {},
|
|
74014
|
+
HOME: tempHome,
|
|
74015
|
+
USERPROFILE: tempHome,
|
|
74016
|
+
CODEX_HOME: tempHome,
|
|
74017
|
+
CODEX_TELEMETRY_LABEL: "codex-reset-activation",
|
|
74018
|
+
ELECTRON_RUN_AS_NODE: "1"
|
|
74019
|
+
};
|
|
74020
|
+
const command = buildCodexCommand$1(binaryPath, [
|
|
74021
|
+
"-s",
|
|
74022
|
+
"read-only",
|
|
74023
|
+
"-a",
|
|
74024
|
+
"untrusted",
|
|
74025
|
+
"app-server"
|
|
74026
|
+
], childEnv);
|
|
74027
|
+
const child = spawn(command.command, command.args, {
|
|
74028
|
+
stdio: [
|
|
74029
|
+
"pipe",
|
|
74030
|
+
"pipe",
|
|
74031
|
+
"pipe"
|
|
74032
|
+
],
|
|
74033
|
+
env: childEnv,
|
|
74034
|
+
shell: command.shell
|
|
74035
|
+
});
|
|
74036
|
+
const rl = readline.createInterface({
|
|
74037
|
+
input: child.stdout,
|
|
74038
|
+
crlfDelay: Infinity
|
|
74039
|
+
});
|
|
74040
|
+
const reader = createRpcMessageReader(rl);
|
|
74041
|
+
let stderrOutput = "";
|
|
74042
|
+
child.stderr?.on("data", (chunk) => {
|
|
74043
|
+
if (stderrOutput.length >= MAX_STDERR_CAPTURE_CHARS) return;
|
|
74044
|
+
const text = chunk.toString("utf8");
|
|
74045
|
+
const remaining = MAX_STDERR_CAPTURE_CHARS - stderrOutput.length;
|
|
74046
|
+
stderrOutput += text.slice(0, Math.max(0, remaining));
|
|
74047
|
+
});
|
|
74048
|
+
try {
|
|
74049
|
+
await sendPayload(child, {
|
|
74050
|
+
id: 1,
|
|
74051
|
+
method: "initialize",
|
|
74052
|
+
params: { clientInfo: {
|
|
74053
|
+
name: "codexuse",
|
|
74054
|
+
version: "0.0.0"
|
|
74055
|
+
} }
|
|
74056
|
+
});
|
|
74057
|
+
const initializeResponse = await reader.read((message) => isRpcResponseForRequest(message, 1), RPC_TIMEOUT_MS);
|
|
74058
|
+
if (initializeResponse.error) throw new Error(formatRpcError("initialize", initializeResponse.error));
|
|
74059
|
+
await sendPayload(child, {
|
|
74060
|
+
method: "initialized",
|
|
74061
|
+
params: {}
|
|
74062
|
+
});
|
|
74063
|
+
await sendPayload(child, {
|
|
74064
|
+
id: 2,
|
|
74065
|
+
method: "thread/start",
|
|
74066
|
+
params: {
|
|
74067
|
+
cwd: tempHome,
|
|
74068
|
+
model: ACTIVATION_MODEL,
|
|
74069
|
+
approvalPolicy: "untrusted",
|
|
74070
|
+
sandbox: "read-only",
|
|
74071
|
+
experimentalRawEvents: false
|
|
74072
|
+
}
|
|
74073
|
+
});
|
|
74074
|
+
const threadResponse = await reader.read((message) => isRpcResponseForRequest(message, 2), RPC_TIMEOUT_MS);
|
|
74075
|
+
if (threadResponse.error) throw new Error(formatRpcError("thread/start", threadResponse.error));
|
|
74076
|
+
const threadId = readThreadIdFromResult(threadResponse.result);
|
|
74077
|
+
if (!threadId) throw new Error("thread/start response did not include a thread id.");
|
|
74078
|
+
await sendPayload(child, {
|
|
74079
|
+
id: 3,
|
|
74080
|
+
method: "turn/start",
|
|
74081
|
+
params: {
|
|
74082
|
+
threadId,
|
|
74083
|
+
model: ACTIVATION_MODEL,
|
|
74084
|
+
effort: "low",
|
|
74085
|
+
input: [{
|
|
74086
|
+
type: "text",
|
|
74087
|
+
text: ACTIVATION_PROMPT,
|
|
74088
|
+
text_elements: []
|
|
74089
|
+
}]
|
|
74090
|
+
}
|
|
74091
|
+
});
|
|
74092
|
+
const turnResponse = await reader.read((message) => isRpcResponseForRequest(message, 3), RPC_TIMEOUT_MS);
|
|
74093
|
+
if (turnResponse.error) {
|
|
74094
|
+
const base = formatRpcError("turn/start", turnResponse.error);
|
|
74095
|
+
const hint = inferRefreshFailureHint(stderrOutput);
|
|
74096
|
+
if (hint && !base.toLowerCase().includes(hint)) throw new Error(`${base}; ${hint}`);
|
|
74097
|
+
throw new Error(base);
|
|
74098
|
+
}
|
|
74099
|
+
const turnId = readTurnIdFromResult(turnResponse.result);
|
|
74100
|
+
if (!turnId) throw new Error("turn/start response did not include a turn id.");
|
|
74101
|
+
const turnStatus = readTurnStatusFromNotification(await reader.read((message) => message.method === "turn/completed" && readTurnIdFromNotification(message) === turnId || message.method === "codex/event/task_complete" && readLegacyEventTurnId(message) === turnId, ACTIVATION_TURN_TIMEOUT_MS));
|
|
74102
|
+
if (turnStatus.status === "failed") return {
|
|
74103
|
+
status: "failed",
|
|
74104
|
+
reason: turnStatus.reason ?? "turn-failed",
|
|
74105
|
+
threadId,
|
|
74106
|
+
turnId
|
|
74107
|
+
};
|
|
74108
|
+
return {
|
|
74109
|
+
status: "completed",
|
|
74110
|
+
reason: null,
|
|
74111
|
+
threadId,
|
|
74112
|
+
turnId
|
|
74113
|
+
};
|
|
74114
|
+
} finally {
|
|
74115
|
+
child.kill();
|
|
74116
|
+
reader.dispose();
|
|
74117
|
+
rl.close();
|
|
74118
|
+
try {
|
|
74119
|
+
const updatedAuth = await promises.readFile(tempAuthPath, "utf8");
|
|
74120
|
+
if (updatedAuth.trim().length > 0) {
|
|
74121
|
+
const currentSourceAuth = await promises.readFile(sourceAuthPath, "utf8").catch(() => null);
|
|
74122
|
+
if (shouldWriteBackAuth(initialSourceAuth, currentSourceAuth, updatedAuth)) await promises.writeFile(sourceAuthPath, updatedAuth, "utf8");
|
|
74123
|
+
else if (currentSourceAuth && currentSourceAuth !== updatedAuth && currentSourceAuth !== initialSourceAuth) logWarn("Skipped stale auth sync-back after reset-window activation; source auth changed in flight.", {
|
|
74124
|
+
sourceAuthPath,
|
|
74125
|
+
currentRecencyMs: extractAuthRecencyMs(currentSourceAuth),
|
|
74126
|
+
updatedRecencyMs: extractAuthRecencyMs(updatedAuth)
|
|
74127
|
+
});
|
|
74128
|
+
}
|
|
74129
|
+
} catch {}
|
|
74130
|
+
await promises.rm(tempHome, {
|
|
74131
|
+
recursive: true,
|
|
74132
|
+
force: true
|
|
74133
|
+
}).catch(() => {});
|
|
74134
|
+
}
|
|
74135
|
+
}
|
|
73828
74136
|
//#endregion
|
|
73829
74137
|
//#region ../../packages/runtime-profiles/src/profiles/profile-manager.ts
|
|
73830
74138
|
const TOKEN_EXPIRING_SOON_WINDOW_MS = 900 * 1e3;
|
|
@@ -74725,11 +75033,11 @@ var ProfileManager = class {
|
|
|
74725
75033
|
const existingIdentity = this.resolveProfileIdentityFromData(profileName, existing, existingMetadata);
|
|
74726
75034
|
const nextIdentity = this.resolveProfileIdentityFromData(profileName, normalized, metadata);
|
|
74727
75035
|
if (existingIdentity && nextIdentity && existingIdentity !== nextIdentity) {
|
|
74728
|
-
|
|
75036
|
+
logInfo(`Skipped syncing tokens for profile '${profileName}' because Codex auth switched to a different OpenAI identity.`);
|
|
74729
75037
|
return;
|
|
74730
75038
|
}
|
|
74731
75039
|
if (this.normalizeWorkspaceId(existing.workspace_id) !== this.normalizeWorkspaceId(normalized.workspace_id)) {
|
|
74732
|
-
|
|
75040
|
+
logInfo(`Skipped syncing tokens for profile '${profileName}' because Codex auth switched to a different workspace.`);
|
|
74733
75041
|
return;
|
|
74734
75042
|
}
|
|
74735
75043
|
if (!this.hasTokenChanges(existing, normalized)) return;
|
|
@@ -75058,6 +75366,18 @@ var ProfileManager = class {
|
|
|
75058
75366
|
});
|
|
75059
75367
|
}
|
|
75060
75368
|
}
|
|
75369
|
+
async activateResetWindow(name, options = {}) {
|
|
75370
|
+
const profileName = this.normalizeProfileName(name);
|
|
75371
|
+
try {
|
|
75372
|
+
return await this.enqueueProfileOperation(profileName, () => this.runWithPreparedProfileHome(profileName, (env) => activateResetWindowViaRpc(env, { codexPath: options.codexPath }), { syncFromActiveAuthBeforeAction: false }));
|
|
75373
|
+
} finally {
|
|
75374
|
+
await this.enqueueAuthSwap(async () => {
|
|
75375
|
+
await this.syncActiveAuthFromProfileIfCurrent(profileName);
|
|
75376
|
+
}).catch((error) => {
|
|
75377
|
+
logWarn(`Failed to sync active auth after reset-window activation for '${profileName}':`, error);
|
|
75378
|
+
});
|
|
75379
|
+
}
|
|
75380
|
+
}
|
|
75061
75381
|
/**
|
|
75062
75382
|
* Rename a profile
|
|
75063
75383
|
*/
|
|
@@ -82274,15 +82594,13 @@ function createTelegramBridge(options) {
|
|
|
82274
82594
|
}
|
|
82275
82595
|
//#endregion
|
|
82276
82596
|
//#region ../../packages/runtime-codex/src/codex/officialAppRestart.ts
|
|
82277
|
-
const RESTART_COOLDOWN_MS = 6e4;
|
|
82278
82597
|
const COMMAND_TIMEOUT_MS = 3e3;
|
|
82279
82598
|
const EXIT_WAIT_MS = 1e4;
|
|
82280
82599
|
const LAUNCH_WAIT_MS = 15e3;
|
|
82281
82600
|
const POLL_INTERVAL_MS = 250;
|
|
82282
82601
|
const APP_DISCOVERY_CACHE_TTL_MS = 6e4;
|
|
82283
82602
|
const APP_DISCOVERY_MISS_CACHE_TTL_MS = 5e3;
|
|
82284
|
-
|
|
82285
|
-
let lastRestartStartedAt = 0;
|
|
82603
|
+
const OFFICIAL_CODEX_ACTIVITY_LIMIT = 50;
|
|
82286
82604
|
let profileActionLock = Promise.resolve();
|
|
82287
82605
|
let appDiscoveryCache = null;
|
|
82288
82606
|
function logOfficialCodexRestart(level, message, context) {
|
|
@@ -82293,6 +82611,47 @@ function logOfficialCodexRestart(level, message, context) {
|
|
|
82293
82611
|
}
|
|
82294
82612
|
logger(`[official-codex-restart] ${message}`);
|
|
82295
82613
|
}
|
|
82614
|
+
function hashProfileKey(profileKey) {
|
|
82615
|
+
if (!profileKey) return null;
|
|
82616
|
+
return createHash("sha256").update(profileKey).digest("hex").slice(0, 12);
|
|
82617
|
+
}
|
|
82618
|
+
async function recordOfficialCodexActivity(input) {
|
|
82619
|
+
const now = /* @__PURE__ */ new Date();
|
|
82620
|
+
const entry = {
|
|
82621
|
+
id: `${now.getTime().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
82622
|
+
at: now.toISOString(),
|
|
82623
|
+
kind: input.kind,
|
|
82624
|
+
status: input.status,
|
|
82625
|
+
reason: input.reason ?? null,
|
|
82626
|
+
decisionId: input.decisionId ?? null,
|
|
82627
|
+
profileName: input.profileName ?? null,
|
|
82628
|
+
sourceProfileName: input.sourceProfileName ?? null,
|
|
82629
|
+
targetProfileName: input.targetProfileName ?? null,
|
|
82630
|
+
remainingPercent: input.remainingPercent ?? null,
|
|
82631
|
+
threshold: input.threshold ?? null,
|
|
82632
|
+
snapshotAgeMs: input.snapshotAgeMs ?? null,
|
|
82633
|
+
snapshotSource: input.snapshotSource ?? null,
|
|
82634
|
+
phase: input.phase ?? null,
|
|
82635
|
+
pid: input.pid ?? null,
|
|
82636
|
+
profileKeyHash: input.profileKeyHash ?? hashProfileKey(input.profileKey),
|
|
82637
|
+
switchVerified: input.switchVerified ?? null,
|
|
82638
|
+
restartRequested: input.restartRequested ?? null,
|
|
82639
|
+
restartResult: input.restartResult ?? null,
|
|
82640
|
+
observedProfileName: input.observedProfileName ?? null,
|
|
82641
|
+
observedProfileKeyHash: input.observedProfileKeyHash ?? hashProfileKey(input.observedProfileKey),
|
|
82642
|
+
observedProfileMatchSource: input.observedProfileMatchSource ?? null
|
|
82643
|
+
};
|
|
82644
|
+
try {
|
|
82645
|
+
await updateAppState((state) => ({ officialCodex: { activity: [...state.officialCodex.activity, entry].slice(-OFFICIAL_CODEX_ACTIVITY_LIMIT) } }));
|
|
82646
|
+
} catch (error) {
|
|
82647
|
+
logOfficialCodexRestart("warn", "Failed to record official Codex activity.", {
|
|
82648
|
+
kind: entry.kind,
|
|
82649
|
+
status: entry.status,
|
|
82650
|
+
profileKeyHash: entry.profileKeyHash,
|
|
82651
|
+
error: error instanceof Error ? error.message : String(error)
|
|
82652
|
+
});
|
|
82653
|
+
}
|
|
82654
|
+
}
|
|
82296
82655
|
function runCommand(command, args, timeoutMs = COMMAND_TIMEOUT_MS) {
|
|
82297
82656
|
return new Promise((resolve) => {
|
|
82298
82657
|
const child = spawn(command, args, { stdio: [
|
|
@@ -82670,14 +83029,6 @@ async function resolveCodexAppTarget() {
|
|
|
82670
83029
|
mainPids
|
|
82671
83030
|
};
|
|
82672
83031
|
}
|
|
82673
|
-
async function waitForCodexExit(candidate, timeoutMs) {
|
|
82674
|
-
const deadline = Date.now() + timeoutMs;
|
|
82675
|
-
while (Date.now() < deadline) {
|
|
82676
|
-
if ((await getRunningCodexPids(candidate)).length === 0) return true;
|
|
82677
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
82678
|
-
}
|
|
82679
|
-
return false;
|
|
82680
|
-
}
|
|
82681
83032
|
async function signalPids(pids, signal) {
|
|
82682
83033
|
const signaled = [];
|
|
82683
83034
|
for (const pid of pids) try {
|
|
@@ -82686,19 +83037,6 @@ async function signalPids(pids, signal) {
|
|
|
82686
83037
|
} catch {}
|
|
82687
83038
|
return signaled;
|
|
82688
83039
|
}
|
|
82689
|
-
async function openCodex(candidate) {
|
|
82690
|
-
if ((await runCommand("/usr/bin/open", ["-b", candidate.bundleId])).code === 0) return true;
|
|
82691
|
-
return (await runCommand("/usr/bin/open", [candidate.appPath])).code === 0;
|
|
82692
|
-
}
|
|
82693
|
-
async function waitForCodexLaunch(candidate) {
|
|
82694
|
-
const deadline = Date.now() + LAUNCH_WAIT_MS;
|
|
82695
|
-
while (Date.now() < deadline) {
|
|
82696
|
-
const pid = (await getRunningCodexMainPids(candidate))[0] ?? null;
|
|
82697
|
-
if (pid !== null) return pid;
|
|
82698
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
82699
|
-
}
|
|
82700
|
-
return null;
|
|
82701
|
-
}
|
|
82702
83040
|
function toIso(value) {
|
|
82703
83041
|
return typeof value === "number" && Number.isFinite(value) ? new Date(value).toISOString() : null;
|
|
82704
83042
|
}
|
|
@@ -82719,152 +83057,15 @@ async function rememberRestartResult(args) {
|
|
|
82719
83057
|
lastRestartReason: args.reason ?? null
|
|
82720
83058
|
} });
|
|
82721
83059
|
}
|
|
82722
|
-
async function
|
|
82723
|
-
if (
|
|
82724
|
-
|
|
82725
|
-
|
|
82726
|
-
|
|
82727
|
-
|
|
82728
|
-
|
|
82729
|
-
|
|
82730
|
-
|
|
82731
|
-
};
|
|
82732
|
-
}
|
|
82733
|
-
const now = Date.now();
|
|
82734
|
-
if (options.source !== "manual" && lastRestartStartedAt > 0 && now - lastRestartStartedAt < RESTART_COOLDOWN_MS) {
|
|
82735
|
-
await rememberRestartResult({
|
|
82736
|
-
status: "skipped",
|
|
82737
|
-
reason: "cooldown",
|
|
82738
|
-
profileKey: options.currentProfileKey
|
|
82739
|
-
});
|
|
82740
|
-
return {
|
|
82741
|
-
status: "skipped",
|
|
82742
|
-
reason: "cooldown"
|
|
82743
|
-
};
|
|
82744
|
-
}
|
|
82745
|
-
const { candidate, runningPids, mainPids } = await resolveCodexAppTarget();
|
|
82746
|
-
if (!candidate) {
|
|
82747
|
-
await rememberRestartResult({
|
|
82748
|
-
status: "skipped",
|
|
82749
|
-
reason: "official-codex-app-not-found",
|
|
82750
|
-
profileKey: options.currentProfileKey
|
|
82751
|
-
});
|
|
82752
|
-
return {
|
|
82753
|
-
status: "skipped",
|
|
82754
|
-
reason: "official-codex-app-not-found"
|
|
82755
|
-
};
|
|
82756
|
-
}
|
|
82757
|
-
const appIsRunning = mainPids.length > 0;
|
|
82758
|
-
if (!appIsRunning && !options.launchIfNotRunning) {
|
|
82759
|
-
await rememberRestartResult({
|
|
82760
|
-
status: "skipped",
|
|
82761
|
-
reason: "official-codex-app-not-running",
|
|
82762
|
-
profileKey: options.currentProfileKey
|
|
82763
|
-
});
|
|
82764
|
-
return {
|
|
82765
|
-
status: "skipped",
|
|
82766
|
-
reason: "official-codex-app-not-running"
|
|
82767
|
-
};
|
|
82768
|
-
}
|
|
82769
|
-
if (options.source !== "manual") lastRestartStartedAt = Date.now();
|
|
82770
|
-
if (appIsRunning) {
|
|
82771
|
-
logOfficialCodexRestart("warn", "Force killing official Codex before relaunch.", {
|
|
82772
|
-
appPath: candidate.appPath,
|
|
82773
|
-
bundleId: candidate.bundleId,
|
|
82774
|
-
source: options.source,
|
|
82775
|
-
runningPids,
|
|
82776
|
-
mainPids
|
|
82777
|
-
});
|
|
82778
|
-
const killedPids = await signalPids(runningPids, "SIGKILL");
|
|
82779
|
-
logOfficialCodexRestart("warn", "Sent SIGKILL to official Codex pids.", {
|
|
82780
|
-
appPath: candidate.appPath,
|
|
82781
|
-
bundleId: candidate.bundleId,
|
|
82782
|
-
source: options.source,
|
|
82783
|
-
killedPids
|
|
82784
|
-
});
|
|
82785
|
-
if (!await waitForCodexExit(candidate, EXIT_WAIT_MS)) {
|
|
82786
|
-
const remainingPids = await getRunningCodexPids(candidate);
|
|
82787
|
-
logOfficialCodexRestart("error", "Official Codex pids remained after force kill.", {
|
|
82788
|
-
appPath: candidate.appPath,
|
|
82789
|
-
bundleId: candidate.bundleId,
|
|
82790
|
-
source: options.source,
|
|
82791
|
-
remainingPids
|
|
82792
|
-
});
|
|
82793
|
-
const failed = {
|
|
82794
|
-
status: "failed",
|
|
82795
|
-
appPath: candidate.appPath,
|
|
82796
|
-
bundleId: candidate.bundleId,
|
|
82797
|
-
reason: "force-quit-timeout",
|
|
82798
|
-
phase: "quit"
|
|
82799
|
-
};
|
|
82800
|
-
await rememberRestartResult({
|
|
82801
|
-
status: failed.status,
|
|
82802
|
-
reason: failed.reason,
|
|
82803
|
-
profileKey: options.currentProfileKey
|
|
82804
|
-
});
|
|
82805
|
-
return failed;
|
|
82806
|
-
}
|
|
82807
|
-
logOfficialCodexRestart("info", "Official Codex exited after force kill.", {
|
|
82808
|
-
appPath: candidate.appPath,
|
|
82809
|
-
bundleId: candidate.bundleId,
|
|
82810
|
-
source: options.source
|
|
82811
|
-
});
|
|
82812
|
-
}
|
|
82813
|
-
if (!await openCodex(candidate)) {
|
|
82814
|
-
const failed = {
|
|
82815
|
-
status: "failed",
|
|
82816
|
-
appPath: candidate.appPath,
|
|
82817
|
-
bundleId: candidate.bundleId,
|
|
82818
|
-
reason: "open-failed",
|
|
82819
|
-
phase: "launch"
|
|
82820
|
-
};
|
|
82821
|
-
await rememberRestartResult({
|
|
82822
|
-
status: failed.status,
|
|
82823
|
-
reason: failed.reason,
|
|
82824
|
-
profileKey: options.currentProfileKey
|
|
82825
|
-
});
|
|
82826
|
-
return failed;
|
|
82827
|
-
}
|
|
82828
|
-
const launchedPid = await waitForCodexLaunch(candidate);
|
|
82829
|
-
if (launchedPid === null) {
|
|
82830
|
-
logOfficialCodexRestart("error", "Official Codex launch was not verified.", {
|
|
82831
|
-
appPath: candidate.appPath,
|
|
82832
|
-
bundleId: candidate.bundleId,
|
|
82833
|
-
source: options.source
|
|
82834
|
-
});
|
|
82835
|
-
const failed = {
|
|
82836
|
-
status: "failed",
|
|
82837
|
-
appPath: candidate.appPath,
|
|
82838
|
-
bundleId: candidate.bundleId,
|
|
82839
|
-
reason: "launch-timeout",
|
|
82840
|
-
phase: "launch"
|
|
82841
|
-
};
|
|
82842
|
-
await rememberRestartResult({
|
|
82843
|
-
status: failed.status,
|
|
82844
|
-
reason: failed.reason,
|
|
82845
|
-
profileKey: options.currentProfileKey
|
|
82846
|
-
});
|
|
82847
|
-
return failed;
|
|
82848
|
-
}
|
|
82849
|
-
const status = appIsRunning ? "restarted" : "started";
|
|
82850
|
-
logOfficialCodexRestart("info", "Official Codex launch verified.", {
|
|
82851
|
-
appPath: candidate.appPath,
|
|
82852
|
-
bundleId: candidate.bundleId,
|
|
82853
|
-
source: options.source,
|
|
82854
|
-
status,
|
|
82855
|
-
pid: launchedPid
|
|
82856
|
-
});
|
|
82857
|
-
await rememberRestartResult({
|
|
82858
|
-
status,
|
|
82859
|
-
profileKey: options.currentProfileKey,
|
|
82860
|
-
pid: launchedPid
|
|
82861
|
-
});
|
|
82862
|
-
return {
|
|
82863
|
-
status,
|
|
82864
|
-
appPath: candidate.appPath,
|
|
82865
|
-
bundleId: candidate.bundleId,
|
|
82866
|
-
pid: launchedPid
|
|
82867
|
-
};
|
|
83060
|
+
async function recordOfficialCodexProfileObservation(profileKey, pid) {
|
|
83061
|
+
if (!profileKey || !pid) return;
|
|
83062
|
+
await patchAppState({ officialCodex: {
|
|
83063
|
+
lastVerifiedLaunchProfileKey: profileKey,
|
|
83064
|
+
lastObservedPid: pid
|
|
83065
|
+
} });
|
|
83066
|
+
}
|
|
83067
|
+
function recordOfficialCodexRestartResult(args) {
|
|
83068
|
+
return rememberRestartResult(args);
|
|
82868
83069
|
}
|
|
82869
83070
|
async function getOfficialCodexSyncStatus(currentProfileKey) {
|
|
82870
83071
|
const stored = (await getAppState()).officialCodex;
|
|
@@ -82873,7 +83074,8 @@ async function getOfficialCodexSyncStatus(currentProfileKey) {
|
|
|
82873
83074
|
lastProfileSwitchAt: toIso(stored.lastProfileSwitchAt),
|
|
82874
83075
|
lastVerifiedLaunchAt: toIso(stored.lastVerifiedLaunchAt),
|
|
82875
83076
|
lastRestartStatus: stored.lastRestartStatus,
|
|
82876
|
-
lastRestartReason: stored.lastRestartReason
|
|
83077
|
+
lastRestartReason: stored.lastRestartReason,
|
|
83078
|
+
activity: stored.activity
|
|
82877
83079
|
};
|
|
82878
83080
|
if (process.platform !== "darwin") return {
|
|
82879
83081
|
...base,
|
|
@@ -82894,10 +83096,12 @@ async function getOfficialCodexSyncStatus(currentProfileKey) {
|
|
|
82894
83096
|
const lastSwitchAt = stored.lastProfileSwitchAt;
|
|
82895
83097
|
const lastLaunchAt = stored.lastVerifiedLaunchAt;
|
|
82896
83098
|
const lastLaunchProfileKey = stored.lastVerifiedLaunchProfileKey;
|
|
82897
|
-
const
|
|
83099
|
+
const lastObservedPid = stored.lastObservedPid;
|
|
83100
|
+
const observedSynced = Boolean(currentProfileKey && lastLaunchProfileKey === currentProfileKey && lastObservedPid && mainPids.includes(lastObservedPid));
|
|
83101
|
+
const stale = Boolean(!observedSynced && currentProfileKey && lastSwitchAt && (!lastLaunchAt || lastLaunchAt < lastSwitchAt || lastLaunchProfileKey !== currentProfileKey));
|
|
82898
83102
|
return {
|
|
82899
83103
|
...base,
|
|
82900
|
-
state:
|
|
83104
|
+
state: observedSynced ? "synced" : stale ? "stale" : "unknown",
|
|
82901
83105
|
appPath: candidate.appPath,
|
|
82902
83106
|
bundleId: candidate.bundleId,
|
|
82903
83107
|
runningPids: mainPids
|
|
@@ -82958,210 +83162,212 @@ async function getOfficialCodexProfileInstances() {
|
|
|
82958
83162
|
};
|
|
82959
83163
|
}
|
|
82960
83164
|
function launchOfficialCodexProfileInstance(options) {
|
|
82961
|
-
return enqueueProfileAction(
|
|
82962
|
-
|
|
82963
|
-
|
|
82964
|
-
|
|
82965
|
-
|
|
82966
|
-
|
|
82967
|
-
|
|
82968
|
-
|
|
82969
|
-
|
|
82970
|
-
|
|
82971
|
-
|
|
82972
|
-
|
|
82973
|
-
|
|
82974
|
-
|
|
82975
|
-
|
|
82976
|
-
|
|
82977
|
-
|
|
82978
|
-
|
|
82979
|
-
|
|
82980
|
-
|
|
82981
|
-
|
|
82982
|
-
|
|
82983
|
-
|
|
82984
|
-
|
|
82985
|
-
|
|
82986
|
-
|
|
82987
|
-
|
|
82988
|
-
|
|
82989
|
-
lastError: null
|
|
82990
|
-
};
|
|
82991
|
-
await patchManagedInstance(verified);
|
|
82992
|
-
return {
|
|
82993
|
-
status: "already-running",
|
|
82994
|
-
profileName: options.profileName,
|
|
82995
|
-
instance: managedInstanceToPayload(verified, true, runtime.appServerPid, runtime.startedAt),
|
|
82996
|
-
reason: null
|
|
82997
|
-
};
|
|
82998
|
-
}
|
|
82999
|
-
}
|
|
83000
|
-
const launch = await openCodexWithProfileHome(candidate, options.profileHome, options.profileName, new Set(mainPids));
|
|
83001
|
-
if (!launch.opened) {
|
|
83002
|
-
const failed = {
|
|
83003
|
-
profileName: options.profileName,
|
|
83004
|
-
profileKey: options.profileKey,
|
|
83005
|
-
profileHome: options.profileHome,
|
|
83006
|
-
appPath: candidate.appPath,
|
|
83007
|
-
bundleId: candidate.bundleId,
|
|
83008
|
-
pid: null,
|
|
83009
|
-
appServerPid: null,
|
|
83010
|
-
launchedAt: null,
|
|
83011
|
-
lastVerifiedAt: null,
|
|
83012
|
-
lastStatus: "failed",
|
|
83013
|
-
lastError: "open-failed"
|
|
83014
|
-
};
|
|
83015
|
-
await patchManagedInstance(failed);
|
|
83016
|
-
return {
|
|
83017
|
-
status: "failed",
|
|
83018
|
-
profileName: options.profileName,
|
|
83019
|
-
instance: managedInstanceToPayload(failed, false),
|
|
83020
|
-
reason: "open-failed"
|
|
83021
|
-
};
|
|
83022
|
-
}
|
|
83023
|
-
const launchedPid = launch.pid;
|
|
83024
|
-
if (launchedPid === null) {
|
|
83025
|
-
const failed = {
|
|
83026
|
-
profileName: options.profileName,
|
|
83027
|
-
profileKey: options.profileKey,
|
|
83028
|
-
profileHome: options.profileHome,
|
|
83029
|
-
appPath: candidate.appPath,
|
|
83030
|
-
bundleId: candidate.bundleId,
|
|
83031
|
-
pid: null,
|
|
83032
|
-
appServerPid: null,
|
|
83033
|
-
launchedAt: null,
|
|
83034
|
-
lastVerifiedAt: null,
|
|
83035
|
-
lastStatus: "failed",
|
|
83036
|
-
lastError: "launch-timeout"
|
|
83037
|
-
};
|
|
83038
|
-
await patchManagedInstance(failed);
|
|
83039
|
-
return {
|
|
83040
|
-
status: "failed",
|
|
83041
|
-
profileName: options.profileName,
|
|
83042
|
-
instance: managedInstanceToPayload(failed, false),
|
|
83043
|
-
reason: "launch-timeout"
|
|
83044
|
-
};
|
|
83045
|
-
}
|
|
83046
|
-
const appServerPid = await waitForAppServerPid(launchedPid, options.profileHome);
|
|
83047
|
-
if (appServerPid === null) {
|
|
83048
|
-
const failed = {
|
|
83049
|
-
profileName: options.profileName,
|
|
83050
|
-
profileKey: options.profileKey,
|
|
83051
|
-
profileHome: options.profileHome,
|
|
83052
|
-
appPath: candidate.appPath,
|
|
83053
|
-
bundleId: candidate.bundleId,
|
|
83054
|
-
pid: null,
|
|
83055
|
-
appServerPid: null,
|
|
83056
|
-
launchedAt: null,
|
|
83165
|
+
return enqueueProfileAction(() => launchOfficialCodexProfileInstanceOnce(options));
|
|
83166
|
+
}
|
|
83167
|
+
async function launchOfficialCodexProfileInstanceOnce(options) {
|
|
83168
|
+
if (process.platform !== "darwin") return {
|
|
83169
|
+
status: "skipped",
|
|
83170
|
+
profileName: options.profileName,
|
|
83171
|
+
instance: null,
|
|
83172
|
+
reason: "unsupported-platform"
|
|
83173
|
+
};
|
|
83174
|
+
const { candidate, mainPids } = await resolveCodexAppTarget();
|
|
83175
|
+
if (!candidate) return {
|
|
83176
|
+
status: "skipped",
|
|
83177
|
+
profileName: options.profileName,
|
|
83178
|
+
instance: null,
|
|
83179
|
+
reason: "official-codex-app-not-found"
|
|
83180
|
+
};
|
|
83181
|
+
const existing = await readManagedInstance(options.profileName);
|
|
83182
|
+
if (existing) {
|
|
83183
|
+
const runtime = await resolveInstanceRuntimeState({
|
|
83184
|
+
instance: existing,
|
|
83185
|
+
candidate,
|
|
83186
|
+
rows: await readProcessRows()
|
|
83187
|
+
});
|
|
83188
|
+
if (runtime.running) {
|
|
83189
|
+
const verified = {
|
|
83190
|
+
...existing,
|
|
83191
|
+
profileHome: existing.profileHome ?? options.profileHome,
|
|
83192
|
+
appServerPid: runtime.appServerPid,
|
|
83057
83193
|
lastVerifiedAt: Date.now(),
|
|
83058
|
-
lastStatus: "
|
|
83059
|
-
lastError:
|
|
83194
|
+
lastStatus: "already-running",
|
|
83195
|
+
lastError: null
|
|
83060
83196
|
};
|
|
83061
|
-
await patchManagedInstance(
|
|
83197
|
+
await patchManagedInstance(verified);
|
|
83062
83198
|
return {
|
|
83063
|
-
status: "
|
|
83199
|
+
status: "already-running",
|
|
83064
83200
|
profileName: options.profileName,
|
|
83065
|
-
instance: managedInstanceToPayload(
|
|
83066
|
-
reason:
|
|
83201
|
+
instance: managedInstanceToPayload(verified, true, runtime.appServerPid, runtime.startedAt),
|
|
83202
|
+
reason: null
|
|
83067
83203
|
};
|
|
83068
83204
|
}
|
|
83069
|
-
|
|
83070
|
-
|
|
83205
|
+
}
|
|
83206
|
+
const launch = await openCodexWithProfileHome(candidate, options.profileHome, options.profileName, new Set(mainPids));
|
|
83207
|
+
if (!launch.opened) {
|
|
83208
|
+
const failed = {
|
|
83071
83209
|
profileName: options.profileName,
|
|
83072
83210
|
profileKey: options.profileKey,
|
|
83073
83211
|
profileHome: options.profileHome,
|
|
83074
83212
|
appPath: candidate.appPath,
|
|
83075
83213
|
bundleId: candidate.bundleId,
|
|
83076
|
-
pid:
|
|
83077
|
-
appServerPid,
|
|
83078
|
-
launchedAt:
|
|
83079
|
-
lastVerifiedAt:
|
|
83080
|
-
lastStatus: "
|
|
83081
|
-
lastError:
|
|
83214
|
+
pid: null,
|
|
83215
|
+
appServerPid: null,
|
|
83216
|
+
launchedAt: null,
|
|
83217
|
+
lastVerifiedAt: null,
|
|
83218
|
+
lastStatus: "failed",
|
|
83219
|
+
lastError: "open-failed"
|
|
83082
83220
|
};
|
|
83083
|
-
await patchManagedInstance(
|
|
83221
|
+
await patchManagedInstance(failed);
|
|
83084
83222
|
return {
|
|
83085
|
-
status: "
|
|
83223
|
+
status: "failed",
|
|
83086
83224
|
profileName: options.profileName,
|
|
83087
|
-
instance: managedInstanceToPayload(
|
|
83088
|
-
reason:
|
|
83225
|
+
instance: managedInstanceToPayload(failed, false),
|
|
83226
|
+
reason: "open-failed"
|
|
83089
83227
|
};
|
|
83090
|
-
}
|
|
83228
|
+
}
|
|
83229
|
+
const launchedPid = launch.pid;
|
|
83230
|
+
if (launchedPid === null) {
|
|
83231
|
+
const failed = {
|
|
83232
|
+
profileName: options.profileName,
|
|
83233
|
+
profileKey: options.profileKey,
|
|
83234
|
+
profileHome: options.profileHome,
|
|
83235
|
+
appPath: candidate.appPath,
|
|
83236
|
+
bundleId: candidate.bundleId,
|
|
83237
|
+
pid: null,
|
|
83238
|
+
appServerPid: null,
|
|
83239
|
+
launchedAt: null,
|
|
83240
|
+
lastVerifiedAt: null,
|
|
83241
|
+
lastStatus: "failed",
|
|
83242
|
+
lastError: "launch-timeout"
|
|
83243
|
+
};
|
|
83244
|
+
await patchManagedInstance(failed);
|
|
83245
|
+
return {
|
|
83246
|
+
status: "failed",
|
|
83247
|
+
profileName: options.profileName,
|
|
83248
|
+
instance: managedInstanceToPayload(failed, false),
|
|
83249
|
+
reason: "launch-timeout"
|
|
83250
|
+
};
|
|
83251
|
+
}
|
|
83252
|
+
const appServerPid = await waitForAppServerPid(launchedPid, options.profileHome);
|
|
83253
|
+
if (appServerPid === null) {
|
|
83254
|
+
const failed = {
|
|
83255
|
+
profileName: options.profileName,
|
|
83256
|
+
profileKey: options.profileKey,
|
|
83257
|
+
profileHome: options.profileHome,
|
|
83258
|
+
appPath: candidate.appPath,
|
|
83259
|
+
bundleId: candidate.bundleId,
|
|
83260
|
+
pid: null,
|
|
83261
|
+
appServerPid: null,
|
|
83262
|
+
launchedAt: null,
|
|
83263
|
+
lastVerifiedAt: Date.now(),
|
|
83264
|
+
lastStatus: "failed",
|
|
83265
|
+
lastError: "app-server-not-verified"
|
|
83266
|
+
};
|
|
83267
|
+
await patchManagedInstance(failed);
|
|
83268
|
+
return {
|
|
83269
|
+
status: "failed",
|
|
83270
|
+
profileName: options.profileName,
|
|
83271
|
+
instance: managedInstanceToPayload(failed, false),
|
|
83272
|
+
reason: "app-server-not-verified"
|
|
83273
|
+
};
|
|
83274
|
+
}
|
|
83275
|
+
const now = Date.now();
|
|
83276
|
+
const instance = {
|
|
83277
|
+
profileName: options.profileName,
|
|
83278
|
+
profileKey: options.profileKey,
|
|
83279
|
+
profileHome: options.profileHome,
|
|
83280
|
+
appPath: candidate.appPath,
|
|
83281
|
+
bundleId: candidate.bundleId,
|
|
83282
|
+
pid: launchedPid,
|
|
83283
|
+
appServerPid,
|
|
83284
|
+
launchedAt: now,
|
|
83285
|
+
lastVerifiedAt: now,
|
|
83286
|
+
lastStatus: "started",
|
|
83287
|
+
lastError: null
|
|
83288
|
+
};
|
|
83289
|
+
await patchManagedInstance(instance);
|
|
83290
|
+
return {
|
|
83291
|
+
status: "started",
|
|
83292
|
+
profileName: options.profileName,
|
|
83293
|
+
instance: managedInstanceToPayload(instance, true, appServerPid),
|
|
83294
|
+
reason: null
|
|
83295
|
+
};
|
|
83091
83296
|
}
|
|
83092
83297
|
function stopOfficialCodexProfileInstance(profileName) {
|
|
83093
|
-
return enqueueProfileAction(
|
|
83094
|
-
|
|
83095
|
-
|
|
83298
|
+
return enqueueProfileAction(() => stopOfficialCodexProfileInstanceOnce(profileName));
|
|
83299
|
+
}
|
|
83300
|
+
async function stopOfficialCodexProfileInstanceOnce(profileName) {
|
|
83301
|
+
const existing = await readManagedInstance(profileName);
|
|
83302
|
+
if (!existing) return {
|
|
83303
|
+
status: "not-running",
|
|
83304
|
+
profileName,
|
|
83305
|
+
instance: null,
|
|
83306
|
+
reason: "not-managed"
|
|
83307
|
+
};
|
|
83308
|
+
const { candidate } = await resolveCodexAppTarget();
|
|
83309
|
+
if (!candidate) {
|
|
83310
|
+
const stopped = {
|
|
83311
|
+
...existing,
|
|
83312
|
+
pid: null,
|
|
83313
|
+
appServerPid: null,
|
|
83314
|
+
lastVerifiedAt: Date.now(),
|
|
83315
|
+
lastStatus: "not-running",
|
|
83316
|
+
lastError: "official-codex-app-not-found"
|
|
83317
|
+
};
|
|
83318
|
+
await patchManagedInstance(stopped);
|
|
83319
|
+
return {
|
|
83096
83320
|
status: "not-running",
|
|
83097
83321
|
profileName,
|
|
83098
|
-
instance:
|
|
83099
|
-
reason: "not-
|
|
83322
|
+
instance: managedInstanceToPayload(stopped, false),
|
|
83323
|
+
reason: "official-codex-app-not-found"
|
|
83100
83324
|
};
|
|
83101
|
-
|
|
83102
|
-
|
|
83103
|
-
|
|
83104
|
-
|
|
83105
|
-
|
|
83106
|
-
|
|
83107
|
-
|
|
83108
|
-
|
|
83109
|
-
lastError: "official-codex-app-not-found"
|
|
83110
|
-
};
|
|
83111
|
-
await patchManagedInstance(stopped);
|
|
83112
|
-
return {
|
|
83113
|
-
status: "not-running",
|
|
83114
|
-
profileName,
|
|
83115
|
-
instance: managedInstanceToPayload(stopped, false),
|
|
83116
|
-
reason: "official-codex-app-not-found"
|
|
83117
|
-
};
|
|
83118
|
-
}
|
|
83119
|
-
const rows = await readProcessRows();
|
|
83120
|
-
const runtime = await resolveInstanceRuntimeState({
|
|
83121
|
-
instance: existing,
|
|
83122
|
-
candidate,
|
|
83123
|
-
rows
|
|
83124
|
-
});
|
|
83125
|
-
if (!runtime.running || !existing.pid) {
|
|
83126
|
-
const stopped = {
|
|
83127
|
-
...existing,
|
|
83128
|
-
pid: null,
|
|
83129
|
-
appServerPid: null,
|
|
83130
|
-
lastVerifiedAt: Date.now(),
|
|
83131
|
-
lastStatus: "not-running",
|
|
83132
|
-
lastError: null
|
|
83133
|
-
};
|
|
83134
|
-
await patchManagedInstance(stopped);
|
|
83135
|
-
return {
|
|
83136
|
-
status: "not-running",
|
|
83137
|
-
profileName,
|
|
83138
|
-
instance: managedInstanceToPayload(stopped, false),
|
|
83139
|
-
reason: null
|
|
83140
|
-
};
|
|
83141
|
-
}
|
|
83142
|
-
const tree = [existing.pid, ...getDescendantPids(existing.pid, rows)].filter((pid, index, all) => all.indexOf(pid) === index).sort((a, b) => b - a);
|
|
83143
|
-
await signalPids(tree, "SIGTERM");
|
|
83144
|
-
if (!await waitForMainPidExit(existing.pid, 5e3)) {
|
|
83145
|
-
await signalPids(tree, "SIGKILL");
|
|
83146
|
-
await waitForMainPidExit(existing.pid, EXIT_WAIT_MS);
|
|
83147
|
-
}
|
|
83148
|
-
const stillRunning = (await readProcessRows()).some((row) => row.pid === existing.pid);
|
|
83325
|
+
}
|
|
83326
|
+
const rows = await readProcessRows();
|
|
83327
|
+
const runtime = await resolveInstanceRuntimeState({
|
|
83328
|
+
instance: existing,
|
|
83329
|
+
candidate,
|
|
83330
|
+
rows
|
|
83331
|
+
});
|
|
83332
|
+
if (!runtime.running || !existing.pid) {
|
|
83149
83333
|
const stopped = {
|
|
83150
83334
|
...existing,
|
|
83151
|
-
pid:
|
|
83152
|
-
appServerPid:
|
|
83335
|
+
pid: null,
|
|
83336
|
+
appServerPid: null,
|
|
83153
83337
|
lastVerifiedAt: Date.now(),
|
|
83154
|
-
lastStatus:
|
|
83155
|
-
lastError:
|
|
83338
|
+
lastStatus: "not-running",
|
|
83339
|
+
lastError: null
|
|
83156
83340
|
};
|
|
83157
83341
|
await patchManagedInstance(stopped);
|
|
83158
83342
|
return {
|
|
83159
|
-
status:
|
|
83343
|
+
status: "not-running",
|
|
83160
83344
|
profileName,
|
|
83161
|
-
instance: managedInstanceToPayload(stopped,
|
|
83162
|
-
reason:
|
|
83345
|
+
instance: managedInstanceToPayload(stopped, false),
|
|
83346
|
+
reason: null
|
|
83163
83347
|
};
|
|
83164
|
-
}
|
|
83348
|
+
}
|
|
83349
|
+
const tree = [existing.pid, ...getDescendantPids(existing.pid, rows)].filter((pid, index, all) => all.indexOf(pid) === index).sort((a, b) => b - a);
|
|
83350
|
+
await signalPids(tree, "SIGTERM");
|
|
83351
|
+
if (!await waitForMainPidExit(existing.pid, 5e3)) {
|
|
83352
|
+
await signalPids(tree, "SIGKILL");
|
|
83353
|
+
await waitForMainPidExit(existing.pid, EXIT_WAIT_MS);
|
|
83354
|
+
}
|
|
83355
|
+
const stillRunning = (await readProcessRows()).some((row) => row.pid === existing.pid);
|
|
83356
|
+
const stopped = {
|
|
83357
|
+
...existing,
|
|
83358
|
+
pid: stillRunning ? existing.pid : null,
|
|
83359
|
+
appServerPid: stillRunning ? runtime.appServerPid : null,
|
|
83360
|
+
lastVerifiedAt: Date.now(),
|
|
83361
|
+
lastStatus: stillRunning ? "failed" : "stopped",
|
|
83362
|
+
lastError: stillRunning ? "stop-timeout" : null
|
|
83363
|
+
};
|
|
83364
|
+
await patchManagedInstance(stopped);
|
|
83365
|
+
return {
|
|
83366
|
+
status: stillRunning ? "failed" : "stopped",
|
|
83367
|
+
profileName,
|
|
83368
|
+
instance: managedInstanceToPayload(stopped, stillRunning, stopped.appServerPid, runtime.startedAt),
|
|
83369
|
+
reason: stillRunning ? "stop-timeout" : null
|
|
83370
|
+
};
|
|
83165
83371
|
}
|
|
83166
83372
|
function focusOfficialCodexProfileInstance(profileName) {
|
|
83167
83373
|
return enqueueProfileAction(async () => {
|
|
@@ -83298,24 +83504,15 @@ function stopOfficialCodexObservedProfileInstance(profileName, pid, appServerPid
|
|
|
83298
83504
|
});
|
|
83299
83505
|
}
|
|
83300
83506
|
async function restartOfficialCodexProfileInstance(options) {
|
|
83301
|
-
|
|
83302
|
-
|
|
83303
|
-
|
|
83304
|
-
|
|
83305
|
-
|
|
83306
|
-
|
|
83307
|
-
|
|
83308
|
-
}
|
|
83309
|
-
function restartOfficialCodexApp(options = {}) {
|
|
83310
|
-
if (restartPromise) return restartPromise;
|
|
83311
|
-
restartPromise = restartOfficialCodexAppOnce({
|
|
83312
|
-
source: options.source ?? "manual",
|
|
83313
|
-
currentProfileKey: options.currentProfileKey ?? null,
|
|
83314
|
-
launchIfNotRunning: options.launchIfNotRunning ?? (options.source ?? "manual") === "manual"
|
|
83315
|
-
}).finally(() => {
|
|
83316
|
-
restartPromise = null;
|
|
83507
|
+
return enqueueProfileAction(async () => {
|
|
83508
|
+
const stopped = await stopOfficialCodexProfileInstanceOnce(options.profileName);
|
|
83509
|
+
if (stopped.status === "failed") return stopped;
|
|
83510
|
+
const launched = await launchOfficialCodexProfileInstanceOnce(options);
|
|
83511
|
+
return {
|
|
83512
|
+
...launched,
|
|
83513
|
+
status: launched.status === "started" ? "restarted" : launched.status
|
|
83514
|
+
};
|
|
83317
83515
|
});
|
|
83318
|
-
return restartPromise;
|
|
83319
83516
|
}
|
|
83320
83517
|
//#endregion
|
|
83321
83518
|
//#region src/wsServer.ts
|
|
@@ -84170,6 +84367,57 @@ const createServer = fn(function* () {
|
|
|
84170
84367
|
};
|
|
84171
84368
|
const lowRemainingNotifications = /* @__PURE__ */ new Map();
|
|
84172
84369
|
const finitePercent = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.min(100, value)) : null;
|
|
84370
|
+
const AUTO_ROLL_SNAPSHOT_MAX_AGE_MS = 3 * 6e4;
|
|
84371
|
+
const AUTO_ROLL_WATCHDOG_INTERVAL_MS = 6e4;
|
|
84372
|
+
const AUTO_ROLL_WATCHDOG_ACTIVITY_TTL_MS = 10 * 6e4;
|
|
84373
|
+
const parseRateLimitTimestamp = (value) => {
|
|
84374
|
+
if (!value) return null;
|
|
84375
|
+
const parsed = Date.parse(value);
|
|
84376
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
84377
|
+
};
|
|
84378
|
+
const createAutoRollDecisionId = () => `ar-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
84379
|
+
const buildSnapshotDiagnostic = (cached, profileSnapshot, fallbackSource = "none") => {
|
|
84380
|
+
const candidates = [{
|
|
84381
|
+
snapshot: cached ?? null,
|
|
84382
|
+
source: "cache",
|
|
84383
|
+
updatedAt: parseRateLimitTimestamp(cached?.lastUpdated)
|
|
84384
|
+
}, {
|
|
84385
|
+
snapshot: profileSnapshot ?? null,
|
|
84386
|
+
source: "profile",
|
|
84387
|
+
updatedAt: parseRateLimitTimestamp(profileSnapshot?.lastUpdated)
|
|
84388
|
+
}].filter((entry) => Boolean(entry.snapshot));
|
|
84389
|
+
candidates.sort((a, b) => (b.updatedAt ?? -Infinity) - (a.updatedAt ?? -Infinity));
|
|
84390
|
+
const selected = candidates[0] ?? null;
|
|
84391
|
+
const snapshot = selected?.snapshot ?? null;
|
|
84392
|
+
const source = selected?.source ?? fallbackSource;
|
|
84393
|
+
const updatedAt = parseRateLimitTimestamp(snapshot?.lastUpdated);
|
|
84394
|
+
return {
|
|
84395
|
+
snapshot,
|
|
84396
|
+
source,
|
|
84397
|
+
ageMs: updatedAt === null ? null : Math.max(0, Date.now() - updatedAt)
|
|
84398
|
+
};
|
|
84399
|
+
};
|
|
84400
|
+
const freshAutoRollSnapshot = (snapshot) => {
|
|
84401
|
+
if (!snapshot) return null;
|
|
84402
|
+
const updatedAt = parseRateLimitTimestamp(snapshot.lastUpdated);
|
|
84403
|
+
if (updatedAt === null || Date.now() - updatedAt >= AUTO_ROLL_SNAPSHOT_MAX_AGE_MS) return null;
|
|
84404
|
+
const now = Date.now();
|
|
84405
|
+
const keepWindow = (window) => {
|
|
84406
|
+
if (!window || finitePercent(window.usedPercent) === null) return window;
|
|
84407
|
+
const resetsAt = parseRateLimitTimestamp(window.resetsAt);
|
|
84408
|
+
if (resetsAt !== null && resetsAt <= now) return;
|
|
84409
|
+
return window;
|
|
84410
|
+
};
|
|
84411
|
+
return {
|
|
84412
|
+
...snapshot,
|
|
84413
|
+
primary: keepWindow(snapshot.primary),
|
|
84414
|
+
secondary: keepWindow(snapshot.secondary)
|
|
84415
|
+
};
|
|
84416
|
+
};
|
|
84417
|
+
const isSnapshotStaleForAutoRollWatchdog = (snapshot) => {
|
|
84418
|
+
const updatedAt = parseRateLimitTimestamp(snapshot?.lastUpdated);
|
|
84419
|
+
return updatedAt === null || Date.now() - updatedAt >= AUTO_ROLL_SNAPSHOT_MAX_AGE_MS;
|
|
84420
|
+
};
|
|
84173
84421
|
const formatLowRemainingPercent = (value) => {
|
|
84174
84422
|
const rounded = Math.round(value * 10) / 10;
|
|
84175
84423
|
return (Number.isInteger(rounded) ? rounded.toFixed(0) : rounded.toFixed(1)).replace(/\.0$/, "");
|
|
@@ -84221,6 +84469,17 @@ const createServer = fn(function* () {
|
|
|
84221
84469
|
remainingPercent,
|
|
84222
84470
|
threshold: settings.lowRemainingNotificationThreshold
|
|
84223
84471
|
});
|
|
84472
|
+
const snapshotUpdatedAt = parseRateLimitTimestamp(payload.snapshot.lastUpdated);
|
|
84473
|
+
recordAutoRollActivitySafe({
|
|
84474
|
+
kind: "low-remaining-alert",
|
|
84475
|
+
status: "sent",
|
|
84476
|
+
profileName: payload.profileName,
|
|
84477
|
+
remainingPercent,
|
|
84478
|
+
threshold: settings.lowRemainingNotificationThreshold,
|
|
84479
|
+
snapshotAgeMs: snapshotUpdatedAt === null ? null : Math.max(0, Date.now() - snapshotUpdatedAt),
|
|
84480
|
+
snapshotSource: "event",
|
|
84481
|
+
profileKey: payload.accountId
|
|
84482
|
+
});
|
|
84224
84483
|
}
|
|
84225
84484
|
};
|
|
84226
84485
|
const publishProfileSwitched = (payload) => {
|
|
@@ -84231,6 +84490,7 @@ const createServer = fn(function* () {
|
|
|
84231
84490
|
let backgroundAutoRollInFlight = false;
|
|
84232
84491
|
let lastAutoRollAttempt = null;
|
|
84233
84492
|
const autoRollRearmBlockedProfiles = /* @__PURE__ */ new Set();
|
|
84493
|
+
const lastAutoRollWatchdogActivityAt = /* @__PURE__ */ new Map();
|
|
84234
84494
|
const rememberAutoRollAttempt = (source, target) => {
|
|
84235
84495
|
if (!source || !target) return;
|
|
84236
84496
|
lastAutoRollAttempt = {
|
|
@@ -84270,6 +84530,19 @@ const createServer = fn(function* () {
|
|
|
84270
84530
|
const profile = (await profileManager.listProfiles()).find((entry) => entry.name === profileName);
|
|
84271
84531
|
return profile ? resolveProfileIdentityKeyFromProfile(profile) : null;
|
|
84272
84532
|
};
|
|
84533
|
+
const hashIdentityKey = (key) => key ? createHash("sha256").update(key).digest("hex").slice(0, 12) : null;
|
|
84534
|
+
const observedOfficialCodexProfileMatches = (instance, targetProfileName, targetProfileKey) => {
|
|
84535
|
+
if (targetProfileKey && instance.profileKey) return instance.profileKey === targetProfileKey;
|
|
84536
|
+
if (instance.profileKey) return false;
|
|
84537
|
+
return Boolean(targetProfileName && instance.profileName === targetProfileName);
|
|
84538
|
+
};
|
|
84539
|
+
const recordAutoRollActivitySafe = async (input) => {
|
|
84540
|
+
try {
|
|
84541
|
+
await recordOfficialCodexActivity(input);
|
|
84542
|
+
} catch (error) {
|
|
84543
|
+
logger.warn("Failed to record auto-roll activity", { error });
|
|
84544
|
+
}
|
|
84545
|
+
};
|
|
84273
84546
|
const prepareOfficialCodexProfileLaunch = async (profileName) => {
|
|
84274
84547
|
const profile = (await profileManager.listProfiles()).find((entry) => entry.name === profileName);
|
|
84275
84548
|
if (!profile) throw new Error(`Profile '${profileName}' was not found.`);
|
|
@@ -84332,17 +84605,68 @@ const createServer = fn(function* () {
|
|
|
84332
84605
|
}
|
|
84333
84606
|
return null;
|
|
84334
84607
|
};
|
|
84608
|
+
const mapOfficialCodexAppAccountToProfile = async () => {
|
|
84609
|
+
const scopePath = nodePath.join(nodeOs.homedir(), "Library", "Application Support", "Codex", "sentry", "scope_v3.json");
|
|
84610
|
+
let parsed;
|
|
84611
|
+
try {
|
|
84612
|
+
parsed = JSON.parse(await promises.readFile(scopePath, "utf8"));
|
|
84613
|
+
} catch {
|
|
84614
|
+
return null;
|
|
84615
|
+
}
|
|
84616
|
+
const scope = parsed && typeof parsed === "object" ? parsed.scope : null;
|
|
84617
|
+
const user = scope && typeof scope === "object" ? scope.user : null;
|
|
84618
|
+
if (!user || typeof user !== "object") return null;
|
|
84619
|
+
const userRecord = user;
|
|
84620
|
+
const ids = new Set([userRecord.account_id, userRecord.id].filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean));
|
|
84621
|
+
if (ids.size === 0) return null;
|
|
84622
|
+
const profiles = await profileManager.listProfiles();
|
|
84623
|
+
for (const profile of profiles) if ([
|
|
84624
|
+
profile.accountId,
|
|
84625
|
+
profile.metadata?.chatgptAccountUserId,
|
|
84626
|
+
profile.metadata?.chatgptUserId,
|
|
84627
|
+
profile.metadata?.userId,
|
|
84628
|
+
resolveProfileIdentityKeyFromProfile(profile)
|
|
84629
|
+
].filter((value) => typeof value === "string" && value.length > 0).some((value) => ids.has(value))) return {
|
|
84630
|
+
name: profile.name,
|
|
84631
|
+
key: resolveProfileIdentityKeyFromProfile(profile)
|
|
84632
|
+
};
|
|
84633
|
+
return null;
|
|
84634
|
+
};
|
|
84335
84635
|
const enrichOfficialCodexInstances = async (payload) => {
|
|
84336
84636
|
if (payload.unmanaged.length === 0) return payload;
|
|
84337
|
-
const
|
|
84338
|
-
|
|
84637
|
+
const hasManagedRunning = payload.instances.some((instance) => instance.running);
|
|
84638
|
+
const [defaultProfile, appAccountProfile, appState] = await Promise.all([
|
|
84639
|
+
mapDefaultCodexAuthToProfile(),
|
|
84640
|
+
!hasManagedRunning && payload.unmanaged.length === 1 && payload.unmanaged[0]?.appServerPid ? mapOfficialCodexAppAccountToProfile() : Promise.resolve(null),
|
|
84641
|
+
getAppState()
|
|
84642
|
+
]);
|
|
84643
|
+
const lastProfileSwitchAt = appState.officialCodex.lastProfileSwitchAt;
|
|
84644
|
+
const lastObservedPid = appState.officialCodex.lastObservedPid;
|
|
84645
|
+
const lastVerifiedLaunchProfileKey = appState.officialCodex.lastVerifiedLaunchProfileKey;
|
|
84646
|
+
const isFreshDefaultAuthObservation = (instance) => {
|
|
84647
|
+
if (!defaultProfile) return false;
|
|
84648
|
+
if (lastObservedPid && instance.pid === lastObservedPid && lastVerifiedLaunchProfileKey === defaultProfile.key) return true;
|
|
84649
|
+
if (!lastProfileSwitchAt) return true;
|
|
84650
|
+
const startedAt = parseRateLimitTimestamp(instance.startedAt);
|
|
84651
|
+
return startedAt !== null && startedAt >= lastProfileSwitchAt - 1e3;
|
|
84652
|
+
};
|
|
84339
84653
|
return {
|
|
84340
84654
|
...payload,
|
|
84341
|
-
unmanaged: payload.unmanaged.map((instance) =>
|
|
84342
|
-
|
|
84343
|
-
|
|
84344
|
-
|
|
84345
|
-
|
|
84655
|
+
unmanaged: payload.unmanaged.map((instance) => {
|
|
84656
|
+
if (instance.profileName || !instance.appServerPid) return instance;
|
|
84657
|
+
if (appAccountProfile) return {
|
|
84658
|
+
...instance,
|
|
84659
|
+
profileName: appAccountProfile.name,
|
|
84660
|
+
profileKey: appAccountProfile.key,
|
|
84661
|
+
profileMatchSource: "app-account"
|
|
84662
|
+
};
|
|
84663
|
+
if (defaultProfile && isFreshDefaultAuthObservation(instance)) return {
|
|
84664
|
+
...instance,
|
|
84665
|
+
profileName: defaultProfile.name,
|
|
84666
|
+
profileKey: defaultProfile.key,
|
|
84667
|
+
profileMatchSource: "default-auth"
|
|
84668
|
+
};
|
|
84669
|
+
return instance;
|
|
84346
84670
|
})
|
|
84347
84671
|
};
|
|
84348
84672
|
};
|
|
@@ -84356,6 +84680,62 @@ const createServer = fn(function* () {
|
|
|
84356
84680
|
bundleId: instances.bundleId
|
|
84357
84681
|
} : null;
|
|
84358
84682
|
};
|
|
84683
|
+
const resolveOfficialCodexStatus = async (currentProfile) => {
|
|
84684
|
+
const currentProfileKey = currentProfile ? resolveProfileIdentityKeyFromProfile(currentProfile) : null;
|
|
84685
|
+
const base = await getOfficialCodexSyncStatus(currentProfileKey);
|
|
84686
|
+
if (base.state === "unsupported" || base.state === "not-found" || base.state === "not-running") return base;
|
|
84687
|
+
try {
|
|
84688
|
+
const instances = await enrichOfficialCodexInstances(await getOfficialCodexProfileInstances());
|
|
84689
|
+
const managed = instances.instances.filter((instance) => instance.running).map((instance) => ({
|
|
84690
|
+
profileName: instance.profileName,
|
|
84691
|
+
profileKey: instance.profileKey,
|
|
84692
|
+
pid: instance.pid,
|
|
84693
|
+
source: "managed"
|
|
84694
|
+
}));
|
|
84695
|
+
const unmanaged = instances.unmanaged.map((instance) => ({
|
|
84696
|
+
profileName: instance.profileName ?? null,
|
|
84697
|
+
profileKey: instance.profileKey ?? null,
|
|
84698
|
+
pid: instance.pid,
|
|
84699
|
+
source: instance.profileMatchSource ?? null
|
|
84700
|
+
}));
|
|
84701
|
+
const observedCandidates = unmanaged;
|
|
84702
|
+
const observed = observedCandidates.find((instance) => observedOfficialCodexProfileMatches(instance, currentProfile?.name ?? null, currentProfileKey)) ?? observedCandidates.find((instance) => instance.profileName || instance.profileKey) ?? null;
|
|
84703
|
+
if (!observed) {
|
|
84704
|
+
if (managed.length > 0 && unmanaged.length === 0) return {
|
|
84705
|
+
...base,
|
|
84706
|
+
state: "not-running",
|
|
84707
|
+
runningPids: [],
|
|
84708
|
+
observedProfileName: null,
|
|
84709
|
+
observedProfileKeyHash: null,
|
|
84710
|
+
observedProfileMatchSource: null
|
|
84711
|
+
};
|
|
84712
|
+
if (base.state === "stale") return {
|
|
84713
|
+
...base,
|
|
84714
|
+
observedProfileName: null,
|
|
84715
|
+
observedProfileKeyHash: null,
|
|
84716
|
+
observedProfileMatchSource: null
|
|
84717
|
+
};
|
|
84718
|
+
return base;
|
|
84719
|
+
}
|
|
84720
|
+
const matched = Boolean(observedOfficialCodexProfileMatches(observed, currentProfile?.name ?? null, currentProfileKey));
|
|
84721
|
+
if (matched && currentProfileKey && observed.pid) try {
|
|
84722
|
+
const stored = (await getAppState()).officialCodex;
|
|
84723
|
+
if (stored.lastVerifiedLaunchProfileKey !== currentProfileKey || stored.lastObservedPid !== observed.pid) await recordOfficialCodexProfileObservation(currentProfileKey, observed.pid);
|
|
84724
|
+
} catch (error) {
|
|
84725
|
+
logger.warn("Failed to record observed Official Codex profile", { error });
|
|
84726
|
+
}
|
|
84727
|
+
return {
|
|
84728
|
+
...base,
|
|
84729
|
+
state: currentProfile ? matched ? "synced" : "stale" : base.state,
|
|
84730
|
+
observedProfileName: observed.profileName,
|
|
84731
|
+
observedProfileKeyHash: hashIdentityKey(observed.profileKey),
|
|
84732
|
+
observedProfileMatchSource: observed.source
|
|
84733
|
+
};
|
|
84734
|
+
} catch (error) {
|
|
84735
|
+
logger.warn("Failed to resolve observed Official Codex profile", { error });
|
|
84736
|
+
return base;
|
|
84737
|
+
}
|
|
84738
|
+
};
|
|
84359
84739
|
const resolveAutoRollRearmActionAfterManualSwitch = async (profileName) => {
|
|
84360
84740
|
const settings = normalizeAutoRollSettings(await getStoredAutoRollSettings());
|
|
84361
84741
|
if (!settings.enabled) return "none";
|
|
@@ -84366,30 +84746,471 @@ const createServer = fn(function* () {
|
|
|
84366
84746
|
if (!summary.hasUsage) return "unblock";
|
|
84367
84747
|
return summary.remainingPercent <= settings.switchRemainingThreshold ? "block" : "unblock";
|
|
84368
84748
|
};
|
|
84369
|
-
const
|
|
84749
|
+
const OFFICIAL_CODEX_RESTART_DEBT_MAX_ATTEMPTS = 5;
|
|
84750
|
+
const OFFICIAL_CODEX_RESTART_RETRY_DELAY_MS = 61e3;
|
|
84751
|
+
const OFFICIAL_CODEX_POST_RESTART_VERIFY_TIMEOUT_MS = 15e3;
|
|
84752
|
+
const OFFICIAL_CODEX_POST_RESTART_VERIFY_INTERVAL_MS = 750;
|
|
84753
|
+
let officialCodexRestartRetryTimer = null;
|
|
84754
|
+
let officialCodexRestartDebt = null;
|
|
84755
|
+
const persistOfficialCodexRestartDebt = async (debt) => {
|
|
84756
|
+
await patchAppState({ officialCodex: { pendingRestartDebt: debt } });
|
|
84757
|
+
};
|
|
84758
|
+
const clearOfficialCodexRestartDebtLocal = () => {
|
|
84759
|
+
officialCodexRestartDebt = null;
|
|
84760
|
+
if (officialCodexRestartRetryTimer) {
|
|
84761
|
+
clearTimeout(officialCodexRestartRetryTimer);
|
|
84762
|
+
officialCodexRestartRetryTimer = null;
|
|
84763
|
+
}
|
|
84764
|
+
};
|
|
84765
|
+
const clearOfficialCodexRestartDebt = async () => {
|
|
84766
|
+
clearOfficialCodexRestartDebtLocal();
|
|
84767
|
+
await persistOfficialCodexRestartDebt(null);
|
|
84768
|
+
};
|
|
84769
|
+
const rememberOfficialCodexRestartDebt = async (targetProfileName, targetProfileKey, reason, decisionId = null, sourceProfileName, sourceProfileKey) => {
|
|
84770
|
+
const previous = officialCodexRestartDebt?.targetProfileName === targetProfileName ? officialCodexRestartDebt : null;
|
|
84771
|
+
officialCodexRestartDebt = {
|
|
84772
|
+
targetProfileName,
|
|
84773
|
+
targetProfileKey,
|
|
84774
|
+
sourceProfileName: sourceProfileName !== void 0 ? sourceProfileName : previous?.sourceProfileName ?? null,
|
|
84775
|
+
sourceProfileKey: sourceProfileKey !== void 0 ? sourceProfileKey : previous?.sourceProfileKey ?? null,
|
|
84776
|
+
decisionId: decisionId ?? previous?.decisionId ?? null,
|
|
84777
|
+
attempts: previous?.attempts ?? 0,
|
|
84778
|
+
lastReason: reason
|
|
84779
|
+
};
|
|
84780
|
+
await persistOfficialCodexRestartDebt(officialCodexRestartDebt);
|
|
84781
|
+
};
|
|
84782
|
+
const getOfficialCodexRestartDebt = async () => {
|
|
84783
|
+
if (officialCodexRestartDebt) return officialCodexRestartDebt;
|
|
84784
|
+
const stored = (await getAppState()).officialCodex.pendingRestartDebt;
|
|
84785
|
+
if (!stored) return null;
|
|
84786
|
+
officialCodexRestartDebt = {
|
|
84787
|
+
...stored,
|
|
84788
|
+
attempts: Math.max(0, stored.attempts)
|
|
84789
|
+
};
|
|
84790
|
+
return officialCodexRestartDebt;
|
|
84791
|
+
};
|
|
84792
|
+
const resolveObservedOfficialCodexProfileMatch = async (targetProfileName, targetProfileKey) => {
|
|
84793
|
+
const instances = await enrichOfficialCodexInstances(await getOfficialCodexProfileInstances());
|
|
84794
|
+
const observed = [...instances.instances.filter((instance) => instance.running).map((instance) => ({
|
|
84795
|
+
profileName: instance.profileName,
|
|
84796
|
+
profileKey: instance.profileKey,
|
|
84797
|
+
pid: instance.pid,
|
|
84798
|
+
appServerPid: instance.appServerPid,
|
|
84799
|
+
source: "managed"
|
|
84800
|
+
})), ...instances.unmanaged.map((instance) => ({
|
|
84801
|
+
profileName: instance.profileName ?? null,
|
|
84802
|
+
profileKey: instance.profileKey ?? null,
|
|
84803
|
+
pid: instance.pid,
|
|
84804
|
+
appServerPid: instance.appServerPid,
|
|
84805
|
+
source: instance.profileMatchSource ?? null
|
|
84806
|
+
}))].filter((instance) => instance.profileName || instance.profileKey || instance.pid);
|
|
84807
|
+
const matchedObserved = observed.find((instance) => observedOfficialCodexProfileMatches(instance, targetProfileName, targetProfileKey)) ?? null;
|
|
84808
|
+
const restartableObserved = observed.filter((instance) => instance.source !== "managed" && instance.pid);
|
|
84809
|
+
const singletonRestartableObserved = restartableObserved.length === 1 ? restartableObserved[0] : null;
|
|
84810
|
+
const firstObserved = matchedObserved ?? singletonRestartableObserved ?? observed[0] ?? null;
|
|
84811
|
+
return {
|
|
84812
|
+
matched: Boolean(matchedObserved),
|
|
84813
|
+
canStopObservedWindow: Boolean(firstObserved?.pid && firstObserved.source !== "managed" && (matchedObserved || singletonRestartableObserved === firstObserved)),
|
|
84814
|
+
ambiguousRestartableWindow: !matchedObserved && restartableObserved.length > 1,
|
|
84815
|
+
state: instances.state,
|
|
84816
|
+
observedProfileName: firstObserved?.profileName ?? null,
|
|
84817
|
+
observedProfileKey: firstObserved?.profileKey ?? null,
|
|
84818
|
+
observedProfileMatchSource: firstObserved?.source ?? null,
|
|
84819
|
+
pid: firstObserved?.pid ?? null,
|
|
84820
|
+
appServerPid: firstObserved?.appServerPid ?? null
|
|
84821
|
+
};
|
|
84822
|
+
};
|
|
84823
|
+
const recordTargetedOfficialCodexRestartResult = async (payload, targetProfileName, targetProfileKey, decisionId) => {
|
|
84824
|
+
const pid = payload.status === "started" || payload.status === "restarted" ? payload.pid : null;
|
|
84825
|
+
const reason = payload.status === "skipped" || payload.status === "failed" ? payload.reason : null;
|
|
84826
|
+
await recordOfficialCodexRestartResult({
|
|
84827
|
+
status: payload.status,
|
|
84828
|
+
reason,
|
|
84829
|
+
profileKey: targetProfileKey,
|
|
84830
|
+
pid
|
|
84831
|
+
});
|
|
84832
|
+
await recordAutoRollActivitySafe({
|
|
84833
|
+
kind: "official-codex-restart",
|
|
84834
|
+
status: payload.status,
|
|
84835
|
+
reason,
|
|
84836
|
+
decisionId,
|
|
84837
|
+
targetProfileName,
|
|
84838
|
+
profileKey: targetProfileKey,
|
|
84839
|
+
phase: payload.status === "failed" ? payload.phase ?? null : "profile",
|
|
84840
|
+
pid,
|
|
84841
|
+
restartRequested: true,
|
|
84842
|
+
restartResult: payload.status
|
|
84843
|
+
});
|
|
84844
|
+
};
|
|
84845
|
+
const profileActionToRestartPayload = (action, runningStatus, failedPhase) => {
|
|
84846
|
+
if (action.status === "failed") return {
|
|
84847
|
+
status: "failed",
|
|
84848
|
+
appPath: action.instance?.appPath ?? void 0,
|
|
84849
|
+
bundleId: action.instance?.bundleId ?? void 0,
|
|
84850
|
+
reason: action.reason ?? "official-codex-profile-action-failed",
|
|
84851
|
+
phase: failedPhase
|
|
84852
|
+
};
|
|
84853
|
+
if (action.status === "started" || action.status === "restarted") return {
|
|
84854
|
+
status: runningStatus,
|
|
84855
|
+
appPath: action.instance?.appPath ?? "",
|
|
84856
|
+
bundleId: action.instance?.bundleId ?? "",
|
|
84857
|
+
pid: action.instance?.pid ?? null
|
|
84858
|
+
};
|
|
84859
|
+
if (action.status === "already-running") return {
|
|
84860
|
+
status: "skipped",
|
|
84861
|
+
reason: "already-running"
|
|
84862
|
+
};
|
|
84863
|
+
if (action.status === "skipped" || action.status === "not-running") return {
|
|
84864
|
+
status: "skipped",
|
|
84865
|
+
reason: action.reason ?? "official-codex-app-not-running"
|
|
84866
|
+
};
|
|
84867
|
+
return {
|
|
84868
|
+
status: "skipped",
|
|
84869
|
+
reason: action.status
|
|
84870
|
+
};
|
|
84871
|
+
};
|
|
84872
|
+
let officialCodexRestartTargetLock = Promise.resolve();
|
|
84873
|
+
let officialCodexRestartTargetIntent = 0;
|
|
84874
|
+
const enqueueOfficialCodexRestartTarget = (work) => {
|
|
84875
|
+
const run = officialCodexRestartTargetLock.then(work, work);
|
|
84876
|
+
officialCodexRestartTargetLock = run.then(() => void 0, () => void 0);
|
|
84877
|
+
return run;
|
|
84878
|
+
};
|
|
84879
|
+
const restartOfficialCodexProfileTarget = async (args) => {
|
|
84880
|
+
const intent = ++officialCodexRestartTargetIntent;
|
|
84881
|
+
return enqueueOfficialCodexRestartTarget(() => restartOfficialCodexProfileTargetOnce(args, intent));
|
|
84882
|
+
};
|
|
84883
|
+
const restartOfficialCodexProfileTargetOnce = async (args, intent) => {
|
|
84884
|
+
const isCurrentIntent = () => intent === officialCodexRestartTargetIntent;
|
|
84885
|
+
const skipSuperseded = async (phase) => {
|
|
84886
|
+
const skipped = {
|
|
84887
|
+
status: "skipped",
|
|
84888
|
+
reason: "superseded-by-newer-profile-target"
|
|
84889
|
+
};
|
|
84890
|
+
await recordAutoRollActivitySafe({
|
|
84891
|
+
kind: "official-codex-restart",
|
|
84892
|
+
status: skipped.status,
|
|
84893
|
+
reason: skipped.reason,
|
|
84894
|
+
decisionId: args.decisionId,
|
|
84895
|
+
targetProfileName: args.targetProfileName,
|
|
84896
|
+
profileKey: args.targetProfileKey,
|
|
84897
|
+
phase,
|
|
84898
|
+
restartRequested: false,
|
|
84899
|
+
restartResult: skipped.status
|
|
84900
|
+
});
|
|
84901
|
+
return skipped;
|
|
84902
|
+
};
|
|
84903
|
+
if (!isCurrentIntent()) return skipSuperseded("queued");
|
|
84904
|
+
await recordAutoRollActivitySafe({
|
|
84905
|
+
kind: "official-codex-restart",
|
|
84906
|
+
status: "started",
|
|
84907
|
+
reason: null,
|
|
84908
|
+
decisionId: args.decisionId,
|
|
84909
|
+
targetProfileName: args.targetProfileName,
|
|
84910
|
+
profileKey: args.targetProfileKey,
|
|
84911
|
+
phase: "profile",
|
|
84912
|
+
restartRequested: true
|
|
84913
|
+
});
|
|
84914
|
+
if (!isCurrentIntent()) return skipSuperseded("start");
|
|
84915
|
+
const observed = await resolveObservedOfficialCodexProfileMatch(args.targetProfileName, args.targetProfileKey);
|
|
84916
|
+
if (!isCurrentIntent()) return skipSuperseded("observe");
|
|
84917
|
+
const canRestartManagedWindow = Boolean(observed.pid !== null && observed.observedProfileMatchSource === "managed" && observed.matched);
|
|
84918
|
+
const canStopMatchedObservedWindow = Boolean(observed.pid !== null && observed.matched && observed.observedProfileMatchSource !== "managed" && observed.canStopObservedWindow);
|
|
84919
|
+
const observedMatchesSource = !observed.matched && Boolean(args.sourceProfileName || args.sourceProfileKey) && observedOfficialCodexProfileMatches({
|
|
84920
|
+
profileName: observed.observedProfileName,
|
|
84921
|
+
profileKey: observed.observedProfileKey
|
|
84922
|
+
}, args.sourceProfileName ?? null, args.sourceProfileKey ?? null);
|
|
84923
|
+
const canStopSourceManagedWindow = Boolean(observed.pid !== null && observedMatchesSource && observed.observedProfileMatchSource === "managed" && args.sourceProfileName);
|
|
84924
|
+
const canStopSourceObservedWindow = Boolean(observed.pid !== null && observedMatchesSource && observed.observedProfileMatchSource !== "managed" && observed.canStopObservedWindow);
|
|
84925
|
+
const hasRestartableWindow = canRestartManagedWindow || canStopMatchedObservedWindow || canStopSourceManagedWindow || canStopSourceObservedWindow;
|
|
84926
|
+
if (!hasRestartableWindow && observed.ambiguousRestartableWindow) {
|
|
84927
|
+
const skipped = {
|
|
84928
|
+
status: "skipped",
|
|
84929
|
+
reason: "ambiguous-official-codex-windows"
|
|
84930
|
+
};
|
|
84931
|
+
await recordTargetedOfficialCodexRestartResult(skipped, args.targetProfileName, args.targetProfileKey, args.decisionId);
|
|
84932
|
+
return skipped;
|
|
84933
|
+
}
|
|
84934
|
+
if (!hasRestartableWindow && !args.launchIfNotRunning) {
|
|
84935
|
+
const skipped = {
|
|
84936
|
+
status: "skipped",
|
|
84937
|
+
reason: observed.state === "unsupported" ? "unsupported-platform" : observed.state === "not-found" ? "official-codex-app-not-found" : observed.pid !== null ? "unverified-official-codex-window" : "official-codex-app-not-running"
|
|
84938
|
+
};
|
|
84939
|
+
await recordTargetedOfficialCodexRestartResult(skipped, args.targetProfileName, args.targetProfileKey, args.decisionId);
|
|
84940
|
+
return skipped;
|
|
84941
|
+
}
|
|
84942
|
+
const options = await prepareOfficialCodexProfileLaunch(args.targetProfileName);
|
|
84943
|
+
if (!isCurrentIntent()) return skipSuperseded("prepare");
|
|
84944
|
+
if (observed.observedProfileMatchSource === "managed" && observed.matched) {
|
|
84945
|
+
const action = await restartOfficialCodexProfileInstance(options);
|
|
84946
|
+
if (!isCurrentIntent()) {
|
|
84947
|
+
if (action.status === "started" || action.status === "restarted") await stopOfficialCodexProfileInstance(args.targetProfileName).catch((error) => {
|
|
84948
|
+
logger.warn("Failed to stop superseded Official Codex profile", {
|
|
84949
|
+
error,
|
|
84950
|
+
profileName: args.targetProfileName
|
|
84951
|
+
});
|
|
84952
|
+
});
|
|
84953
|
+
return skipSuperseded("profile");
|
|
84954
|
+
}
|
|
84955
|
+
const payload = profileActionToRestartPayload(action, "restarted", "profile");
|
|
84956
|
+
await recordTargetedOfficialCodexRestartResult(payload, args.targetProfileName, args.targetProfileKey, args.decisionId);
|
|
84957
|
+
return payload;
|
|
84958
|
+
}
|
|
84959
|
+
let stoppedRunningWindow = false;
|
|
84960
|
+
if (canStopMatchedObservedWindow && observed.pid !== null) {
|
|
84961
|
+
const stopped = await stopOfficialCodexObservedProfileInstance(observed.observedProfileName ?? args.targetProfileName, observed.pid, observed.appServerPid);
|
|
84962
|
+
if (stopped.status === "failed") {
|
|
84963
|
+
const failed = profileActionToRestartPayload(stopped, "restarted", "quit");
|
|
84964
|
+
await recordTargetedOfficialCodexRestartResult(failed, args.targetProfileName, args.targetProfileKey, args.decisionId);
|
|
84965
|
+
return failed;
|
|
84966
|
+
}
|
|
84967
|
+
stoppedRunningWindow = stopped.status === "stopped";
|
|
84968
|
+
} else if (canStopSourceManagedWindow && args.sourceProfileName) {
|
|
84969
|
+
const stopped = await stopOfficialCodexProfileInstance(args.sourceProfileName);
|
|
84970
|
+
if (stopped.status === "failed") {
|
|
84971
|
+
const failed = profileActionToRestartPayload(stopped, "restarted", "quit");
|
|
84972
|
+
await recordTargetedOfficialCodexRestartResult(failed, args.targetProfileName, args.targetProfileKey, args.decisionId);
|
|
84973
|
+
return failed;
|
|
84974
|
+
}
|
|
84975
|
+
stoppedRunningWindow = stopped.status === "stopped";
|
|
84976
|
+
} else if (canStopSourceObservedWindow && observed.pid !== null) {
|
|
84977
|
+
const stopped = await stopOfficialCodexObservedProfileInstance(observed.observedProfileName ?? args.sourceProfileName ?? args.targetProfileName, observed.pid, observed.appServerPid);
|
|
84978
|
+
if (stopped.status === "failed") {
|
|
84979
|
+
const failed = profileActionToRestartPayload(stopped, "restarted", "quit");
|
|
84980
|
+
await recordTargetedOfficialCodexRestartResult(failed, args.targetProfileName, args.targetProfileKey, args.decisionId);
|
|
84981
|
+
return failed;
|
|
84982
|
+
}
|
|
84983
|
+
stoppedRunningWindow = stopped.status === "stopped";
|
|
84984
|
+
}
|
|
84985
|
+
if (!isCurrentIntent()) return skipSuperseded("quit");
|
|
84986
|
+
const launched = await launchOfficialCodexProfileInstance(options);
|
|
84987
|
+
if (!isCurrentIntent()) {
|
|
84988
|
+
if (launched.status === "started" || launched.status === "restarted") await stopOfficialCodexProfileInstance(args.targetProfileName).catch((error) => {
|
|
84989
|
+
logger.warn("Failed to stop superseded Official Codex profile", {
|
|
84990
|
+
error,
|
|
84991
|
+
profileName: args.targetProfileName
|
|
84992
|
+
});
|
|
84993
|
+
});
|
|
84994
|
+
return skipSuperseded("launch");
|
|
84995
|
+
}
|
|
84996
|
+
const payload = profileActionToRestartPayload(launched, stoppedRunningWindow ? "restarted" : "started", "launch");
|
|
84997
|
+
await recordTargetedOfficialCodexRestartResult(payload, args.targetProfileName, args.targetProfileKey, args.decisionId);
|
|
84998
|
+
return payload;
|
|
84999
|
+
};
|
|
85000
|
+
const waitForOfficialCodexProfileMatch = async (targetProfileName, targetProfileKey) => {
|
|
85001
|
+
const deadline = Date.now() + OFFICIAL_CODEX_POST_RESTART_VERIFY_TIMEOUT_MS;
|
|
85002
|
+
let latest = await resolveObservedOfficialCodexProfileMatch(targetProfileName, targetProfileKey);
|
|
85003
|
+
while (!latest.matched && Date.now() < deadline) {
|
|
85004
|
+
await new Promise((resolve) => setTimeout(resolve, OFFICIAL_CODEX_POST_RESTART_VERIFY_INTERVAL_MS));
|
|
85005
|
+
latest = await resolveObservedOfficialCodexProfileMatch(targetProfileName, targetProfileKey);
|
|
85006
|
+
}
|
|
85007
|
+
return latest;
|
|
85008
|
+
};
|
|
85009
|
+
const scheduleOfficialCodexRestartRetry = () => {
|
|
85010
|
+
const debt = officialCodexRestartDebt;
|
|
85011
|
+
if (!debt || officialCodexRestartRetryTimer) return;
|
|
85012
|
+
if (debt.attempts >= OFFICIAL_CODEX_RESTART_DEBT_MAX_ATTEMPTS) {
|
|
85013
|
+
clearOfficialCodexRestartDebt().catch((error) => {
|
|
85014
|
+
logger.warn("Failed to clear Official Codex restart debt", { error });
|
|
85015
|
+
});
|
|
85016
|
+
recordAutoRollActivitySafe({
|
|
85017
|
+
kind: "official-codex-restart",
|
|
85018
|
+
status: "skipped",
|
|
85019
|
+
reason: "restart-retry-exhausted",
|
|
85020
|
+
decisionId: debt.decisionId,
|
|
85021
|
+
targetProfileName: debt.targetProfileName,
|
|
85022
|
+
profileKey: debt.targetProfileKey,
|
|
85023
|
+
restartRequested: false,
|
|
85024
|
+
restartResult: "skipped"
|
|
85025
|
+
});
|
|
85026
|
+
return;
|
|
85027
|
+
}
|
|
85028
|
+
const delayMs = Math.min(5 * 6e4, OFFICIAL_CODEX_RESTART_RETRY_DELAY_MS * Math.max(1, debt.attempts + 1));
|
|
85029
|
+
officialCodexRestartRetryTimer = setTimeout(() => {
|
|
85030
|
+
officialCodexRestartRetryTimer = null;
|
|
85031
|
+
(async () => {
|
|
85032
|
+
const debt = officialCodexRestartDebt;
|
|
85033
|
+
if (!debt) return;
|
|
85034
|
+
if ((await resolveObservedOfficialCodexProfileMatch(debt.targetProfileName, debt.targetProfileKey)).matched) {
|
|
85035
|
+
await clearOfficialCodexRestartDebt();
|
|
85036
|
+
return;
|
|
85037
|
+
}
|
|
85038
|
+
if (officialCodexRestartDebt) {
|
|
85039
|
+
officialCodexRestartDebt = {
|
|
85040
|
+
...officialCodexRestartDebt,
|
|
85041
|
+
attempts: officialCodexRestartDebt.attempts + 1
|
|
85042
|
+
};
|
|
85043
|
+
await persistOfficialCodexRestartDebt(officialCodexRestartDebt);
|
|
85044
|
+
await maybeRestartOfficialCodexAfterAutoRoll(officialCodexRestartDebt.targetProfileName, officialCodexRestartDebt.targetProfileKey, officialCodexRestartDebt.decisionId, officialCodexRestartDebt.sourceProfileName, officialCodexRestartDebt.sourceProfileKey);
|
|
85045
|
+
}
|
|
85046
|
+
})().catch((error) => {
|
|
85047
|
+
logger.warn("Official Codex restart retry failed", { error });
|
|
85048
|
+
});
|
|
85049
|
+
}, delayMs);
|
|
85050
|
+
officialCodexRestartRetryTimer.unref?.();
|
|
85051
|
+
};
|
|
85052
|
+
const reconcileOfficialCodexRestartDebt = async () => {
|
|
85053
|
+
const debt = await getOfficialCodexRestartDebt();
|
|
85054
|
+
if (!debt) return;
|
|
85055
|
+
const settings = normalizeAutoRollSettings(await getStoredAutoRollSettings());
|
|
85056
|
+
if (!settings.restartOfficialCodexOnAutoRoll) {
|
|
85057
|
+
await clearOfficialCodexRestartDebt();
|
|
85058
|
+
return;
|
|
85059
|
+
}
|
|
85060
|
+
const targetProfile = (await profileManager.listProfiles()).find((profile) => profile.name === debt.targetProfileName) ?? null;
|
|
85061
|
+
if ((await resolveObservedOfficialCodexProfileMatch(debt.targetProfileName, debt.targetProfileKey)).matched) {
|
|
85062
|
+
await clearOfficialCodexRestartDebt();
|
|
85063
|
+
return;
|
|
85064
|
+
}
|
|
85065
|
+
const status = targetProfile ? await resolveOfficialCodexStatus(targetProfile) : await getOfficialCodexSyncStatus(debt.targetProfileKey);
|
|
85066
|
+
if (status.state === "synced") {
|
|
85067
|
+
await rememberOfficialCodexRestartDebt(debt.targetProfileName, debt.targetProfileKey, "launched-auth-unverified", debt.decisionId);
|
|
85068
|
+
scheduleOfficialCodexRestartRetry();
|
|
85069
|
+
return;
|
|
85070
|
+
}
|
|
85071
|
+
if (status.state === "not-running" && !settings.launchOfficialCodexWhenClosedOnAutoRoll) {
|
|
85072
|
+
await clearOfficialCodexRestartDebt();
|
|
85073
|
+
return;
|
|
85074
|
+
}
|
|
85075
|
+
if (status.state === "stale" || status.state === "unknown" || status.state === "not-running" && settings.launchOfficialCodexWhenClosedOnAutoRoll) scheduleOfficialCodexRestartRetry();
|
|
85076
|
+
};
|
|
85077
|
+
const maybeRestartOfficialCodexAfterAutoRoll = async (targetProfileName, targetProfileKey, decisionId, sourceProfileName = null, sourceProfileKey = null) => {
|
|
84370
85078
|
try {
|
|
84371
85079
|
const settings = normalizeAutoRollSettings(await getStoredAutoRollSettings());
|
|
84372
|
-
if (!settings.restartOfficialCodexOnAutoRoll)
|
|
84373
|
-
|
|
84374
|
-
|
|
84375
|
-
|
|
84376
|
-
|
|
85080
|
+
if (!settings.restartOfficialCodexOnAutoRoll) {
|
|
85081
|
+
await clearOfficialCodexRestartDebt();
|
|
85082
|
+
return;
|
|
85083
|
+
}
|
|
85084
|
+
const alreadyMatched = await resolveObservedOfficialCodexProfileMatch(targetProfileName, targetProfileKey);
|
|
85085
|
+
if (alreadyMatched.matched) {
|
|
85086
|
+
await clearOfficialCodexRestartDebt();
|
|
85087
|
+
await recordAutoRollActivitySafe({
|
|
85088
|
+
kind: "official-codex-restart",
|
|
85089
|
+
status: "skipped",
|
|
85090
|
+
reason: "already-synced",
|
|
85091
|
+
decisionId,
|
|
85092
|
+
targetProfileName,
|
|
85093
|
+
profileKey: targetProfileKey,
|
|
85094
|
+
restartRequested: false,
|
|
85095
|
+
restartResult: "skipped",
|
|
85096
|
+
observedProfileName: alreadyMatched.observedProfileName,
|
|
85097
|
+
observedProfileKey: alreadyMatched.observedProfileKey,
|
|
85098
|
+
observedProfileMatchSource: alreadyMatched.observedProfileMatchSource
|
|
85099
|
+
});
|
|
85100
|
+
return;
|
|
85101
|
+
}
|
|
85102
|
+
await rememberOfficialCodexRestartDebt(targetProfileName, targetProfileKey, null, decisionId, sourceProfileName, sourceProfileKey);
|
|
85103
|
+
const result = await restartOfficialCodexProfileTarget({
|
|
85104
|
+
targetProfileName,
|
|
85105
|
+
targetProfileKey,
|
|
85106
|
+
sourceProfileName,
|
|
85107
|
+
sourceProfileKey,
|
|
85108
|
+
launchIfNotRunning: settings.launchOfficialCodexWhenClosedOnAutoRoll,
|
|
85109
|
+
decisionId
|
|
84377
85110
|
});
|
|
84378
85111
|
trackAnalyticsEvent("official_codex_restart_after_auto_roll", {
|
|
84379
85112
|
status: result.status,
|
|
84380
|
-
reason: result.status === "skipped" || result.status === "failed" ? result.reason : void 0
|
|
84381
|
-
targetProfileName
|
|
85113
|
+
reason: result.status === "skipped" || result.status === "failed" ? result.reason : void 0
|
|
84382
85114
|
});
|
|
85115
|
+
if (result.status === "skipped" && result.reason === "cooldown") {
|
|
85116
|
+
await rememberOfficialCodexRestartDebt(targetProfileName, targetProfileKey, "cooldown", decisionId);
|
|
85117
|
+
await reconcileOfficialCodexRestartDebt();
|
|
85118
|
+
} else if (result.status === "skipped" && result.reason === "official-codex-app-not-running" && !settings.launchOfficialCodexWhenClosedOnAutoRoll) await clearOfficialCodexRestartDebt();
|
|
85119
|
+
else if (result.status === "skipped" && result.reason === "superseded-by-newer-profile-target") {
|
|
85120
|
+
if ((await getOfficialCodexRestartDebt())?.targetProfileName === targetProfileName) await clearOfficialCodexRestartDebt();
|
|
85121
|
+
} else if (result.status === "skipped" || result.status === "failed") {
|
|
85122
|
+
await rememberOfficialCodexRestartDebt(targetProfileName, targetProfileKey, result.reason, decisionId);
|
|
85123
|
+
await reconcileOfficialCodexRestartDebt();
|
|
85124
|
+
} else {
|
|
85125
|
+
const verified = await waitForOfficialCodexProfileMatch(targetProfileName, targetProfileKey);
|
|
85126
|
+
if (verified.matched) {
|
|
85127
|
+
await recordAutoRollActivitySafe({
|
|
85128
|
+
kind: "official-codex-restart",
|
|
85129
|
+
status: "auth-verified",
|
|
85130
|
+
reason: null,
|
|
85131
|
+
decisionId,
|
|
85132
|
+
targetProfileName,
|
|
85133
|
+
profileKey: targetProfileKey,
|
|
85134
|
+
restartRequested: true,
|
|
85135
|
+
restartResult: result.status,
|
|
85136
|
+
observedProfileName: verified.observedProfileName,
|
|
85137
|
+
observedProfileKey: verified.observedProfileKey,
|
|
85138
|
+
observedProfileMatchSource: verified.observedProfileMatchSource
|
|
85139
|
+
});
|
|
85140
|
+
await clearOfficialCodexRestartDebt();
|
|
85141
|
+
} else {
|
|
85142
|
+
await rememberOfficialCodexRestartDebt(targetProfileName, targetProfileKey, "launched-auth-unverified", decisionId);
|
|
85143
|
+
await recordAutoRollActivitySafe({
|
|
85144
|
+
kind: "official-codex-restart",
|
|
85145
|
+
status: "waiting",
|
|
85146
|
+
reason: "launched-auth-unverified",
|
|
85147
|
+
decisionId,
|
|
85148
|
+
targetProfileName,
|
|
85149
|
+
profileKey: targetProfileKey,
|
|
85150
|
+
restartRequested: true,
|
|
85151
|
+
restartResult: result.status,
|
|
85152
|
+
observedProfileName: verified.observedProfileName,
|
|
85153
|
+
observedProfileKey: verified.observedProfileKey,
|
|
85154
|
+
observedProfileMatchSource: verified.observedProfileMatchSource
|
|
85155
|
+
});
|
|
85156
|
+
await reconcileOfficialCodexRestartDebt();
|
|
85157
|
+
}
|
|
85158
|
+
}
|
|
84383
85159
|
if (result.status === "failed") logger.warn("Official Codex restart after auto-roll failed", result);
|
|
84384
85160
|
else if (result.status === "restarted" || result.status === "started") logger.info("Official Codex restarted after auto-roll", result);
|
|
84385
85161
|
} catch (error) {
|
|
85162
|
+
await rememberOfficialCodexRestartDebt(targetProfileName, targetProfileKey, error instanceof Error ? error.message : "restart-threw", decisionId);
|
|
85163
|
+
await recordAutoRollActivitySafe({
|
|
85164
|
+
kind: "official-codex-restart",
|
|
85165
|
+
status: "failed",
|
|
85166
|
+
reason: error instanceof Error ? error.message : "restart-threw",
|
|
85167
|
+
decisionId,
|
|
85168
|
+
targetProfileName,
|
|
85169
|
+
profileKey: targetProfileKey,
|
|
85170
|
+
restartRequested: true,
|
|
85171
|
+
restartResult: "failed"
|
|
85172
|
+
});
|
|
85173
|
+
scheduleOfficialCodexRestartRetry();
|
|
84386
85174
|
logger.warn("Official Codex restart after auto-roll threw", { error });
|
|
84387
85175
|
}
|
|
84388
85176
|
};
|
|
84389
|
-
const handleProfileSwitch = async (name, source = "app") => {
|
|
85177
|
+
const handleProfileSwitch = async (name, source = "app", decisionContext = {}) => {
|
|
84390
85178
|
if (!name) throw new Error("Profile name is required");
|
|
84391
85179
|
const previousProfile = source === "auto-roll" ? (await profileManager.getCurrentProfile()).name ?? null : null;
|
|
85180
|
+
const previousProfileKey = source === "auto-roll" ? await resolveProfileIdentityKeyByName(previousProfile) : null;
|
|
84392
85181
|
await profileManager.switchToProfile(name);
|
|
85182
|
+
if (source === "auto-roll") {
|
|
85183
|
+
const verified = await profileManager.getCurrentProfile();
|
|
85184
|
+
if (verified.name !== name || !verified.trusted) {
|
|
85185
|
+
await recordAutoRollActivitySafe({
|
|
85186
|
+
kind: "auth-verified",
|
|
85187
|
+
status: "failed",
|
|
85188
|
+
reason: "active-auth-mismatch-after-switch",
|
|
85189
|
+
decisionId: decisionContext.decisionId,
|
|
85190
|
+
sourceProfileName: previousProfile,
|
|
85191
|
+
targetProfileName: name,
|
|
85192
|
+
remainingPercent: decisionContext.remainingPercent,
|
|
85193
|
+
threshold: decisionContext.threshold,
|
|
85194
|
+
snapshotAgeMs: decisionContext.snapshotAgeMs,
|
|
85195
|
+
snapshotSource: decisionContext.snapshotSource,
|
|
85196
|
+
switchVerified: false
|
|
85197
|
+
});
|
|
85198
|
+
throw new Error("Auto-roll profile switch did not verify active Codex auth.");
|
|
85199
|
+
}
|
|
85200
|
+
await recordAutoRollActivitySafe({
|
|
85201
|
+
kind: "auth-verified",
|
|
85202
|
+
status: "ok",
|
|
85203
|
+
reason: null,
|
|
85204
|
+
decisionId: decisionContext.decisionId,
|
|
85205
|
+
sourceProfileName: previousProfile,
|
|
85206
|
+
targetProfileName: name,
|
|
85207
|
+
remainingPercent: decisionContext.remainingPercent,
|
|
85208
|
+
threshold: decisionContext.threshold,
|
|
85209
|
+
snapshotAgeMs: decisionContext.snapshotAgeMs,
|
|
85210
|
+
snapshotSource: decisionContext.snapshotSource,
|
|
85211
|
+
switchVerified: true
|
|
85212
|
+
});
|
|
85213
|
+
}
|
|
84393
85214
|
let targetProfileKey = null;
|
|
84394
85215
|
try {
|
|
84395
85216
|
targetProfileKey = await resolveProfileIdentityKeyByName(name);
|
|
@@ -84400,23 +85221,60 @@ const createServer = fn(function* () {
|
|
|
84400
85221
|
profileName: name
|
|
84401
85222
|
});
|
|
84402
85223
|
}
|
|
84403
|
-
if (source === "auto-roll")
|
|
84404
|
-
|
|
84405
|
-
|
|
84406
|
-
|
|
84407
|
-
|
|
84408
|
-
|
|
84409
|
-
|
|
84410
|
-
|
|
84411
|
-
|
|
85224
|
+
if (source === "auto-roll") {
|
|
85225
|
+
rememberAutoRollAttempt(previousProfile, name);
|
|
85226
|
+
await recordAutoRollActivitySafe({
|
|
85227
|
+
kind: "profile-switch",
|
|
85228
|
+
status: "completed",
|
|
85229
|
+
reason: null,
|
|
85230
|
+
decisionId: decisionContext.decisionId,
|
|
85231
|
+
sourceProfileName: previousProfile,
|
|
85232
|
+
targetProfileName: name,
|
|
85233
|
+
remainingPercent: decisionContext.remainingPercent,
|
|
85234
|
+
threshold: decisionContext.threshold,
|
|
85235
|
+
snapshotAgeMs: decisionContext.snapshotAgeMs,
|
|
85236
|
+
snapshotSource: decisionContext.snapshotSource,
|
|
85237
|
+
profileKey: targetProfileKey,
|
|
85238
|
+
switchVerified: true,
|
|
85239
|
+
restartRequested: decisionContext.restartRequested ?? null
|
|
84412
85240
|
});
|
|
85241
|
+
} else {
|
|
85242
|
+
officialCodexRestartTargetIntent += 1;
|
|
85243
|
+
const pendingRestart = await getOfficialCodexRestartDebt();
|
|
85244
|
+
if (pendingRestart && pendingRestart.targetProfileName !== name) {
|
|
85245
|
+
await clearOfficialCodexRestartDebt();
|
|
85246
|
+
await recordAutoRollActivitySafe({
|
|
85247
|
+
kind: "official-codex-restart",
|
|
85248
|
+
status: "skipped",
|
|
85249
|
+
reason: "manual-profile-switch-superseded-restart",
|
|
85250
|
+
decisionId: pendingRestart.decisionId,
|
|
85251
|
+
sourceProfileName: pendingRestart.sourceProfileName,
|
|
85252
|
+
targetProfileName: pendingRestart.targetProfileName,
|
|
85253
|
+
profileKey: pendingRestart.targetProfileKey,
|
|
85254
|
+
restartRequested: false,
|
|
85255
|
+
restartResult: "skipped"
|
|
85256
|
+
});
|
|
85257
|
+
}
|
|
85258
|
+
try {
|
|
85259
|
+
const rearmAction = await resolveAutoRollRearmActionAfterManualSwitch(name);
|
|
85260
|
+
if (rearmAction === "block") blockAutoRollUntilRearm(name);
|
|
85261
|
+
else if (rearmAction === "unblock") unblockAutoRollRearm(name);
|
|
85262
|
+
} catch (error) {
|
|
85263
|
+
logger.warn("Failed to evaluate auto-roll rearm block after manual switch", {
|
|
85264
|
+
error,
|
|
85265
|
+
profileName: name
|
|
85266
|
+
});
|
|
85267
|
+
}
|
|
84413
85268
|
}
|
|
84414
85269
|
await publishProfileSwitched({ name });
|
|
84415
85270
|
trackAnalyticsEvent("profile_switched", { source });
|
|
84416
|
-
if (source === "auto-roll") await maybeRestartOfficialCodexAfterAutoRoll(name, targetProfileKey);
|
|
85271
|
+
if (source === "auto-roll") await maybeRestartOfficialCodexAfterAutoRoll(name, targetProfileKey, decisionContext.decisionId ?? null, previousProfile, previousProfileKey);
|
|
85272
|
+
else maybeRunBackgroundAutoRoll();
|
|
84417
85273
|
};
|
|
84418
85274
|
const maybeRunBackgroundAutoRoll = async () => {
|
|
84419
85275
|
if (backgroundAutoRollInFlight) return;
|
|
85276
|
+
const decisionId = createAutoRollDecisionId();
|
|
85277
|
+
let lastDecisionContext = { decisionId };
|
|
84420
85278
|
backgroundAutoRollInFlight = true;
|
|
84421
85279
|
try {
|
|
84422
85280
|
const settings = normalizeAutoRollSettings(await getStoredAutoRollSettings());
|
|
@@ -84428,9 +85286,12 @@ const createServer = fn(function* () {
|
|
|
84428
85286
|
const profiles = await profileManager.listProfiles();
|
|
84429
85287
|
const snapshots = await loadCachedRateLimitSnapshots(profiles.map((profile) => resolveProfileIdentityKeyFromProfile(profile)));
|
|
84430
85288
|
const usageSummaries = /* @__PURE__ */ new Map();
|
|
85289
|
+
const snapshotDiagnostics = /* @__PURE__ */ new Map();
|
|
84431
85290
|
const profilesWithSnapshots = profiles.map((profile) => {
|
|
84432
85291
|
const accountId = resolveProfileIdentityKeyFromProfile(profile);
|
|
84433
|
-
const
|
|
85292
|
+
const diagnostic = buildSnapshotDiagnostic(snapshots.get(accountId) ?? null, profile.rateLimit ?? null);
|
|
85293
|
+
snapshotDiagnostics.set(profile.name, diagnostic);
|
|
85294
|
+
const snapshot = freshAutoRollSnapshot(diagnostic.snapshot);
|
|
84434
85295
|
usageSummaries.set(profile.name, summarizeRateLimitSnapshot(snapshot));
|
|
84435
85296
|
return {
|
|
84436
85297
|
...profile,
|
|
@@ -84441,19 +85302,125 @@ const createServer = fn(function* () {
|
|
|
84441
85302
|
const currentProfile = profilesWithSnapshots.find((profile) => profile.name === currentProfileName);
|
|
84442
85303
|
if (!currentProfile) return;
|
|
84443
85304
|
const currentSummary = usageSummaries.get(currentProfileName) ?? summarizeRateLimitSnapshot(currentProfile.rateLimit ?? null);
|
|
85305
|
+
const currentSnapshotDiagnostic = snapshotDiagnostics.get(currentProfileName) ?? buildSnapshotDiagnostic(null, currentProfile.rateLimit ?? null);
|
|
85306
|
+
const decisionContext = {
|
|
85307
|
+
decisionId,
|
|
85308
|
+
remainingPercent: currentSummary.hasUsage ? currentSummary.remainingPercent : null,
|
|
85309
|
+
threshold: settings.switchRemainingThreshold,
|
|
85310
|
+
snapshotAgeMs: currentSnapshotDiagnostic.ageMs,
|
|
85311
|
+
snapshotSource: currentSnapshotDiagnostic.source,
|
|
85312
|
+
restartRequested: settings.restartOfficialCodexOnAutoRoll
|
|
85313
|
+
};
|
|
85314
|
+
lastDecisionContext = decisionContext;
|
|
84444
85315
|
if (!currentSummary.hasUsage) return;
|
|
84445
|
-
if (isAutoRollBlockedUntilRearm(currentProfileName, currentSummary, settings.rearmRemainingThreshold))
|
|
85316
|
+
if (isAutoRollBlockedUntilRearm(currentProfileName, currentSummary, settings.rearmRemainingThreshold)) {
|
|
85317
|
+
await recordAutoRollActivitySafe({
|
|
85318
|
+
kind: "auto-roll-eval",
|
|
85319
|
+
status: "blocked",
|
|
85320
|
+
reason: "waiting-for-rearm",
|
|
85321
|
+
decisionId,
|
|
85322
|
+
profileName: currentProfileName,
|
|
85323
|
+
remainingPercent: currentSummary.remainingPercent,
|
|
85324
|
+
threshold: settings.rearmRemainingThreshold,
|
|
85325
|
+
snapshotAgeMs: currentSnapshotDiagnostic.ageMs,
|
|
85326
|
+
snapshotSource: currentSnapshotDiagnostic.source
|
|
85327
|
+
});
|
|
85328
|
+
return;
|
|
85329
|
+
}
|
|
84446
85330
|
if (currentSummary.remainingPercent > settings.switchRemainingThreshold) return;
|
|
85331
|
+
await recordAutoRollActivitySafe({
|
|
85332
|
+
kind: "auto-roll-eval",
|
|
85333
|
+
status: "threshold-hit",
|
|
85334
|
+
reason: null,
|
|
85335
|
+
decisionId,
|
|
85336
|
+
profileName: currentProfileName,
|
|
85337
|
+
remainingPercent: currentSummary.remainingPercent,
|
|
85338
|
+
threshold: settings.switchRemainingThreshold,
|
|
85339
|
+
snapshotAgeMs: currentSnapshotDiagnostic.ageMs,
|
|
85340
|
+
snapshotSource: currentSnapshotDiagnostic.source
|
|
85341
|
+
});
|
|
84447
85342
|
const candidate = computeAutoRollCandidate(profilesWithSnapshots, usageSummaries, currentProfileName, currentSummary, settings.switchRemainingThreshold, settings.priorityOrder, autoRollRearmBlockedProfiles);
|
|
84448
|
-
if (!candidate
|
|
84449
|
-
|
|
85343
|
+
if (!candidate) {
|
|
85344
|
+
await recordAutoRollActivitySafe({
|
|
85345
|
+
kind: "auto-roll-eval",
|
|
85346
|
+
status: "skipped",
|
|
85347
|
+
reason: "no-candidate",
|
|
85348
|
+
decisionId,
|
|
85349
|
+
profileName: currentProfileName,
|
|
85350
|
+
remainingPercent: currentSummary.remainingPercent,
|
|
85351
|
+
threshold: settings.switchRemainingThreshold,
|
|
85352
|
+
snapshotAgeMs: currentSnapshotDiagnostic.ageMs,
|
|
85353
|
+
snapshotSource: currentSnapshotDiagnostic.source
|
|
85354
|
+
});
|
|
85355
|
+
return;
|
|
85356
|
+
}
|
|
85357
|
+
if (isRecentAutoRollAttempt(currentProfileName, candidate.profile.name)) {
|
|
85358
|
+
await recordAutoRollActivitySafe({
|
|
85359
|
+
kind: "auto-roll-eval",
|
|
85360
|
+
status: "skipped",
|
|
85361
|
+
reason: "recent-duplicate-attempt",
|
|
85362
|
+
decisionId,
|
|
85363
|
+
sourceProfileName: currentProfileName,
|
|
85364
|
+
targetProfileName: candidate.profile.name,
|
|
85365
|
+
remainingPercent: currentSummary.remainingPercent,
|
|
85366
|
+
threshold: settings.switchRemainingThreshold,
|
|
85367
|
+
snapshotAgeMs: currentSnapshotDiagnostic.ageMs,
|
|
85368
|
+
snapshotSource: currentSnapshotDiagnostic.source
|
|
85369
|
+
});
|
|
85370
|
+
return;
|
|
85371
|
+
}
|
|
85372
|
+
await handleProfileSwitch(candidate.profile.name, "auto-roll", decisionContext);
|
|
84450
85373
|
blockAutoRollUntilRearm(currentProfileName);
|
|
84451
85374
|
} catch (error) {
|
|
85375
|
+
await recordAutoRollActivitySafe({
|
|
85376
|
+
kind: "auto-roll-eval",
|
|
85377
|
+
status: "failed",
|
|
85378
|
+
reason: error instanceof Error ? error.message : "unknown-error",
|
|
85379
|
+
decisionId,
|
|
85380
|
+
remainingPercent: lastDecisionContext.remainingPercent,
|
|
85381
|
+
threshold: lastDecisionContext.threshold,
|
|
85382
|
+
snapshotAgeMs: lastDecisionContext.snapshotAgeMs,
|
|
85383
|
+
snapshotSource: lastDecisionContext.snapshotSource
|
|
85384
|
+
});
|
|
84452
85385
|
logger.warn("Background auto-roll failed", { error });
|
|
84453
85386
|
} finally {
|
|
84454
85387
|
backgroundAutoRollInFlight = false;
|
|
84455
85388
|
}
|
|
84456
85389
|
};
|
|
85390
|
+
const runAutoRollWatchdog = async () => {
|
|
85391
|
+
const decisionId = createAutoRollDecisionId();
|
|
85392
|
+
const settings = normalizeAutoRollSettings(await getStoredAutoRollSettings());
|
|
85393
|
+
if (!settings.enabled) return;
|
|
85394
|
+
if (!(await licenseService.getCachedStatus()).isPro) return;
|
|
85395
|
+
const current = await profileManager.getCurrentProfile();
|
|
85396
|
+
const currentProfileName = typeof current.name === "string" && current.name.length > 0 ? current.name : null;
|
|
85397
|
+
if (!currentProfileName) return;
|
|
85398
|
+
const currentProfile = (await profileManager.listProfiles()).find((profile) => profile.name === currentProfileName) ?? null;
|
|
85399
|
+
if (!currentProfile) return;
|
|
85400
|
+
const accountId = resolveProfileIdentityKeyFromProfile(currentProfile);
|
|
85401
|
+
const diagnostic = buildSnapshotDiagnostic((await loadCachedRateLimitSnapshots([accountId])).get(accountId) ?? null, currentProfile.rateLimit ?? null);
|
|
85402
|
+
const snapshot = diagnostic.snapshot;
|
|
85403
|
+
if (isSnapshotStaleForAutoRollWatchdog(snapshot)) {
|
|
85404
|
+
const queued = await enqueueAccountsRefreshNow([currentProfileName]);
|
|
85405
|
+
const lastRecordedAt = lastAutoRollWatchdogActivityAt.get(accountId) ?? 0;
|
|
85406
|
+
if (queued.enqueuedAccountIds.includes(accountId) && Date.now() - lastRecordedAt >= AUTO_ROLL_WATCHDOG_ACTIVITY_TTL_MS) {
|
|
85407
|
+
lastAutoRollWatchdogActivityAt.set(accountId, Date.now());
|
|
85408
|
+
await recordAutoRollActivitySafe({
|
|
85409
|
+
kind: "auto-roll-eval",
|
|
85410
|
+
status: "refresh-queued",
|
|
85411
|
+
reason: "watchdog-stale-snapshot",
|
|
85412
|
+
decisionId,
|
|
85413
|
+
profileName: currentProfileName,
|
|
85414
|
+
threshold: settings.switchRemainingThreshold,
|
|
85415
|
+
snapshotAgeMs: diagnostic.ageMs,
|
|
85416
|
+
snapshotSource: diagnostic.source,
|
|
85417
|
+
profileKey: accountId
|
|
85418
|
+
});
|
|
85419
|
+
}
|
|
85420
|
+
return;
|
|
85421
|
+
}
|
|
85422
|
+
await maybeRunBackgroundAutoRoll();
|
|
85423
|
+
};
|
|
84457
85424
|
const handleDesktopMessage = (message) => {
|
|
84458
85425
|
if (!isDesktopChildCommand(message)) return;
|
|
84459
85426
|
if (message.type === "t3-server:switch-profile") {
|
|
@@ -84484,6 +85451,7 @@ const createServer = fn(function* () {
|
|
|
84484
85451
|
logger.warn("Low remaining notification failed", { error });
|
|
84485
85452
|
});
|
|
84486
85453
|
maybeRunBackgroundAutoRoll();
|
|
85454
|
+
reconcileOfficialCodexRestartDebt();
|
|
84487
85455
|
};
|
|
84488
85456
|
const handleRateLimitStateChanged = (payload) => {
|
|
84489
85457
|
refreshTray();
|
|
@@ -84491,9 +85459,16 @@ const createServer = fn(function* () {
|
|
|
84491
85459
|
};
|
|
84492
85460
|
rateLimitEvents.on("snapshot-updated", handleRateLimitSnapshotUpdated);
|
|
84493
85461
|
rateLimitEvents.on("refresh-state-changed", handleRateLimitStateChanged);
|
|
85462
|
+
const autoRollWatchdogInterval = setInterval(() => {
|
|
85463
|
+
runAutoRollWatchdog().catch((error) => {
|
|
85464
|
+
logger.warn("Auto-roll watchdog failed", { error });
|
|
85465
|
+
});
|
|
85466
|
+
}, AUTO_ROLL_WATCHDOG_INTERVAL_MS);
|
|
85467
|
+
autoRollWatchdogInterval.unref?.();
|
|
84494
85468
|
yield* addFinalizer(() => sync(() => {
|
|
84495
85469
|
rateLimitEvents.off("snapshot-updated", handleRateLimitSnapshotUpdated);
|
|
84496
85470
|
rateLimitEvents.off("refresh-state-changed", handleRateLimitStateChanged);
|
|
85471
|
+
clearInterval(autoRollWatchdogInterval);
|
|
84497
85472
|
}));
|
|
84498
85473
|
const unsubscribeTerminalEvents = yield* terminalManager.subscribe((event) => void runPromise(pushBus.publishAll(WS_CHANNELS.terminalEvent, event)));
|
|
84499
85474
|
yield* addFinalizer(() => sync(() => unsubscribeTerminalEvents()));
|
|
@@ -84513,6 +85488,8 @@ const createServer = fn(function* () {
|
|
|
84513
85488
|
});
|
|
84514
85489
|
});
|
|
84515
85490
|
yield* readiness.markHttpListening;
|
|
85491
|
+
maybeRunBackgroundAutoRoll();
|
|
85492
|
+
reconcileOfficialCodexRestartDebt();
|
|
84516
85493
|
readResolvedTelegramRuntimeSettings().then((settings) => queueTelegramRuntimeSettingsApply(settings)).catch((error) => {
|
|
84517
85494
|
logger.warn("Failed to apply Telegram runtime settings during startup", { error: error instanceof Error ? error.message : String(error) });
|
|
84518
85495
|
});
|
|
@@ -84891,10 +85868,15 @@ const createServer = fn(function* () {
|
|
|
84891
85868
|
return yield* promise(() => telegramBridge.testToken(body.token));
|
|
84892
85869
|
}
|
|
84893
85870
|
case WS_METHODS.profilesFetch: {
|
|
84894
|
-
const
|
|
85871
|
+
const body = request.body && typeof request.body === "object" ? stripRequestTag(request.body) : {};
|
|
85872
|
+
const data = yield* promise(() => loadProfilesViewData({
|
|
85873
|
+
autoImportActiveAuth: true,
|
|
85874
|
+
backgroundRefresh: body.backgroundRefresh !== false
|
|
85875
|
+
}));
|
|
84895
85876
|
const currentProfile = data.currentProfile ? data.profiles.find((profile) => profile.name === data.currentProfile) ?? null : null;
|
|
84896
|
-
const
|
|
84897
|
-
|
|
85877
|
+
const officialCodexStatus = yield* promise(() => resolveOfficialCodexStatus(currentProfile));
|
|
85878
|
+
maybeRunBackgroundAutoRoll();
|
|
85879
|
+
reconcileOfficialCodexRestartDebt();
|
|
84898
85880
|
refreshTray();
|
|
84899
85881
|
return {
|
|
84900
85882
|
...data,
|
|
@@ -85171,6 +86153,7 @@ const createServer = fn(function* () {
|
|
|
85171
86153
|
const normalized = normalizeAutoRollSettings(stripRequestTag(request.body).settings);
|
|
85172
86154
|
yield* promise(() => persistAutoRollSettings(normalized));
|
|
85173
86155
|
maybeRunBackgroundAutoRoll();
|
|
86156
|
+
reconcileOfficialCodexRestartDebt();
|
|
85174
86157
|
trackAnalyticsEvent("auto_roll_settings_saved", {
|
|
85175
86158
|
enabled: normalized.enabled,
|
|
85176
86159
|
rearmRemainingThreshold: normalized.rearmRemainingThreshold,
|
|
@@ -85184,12 +86167,30 @@ const createServer = fn(function* () {
|
|
|
85184
86167
|
return normalized;
|
|
85185
86168
|
}
|
|
85186
86169
|
case WS_METHODS.officialCodexRestart: return yield* promise(async () => {
|
|
85187
|
-
|
|
85188
|
-
|
|
85189
|
-
|
|
86170
|
+
const current = await profileManager.getCurrentProfile();
|
|
86171
|
+
const currentProfileKey = await resolveProfileIdentityKeyByName(current.name ?? null);
|
|
86172
|
+
if (!current.name) return {
|
|
86173
|
+
status: "skipped",
|
|
86174
|
+
reason: "profile-not-selected"
|
|
86175
|
+
};
|
|
86176
|
+
return restartOfficialCodexProfileTarget({
|
|
86177
|
+
targetProfileName: current.name,
|
|
86178
|
+
targetProfileKey: currentProfileKey,
|
|
86179
|
+
sourceProfileName: null,
|
|
86180
|
+
sourceProfileKey: null,
|
|
86181
|
+
launchIfNotRunning: true,
|
|
86182
|
+
decisionId: null
|
|
85190
86183
|
});
|
|
85191
86184
|
});
|
|
85192
|
-
case WS_METHODS.officialCodexInstances: return yield* promise(async () =>
|
|
86185
|
+
case WS_METHODS.officialCodexInstances: return yield* promise(async () => {
|
|
86186
|
+
const [instances, current] = await Promise.all([enrichOfficialCodexInstances(await getOfficialCodexProfileInstances()), profileManager.getCurrentProfile()]);
|
|
86187
|
+
const currentProfile = current.name ? (await profileManager.listProfiles()).find((profile) => profile.name === current.name) ?? null : null;
|
|
86188
|
+
const syncStatus = await getOfficialCodexSyncStatus(currentProfile ? resolveProfileIdentityKeyFromProfile(currentProfile) : null);
|
|
86189
|
+
return {
|
|
86190
|
+
...instances,
|
|
86191
|
+
syncStatus
|
|
86192
|
+
};
|
|
86193
|
+
});
|
|
85193
86194
|
case WS_METHODS.officialCodexLaunchProfile: {
|
|
85194
86195
|
const name = stripRequestTag(request.body).name?.trim() ?? "";
|
|
85195
86196
|
const access = yield* tryPromise({
|
|
@@ -85289,6 +86290,50 @@ const createServer = fn(function* () {
|
|
|
85289
86290
|
return restartOfficialCodexProfileInstance(options);
|
|
85290
86291
|
});
|
|
85291
86292
|
}
|
|
86293
|
+
case WS_METHODS.officialCodexUseProfile: {
|
|
86294
|
+
const name = stripRequestTag(request.body).name?.trim() ?? "";
|
|
86295
|
+
const access = yield* tryPromise({
|
|
86296
|
+
try: () => resolveOfficialCodexProfileAccess(),
|
|
86297
|
+
catch: toOfficialCodexProfileAccessRouteError
|
|
86298
|
+
});
|
|
86299
|
+
yield* try_({
|
|
86300
|
+
try: () => assertOfficialCodexProfileAccess(name, access),
|
|
86301
|
+
catch: toOfficialCodexProfileAccessRouteError
|
|
86302
|
+
});
|
|
86303
|
+
return yield* promise(async () => {
|
|
86304
|
+
const previousName = (await profileManager.getCurrentProfile()).name ?? null;
|
|
86305
|
+
const previousKey = await resolveProfileIdentityKeyByName(previousName);
|
|
86306
|
+
await handleProfileSwitch(name, "app");
|
|
86307
|
+
const verified = await profileManager.getCurrentProfile();
|
|
86308
|
+
if (verified.name !== name || !verified.trusted) {
|
|
86309
|
+
await recordAutoRollActivitySafe({
|
|
86310
|
+
kind: "auth-verified",
|
|
86311
|
+
status: "failed",
|
|
86312
|
+
reason: "active-auth-mismatch-after-switch",
|
|
86313
|
+
sourceProfileName: previousName,
|
|
86314
|
+
targetProfileName: name,
|
|
86315
|
+
switchVerified: false
|
|
86316
|
+
});
|
|
86317
|
+
throw new Error("Profile switch did not verify active Codex auth.");
|
|
86318
|
+
}
|
|
86319
|
+
await recordAutoRollActivitySafe({
|
|
86320
|
+
kind: "auth-verified",
|
|
86321
|
+
status: "ok",
|
|
86322
|
+
reason: null,
|
|
86323
|
+
sourceProfileName: previousName,
|
|
86324
|
+
targetProfileName: name,
|
|
86325
|
+
switchVerified: true
|
|
86326
|
+
});
|
|
86327
|
+
return restartOfficialCodexProfileTarget({
|
|
86328
|
+
targetProfileName: name,
|
|
86329
|
+
targetProfileKey: await resolveProfileIdentityKeyByName(name),
|
|
86330
|
+
sourceProfileName: previousName,
|
|
86331
|
+
sourceProfileKey: previousKey,
|
|
86332
|
+
launchIfNotRunning: true,
|
|
86333
|
+
decisionId: null
|
|
86334
|
+
});
|
|
86335
|
+
});
|
|
86336
|
+
}
|
|
85292
86337
|
case WS_METHODS.officialCodexLaunchProfiles: {
|
|
85293
86338
|
const body = stripRequestTag(request.body);
|
|
85294
86339
|
const rawNames = Array.isArray(body.names) ? body.names : [];
|
|
@@ -85361,6 +86406,78 @@ const createServer = fn(function* () {
|
|
|
85361
86406
|
trackAnalyticsEvent("official_codex_profiles_stop_requested", { count: results.length });
|
|
85362
86407
|
return { results };
|
|
85363
86408
|
}
|
|
86409
|
+
case WS_METHODS.officialCodexActivateProfiles: {
|
|
86410
|
+
const body = stripRequestTag(request.body);
|
|
86411
|
+
const rawNames = Array.isArray(body.names) ? body.names : [];
|
|
86412
|
+
const names = Array.from(new Set(rawNames.map((name) => typeof name === "string" ? name.trim() : "").filter(Boolean)));
|
|
86413
|
+
const access = yield* tryPromise({
|
|
86414
|
+
try: () => resolveOfficialCodexProfileAccess(),
|
|
86415
|
+
catch: toOfficialCodexProfileAccessRouteError
|
|
86416
|
+
});
|
|
86417
|
+
yield* try_({
|
|
86418
|
+
try: () => {
|
|
86419
|
+
for (const name of names) assertOfficialCodexProfileAccess(name, access);
|
|
86420
|
+
},
|
|
86421
|
+
catch: toOfficialCodexProfileAccessRouteError
|
|
86422
|
+
});
|
|
86423
|
+
const results = [];
|
|
86424
|
+
for (const name of names) {
|
|
86425
|
+
const result = yield* promise(async () => {
|
|
86426
|
+
try {
|
|
86427
|
+
const activation = await profileManager.activateResetWindow(name);
|
|
86428
|
+
const entry = {
|
|
86429
|
+
profileName: name,
|
|
86430
|
+
status: activation.status,
|
|
86431
|
+
reason: activation.reason,
|
|
86432
|
+
threadId: activation.threadId ?? null,
|
|
86433
|
+
turnId: activation.turnId ?? null
|
|
86434
|
+
};
|
|
86435
|
+
await recordAutoRollActivitySafe({
|
|
86436
|
+
kind: "reset-window-activation",
|
|
86437
|
+
status: entry.status,
|
|
86438
|
+
reason: entry.reason,
|
|
86439
|
+
profileName: name
|
|
86440
|
+
});
|
|
86441
|
+
return entry;
|
|
86442
|
+
} catch (error) {
|
|
86443
|
+
const entry = {
|
|
86444
|
+
profileName: name,
|
|
86445
|
+
status: "failed",
|
|
86446
|
+
reason: formatUserFacingError(error, { fallback: "Could not activate reset window." }),
|
|
86447
|
+
threadId: null,
|
|
86448
|
+
turnId: null
|
|
86449
|
+
};
|
|
86450
|
+
await recordAutoRollActivitySafe({
|
|
86451
|
+
kind: "reset-window-activation",
|
|
86452
|
+
status: entry.status,
|
|
86453
|
+
reason: entry.reason,
|
|
86454
|
+
profileName: name
|
|
86455
|
+
});
|
|
86456
|
+
return entry;
|
|
86457
|
+
}
|
|
86458
|
+
});
|
|
86459
|
+
results.push(result);
|
|
86460
|
+
}
|
|
86461
|
+
const completed = results.filter((result) => result.status === "completed").length;
|
|
86462
|
+
const failed = results.filter((result) => result.status === "failed").length;
|
|
86463
|
+
const skipped = results.filter((result) => result.status === "skipped").length;
|
|
86464
|
+
if (completed > 0) enqueueAccountsRefreshNow(results.filter((result) => result.status === "completed").map((result) => result.profileName)).catch((error) => {
|
|
86465
|
+
logger.warn("Failed to refresh rate limits after reset-window activation", { error });
|
|
86466
|
+
});
|
|
86467
|
+
trackAnalyticsEvent("official_codex_profiles_activation_requested", {
|
|
86468
|
+
count: results.length,
|
|
86469
|
+
completed,
|
|
86470
|
+
failed,
|
|
86471
|
+
skipped
|
|
86472
|
+
});
|
|
86473
|
+
return {
|
|
86474
|
+
total: results.length,
|
|
86475
|
+
completed,
|
|
86476
|
+
failed,
|
|
86477
|
+
skipped,
|
|
86478
|
+
results
|
|
86479
|
+
};
|
|
86480
|
+
}
|
|
85364
86481
|
case WS_METHODS.cliInfo: return yield* promise(() => getCodexCliInfo());
|
|
85365
86482
|
case WS_METHODS.cliStatus: return yield* promise(() => getCliInstallStatusWithFreshness());
|
|
85366
86483
|
case WS_METHODS.cliCheckFreshness: {
|