codex-worker 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/bin/codex-worker.mjs +9 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +579 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/core/failure-classifier.d.ts +2 -0
- package/dist/src/core/failure-classifier.js +70 -0
- package/dist/src/core/failure-classifier.js.map +1 -0
- package/dist/src/core/fleet-mode.d.ts +3 -0
- package/dist/src/core/fleet-mode.js +21 -0
- package/dist/src/core/fleet-mode.js.map +1 -0
- package/dist/src/core/ids.d.ts +1 -0
- package/dist/src/core/ids.js +5 -0
- package/dist/src/core/ids.js.map +1 -0
- package/dist/src/core/markdown.d.ts +5 -0
- package/dist/src/core/markdown.js +14 -0
- package/dist/src/core/markdown.js.map +1 -0
- package/dist/src/core/model-catalog.d.ts +21 -0
- package/dist/src/core/model-catalog.js +47 -0
- package/dist/src/core/model-catalog.js.map +1 -0
- package/dist/src/core/paths.d.ts +18 -0
- package/dist/src/core/paths.js +43 -0
- package/dist/src/core/paths.js.map +1 -0
- package/dist/src/core/profile-faults.d.ts +15 -0
- package/dist/src/core/profile-faults.js +110 -0
- package/dist/src/core/profile-faults.js.map +1 -0
- package/dist/src/core/profile-manager.d.ts +25 -0
- package/dist/src/core/profile-manager.js +162 -0
- package/dist/src/core/profile-manager.js.map +1 -0
- package/dist/src/core/store.d.ts +33 -0
- package/dist/src/core/store.js +184 -0
- package/dist/src/core/store.js.map +1 -0
- package/dist/src/core/types.d.ts +97 -0
- package/dist/src/core/types.js +2 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/daemon/client.d.ts +6 -0
- package/dist/src/daemon/client.js +117 -0
- package/dist/src/daemon/client.js.map +1 -0
- package/dist/src/daemon/server.d.ts +1 -0
- package/dist/src/daemon/server.js +176 -0
- package/dist/src/daemon/server.js.map +1 -0
- package/dist/src/daemon/service.d.ts +86 -0
- package/dist/src/daemon/service.js +973 -0
- package/dist/src/daemon/service.js.map +1 -0
- package/dist/src/doctor.d.ts +1 -0
- package/dist/src/doctor.js +28 -0
- package/dist/src/doctor.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/output.d.ts +9 -0
- package/dist/src/output.js +49 -0
- package/dist/src/output.js.map +1 -0
- package/dist/src/runtime/app-server.d.ts +44 -0
- package/dist/src/runtime/app-server.js +194 -0
- package/dist/src/runtime/app-server.js.map +1 -0
- package/dist/src/smoke.d.ts +1 -0
- package/dist/src/smoke.js +55 -0
- package/dist/src/smoke.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
function buildFailureInfo(category, message, details) {
|
|
2
|
+
return {
|
|
3
|
+
category,
|
|
4
|
+
retryable: category !== 'fatal',
|
|
5
|
+
message,
|
|
6
|
+
...details,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function normalizeMessage(input) {
|
|
10
|
+
if (input instanceof Error) {
|
|
11
|
+
return input.message || input.name;
|
|
12
|
+
}
|
|
13
|
+
if (typeof input === 'string') {
|
|
14
|
+
return input;
|
|
15
|
+
}
|
|
16
|
+
if (input && typeof input === 'object' && 'message' in input) {
|
|
17
|
+
const value = input.message;
|
|
18
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return 'Unknown worker failure';
|
|
23
|
+
}
|
|
24
|
+
function classifyStatusCode(statusCode) {
|
|
25
|
+
if (statusCode === undefined) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
29
|
+
return 'auth';
|
|
30
|
+
}
|
|
31
|
+
if (statusCode === 429) {
|
|
32
|
+
return 'rate_limit';
|
|
33
|
+
}
|
|
34
|
+
if (statusCode >= 500) {
|
|
35
|
+
return 'transient';
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
function classifyText(message) {
|
|
40
|
+
const text = message.toLowerCase();
|
|
41
|
+
if (text.includes('unauthorized') || text.includes('login') || text.includes('auth')) {
|
|
42
|
+
return 'auth';
|
|
43
|
+
}
|
|
44
|
+
if (text.includes('rate limit') || text.includes('429') || text.includes('quota')) {
|
|
45
|
+
return 'rate_limit';
|
|
46
|
+
}
|
|
47
|
+
if (text.includes('connection') || text.includes('socket') || text.includes('broken pipe') || text.includes('econn')) {
|
|
48
|
+
return 'connection';
|
|
49
|
+
}
|
|
50
|
+
if (text.includes('timeout') || text.includes('overloaded') || text.includes('try again')) {
|
|
51
|
+
return 'transient';
|
|
52
|
+
}
|
|
53
|
+
return 'fatal';
|
|
54
|
+
}
|
|
55
|
+
export function classifyWorkerFailure(error) {
|
|
56
|
+
const message = normalizeMessage(error);
|
|
57
|
+
const statusCode = (() => {
|
|
58
|
+
if (error && typeof error === 'object') {
|
|
59
|
+
const code = error.code;
|
|
60
|
+
if (typeof code === 'number') {
|
|
61
|
+
return code;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
})();
|
|
66
|
+
return buildFailureInfo(classifyStatusCode(statusCode) ?? classifyText(message), message, {
|
|
67
|
+
code: statusCode,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=failure-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure-classifier.js","sourceRoot":"","sources":["../../../src/core/failure-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const CODEX_ENABLE_FLEET_ENV = 'CODEX_ENABLE_FLEET';
|
|
2
|
+
const TRUTHY_VALUES = new Set(['1', 'true', 'yes', 'on']);
|
|
3
|
+
export function isFleetModeEnabled(value = process.env[CODEX_ENABLE_FLEET_ENV]) {
|
|
4
|
+
return value !== undefined && TRUTHY_VALUES.has(value.trim().toLowerCase());
|
|
5
|
+
}
|
|
6
|
+
export function appendFleetDeveloperInstructions(base) {
|
|
7
|
+
if (!isFleetModeEnabled()) {
|
|
8
|
+
return base ?? undefined;
|
|
9
|
+
}
|
|
10
|
+
const suffix = [
|
|
11
|
+
'',
|
|
12
|
+
'[codex-worker:fleet]',
|
|
13
|
+
'This request is running with fleet mode enabled.',
|
|
14
|
+
'Prefer concise, independently useful progress that can be composed with parallel workers.',
|
|
15
|
+
].join('\n');
|
|
16
|
+
if (!base || base.trim().length === 0) {
|
|
17
|
+
return suffix.trim();
|
|
18
|
+
}
|
|
19
|
+
return `${base.trim()}\n${suffix}`;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=fleet-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet-mode.js","sourceRoot":"","sources":["../../../src/core/fleet-mode.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAE1D,MAAM,UAAU,kBAAkB,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAC5E,OAAO,KAAK,KAAK,SAAS,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,gCAAgC,CAAC,IAAoB;IACnE,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAC1B,OAAO,IAAI,IAAI,SAAS,CAAC;IAC3B,CAAC;IAED,MAAM,MAAM,GAAG;QACb,EAAE;QACF,sBAAsB;QACtB,kDAAkD;QAClD,2FAA2F;KAC5F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAED,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateId(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../../src/core/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,UAAU;IACxB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
export async function readMarkdownFile(filePath, cwd = process.cwd()) {
|
|
4
|
+
const absolutePath = resolve(cwd, filePath);
|
|
5
|
+
const content = (await readFile(absolutePath, 'utf8')).trim();
|
|
6
|
+
if (!content) {
|
|
7
|
+
throw new Error(`Markdown file is empty: ${filePath}`);
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
path: absolutePath,
|
|
11
|
+
content,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/core/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAC1E,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ModelCatalogInput {
|
|
2
|
+
id: string;
|
|
3
|
+
hidden: boolean;
|
|
4
|
+
upgrade?: string | null | undefined;
|
|
5
|
+
}
|
|
6
|
+
export interface ModelAliasMapping {
|
|
7
|
+
alias: string;
|
|
8
|
+
canonical: string;
|
|
9
|
+
reason: 'upgrade';
|
|
10
|
+
}
|
|
11
|
+
export interface ModelCatalog {
|
|
12
|
+
visibleModelIds: string[];
|
|
13
|
+
hiddenModelIds: string[];
|
|
14
|
+
aliasMappings: ModelAliasMapping[];
|
|
15
|
+
}
|
|
16
|
+
export declare function buildModelCatalog(models: ModelCatalogInput[]): ModelCatalog;
|
|
17
|
+
export declare function resolveRequestedModel(requested: string, catalog: ModelCatalog): {
|
|
18
|
+
resolved: string;
|
|
19
|
+
remappedFrom?: string | undefined;
|
|
20
|
+
} | undefined;
|
|
21
|
+
export declare function describeAllowedModels(catalog: ModelCatalog, includeHidden?: boolean): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export function buildModelCatalog(models) {
|
|
2
|
+
const visibleModelIds = models
|
|
3
|
+
.filter((model) => !model.hidden)
|
|
4
|
+
.map((model) => model.id)
|
|
5
|
+
.sort((left, right) => left.localeCompare(right));
|
|
6
|
+
const hiddenModelIds = models
|
|
7
|
+
.filter((model) => model.hidden)
|
|
8
|
+
.map((model) => model.id)
|
|
9
|
+
.sort((left, right) => left.localeCompare(right));
|
|
10
|
+
const aliasMappings = models
|
|
11
|
+
.filter((model) => Boolean(model.upgrade))
|
|
12
|
+
.map((model) => ({
|
|
13
|
+
alias: model.id,
|
|
14
|
+
canonical: model.upgrade,
|
|
15
|
+
reason: 'upgrade',
|
|
16
|
+
}))
|
|
17
|
+
.sort((left, right) => left.alias.localeCompare(right.alias));
|
|
18
|
+
return {
|
|
19
|
+
visibleModelIds,
|
|
20
|
+
hiddenModelIds,
|
|
21
|
+
aliasMappings,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function resolveRequestedModel(requested, catalog) {
|
|
25
|
+
const alias = catalog.aliasMappings.find((mapping) => mapping.alias === requested);
|
|
26
|
+
if (!alias) {
|
|
27
|
+
if (catalog.visibleModelIds.includes(requested) || catalog.hiddenModelIds.includes(requested)) {
|
|
28
|
+
return { resolved: requested };
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
resolved: alias.canonical,
|
|
34
|
+
remappedFrom: requested,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function describeAllowedModels(catalog, includeHidden = false) {
|
|
38
|
+
const visible = catalog.visibleModelIds.join(', ');
|
|
39
|
+
const hidden = includeHidden && catalog.hiddenModelIds.length > 0
|
|
40
|
+
? ` | hidden: ${catalog.hiddenModelIds.join(', ')}`
|
|
41
|
+
: '';
|
|
42
|
+
const aliases = catalog.aliasMappings.length > 0
|
|
43
|
+
? ` | aliases: ${catalog.aliasMappings.map((entry) => `${entry.alias} -> ${entry.canonical}`).join(', ')}`
|
|
44
|
+
: '';
|
|
45
|
+
return `Allowed models: ${visible}${hidden}${aliases}`;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=model-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-catalog.js","sourceRoot":"","sources":["../../../src/core/model-catalog.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,iBAAiB,CAAC,MAA2B;IAC3D,MAAM,eAAe,GAAG,MAAM;SAC3B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;SAChC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;SACxB,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAEpD,MAAM,cAAc,GAAG,MAAM;SAC1B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;SAC/B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;SACxB,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAEpD,MAAM,aAAa,GAAG,MAAM;SACzB,MAAM,CAAC,CAAC,KAAK,EAAoD,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;SAC3F,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACf,KAAK,EAAE,KAAK,CAAC,EAAE;QACf,SAAS,EAAE,KAAK,CAAC,OAAQ;QACzB,MAAM,EAAE,SAAkB;KAC3B,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAEhE,OAAO;QACL,eAAe;QACf,cAAc;QACd,aAAa;KACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,OAAqB;IAErB,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IACnF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9F,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QACjC,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,SAAS;QACzB,YAAY,EAAE,SAAS;KACxB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAqB,EAAE,aAAa,GAAG,KAAK;IAChF,MAAM,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;QAC/D,CAAC,CAAC,cAAc,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACnD,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;QAC9C,CAAC,CAAC,eAAe,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,OAAO,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC1G,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,mBAAmB,OAAO,GAAG,MAAM,GAAG,OAAO,EAAE,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface StatePaths {
|
|
2
|
+
rootDir: string;
|
|
3
|
+
registryPath: string;
|
|
4
|
+
daemonMetaPath: string;
|
|
5
|
+
socketPath: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function stateRootDir(): string;
|
|
8
|
+
export declare function ensureStateRoot(): StatePaths;
|
|
9
|
+
export declare function workspaceIdForCwd(cwd: string): string;
|
|
10
|
+
export declare function workspaceDir(cwd: string): string;
|
|
11
|
+
export declare function ensureWorkspaceDirs(cwd: string): {
|
|
12
|
+
workspaceDir: string;
|
|
13
|
+
transcriptDir: string;
|
|
14
|
+
logDir: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function transcriptPath(cwd: string, threadId: string): string;
|
|
17
|
+
export declare function logPath(cwd: string, threadId: string): string;
|
|
18
|
+
export declare function buildDaemonToken(): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
export function stateRootDir() {
|
|
6
|
+
const explicitRoot = process.env.CODEX_WORKER_STATE_DIR?.trim()
|
|
7
|
+
?? process.env.CLI_CODEX_WORKER_STATE_DIR?.trim();
|
|
8
|
+
return explicitRoot || join(homedir(), '.codex-worker');
|
|
9
|
+
}
|
|
10
|
+
export function ensureStateRoot() {
|
|
11
|
+
const rootDir = stateRootDir();
|
|
12
|
+
mkdirSync(rootDir, { recursive: true });
|
|
13
|
+
return {
|
|
14
|
+
rootDir,
|
|
15
|
+
registryPath: join(rootDir, 'registry.json'),
|
|
16
|
+
daemonMetaPath: join(rootDir, 'daemon.json'),
|
|
17
|
+
socketPath: join(rootDir, 'daemon.sock'),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function workspaceIdForCwd(cwd) {
|
|
21
|
+
return createHash('sha256').update(cwd).digest('hex').slice(0, 12);
|
|
22
|
+
}
|
|
23
|
+
export function workspaceDir(cwd) {
|
|
24
|
+
return join(ensureStateRoot().rootDir, 'workspaces', workspaceIdForCwd(cwd));
|
|
25
|
+
}
|
|
26
|
+
export function ensureWorkspaceDirs(cwd) {
|
|
27
|
+
const base = workspaceDir(cwd);
|
|
28
|
+
const transcriptDir = join(base, 'threads');
|
|
29
|
+
const logDir = join(base, 'logs');
|
|
30
|
+
mkdirSync(transcriptDir, { recursive: true });
|
|
31
|
+
mkdirSync(logDir, { recursive: true });
|
|
32
|
+
return { workspaceDir: base, transcriptDir, logDir };
|
|
33
|
+
}
|
|
34
|
+
export function transcriptPath(cwd, threadId) {
|
|
35
|
+
return join(ensureWorkspaceDirs(cwd).transcriptDir, `${threadId}.jsonl`);
|
|
36
|
+
}
|
|
37
|
+
export function logPath(cwd, threadId) {
|
|
38
|
+
return join(ensureWorkspaceDirs(cwd).logDir, `${threadId}.output`);
|
|
39
|
+
}
|
|
40
|
+
export function buildDaemonToken() {
|
|
41
|
+
return randomUUID();
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/core/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,UAAU,YAAY;IAC1B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,EAAE;WAC1D,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,EAAE,CAAC;IACpD,OAAO,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,OAAO;QACL,OAAO;QACP,YAAY,EAAE,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC;QAC5C,cAAc,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC;QAC5C,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,QAAgB;IAC1D,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,GAAG,QAAQ,QAAQ,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,QAAgB;IACnD,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,QAAQ,SAAS,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AccountProfileState, WorkerFailureCategory } from './types.js';
|
|
2
|
+
export interface InjectedProfileFault {
|
|
3
|
+
category: WorkerFailureCategory;
|
|
4
|
+
remaining?: number | undefined;
|
|
5
|
+
message?: string | undefined;
|
|
6
|
+
errorType?: string | undefined;
|
|
7
|
+
statusCode?: number | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare class ProfileFaultPlanner {
|
|
10
|
+
private readonly faults;
|
|
11
|
+
constructor(raw?: string | undefined);
|
|
12
|
+
static fromEnvironment(): ProfileFaultPlanner;
|
|
13
|
+
takeFault(profile: Pick<AccountProfileState, 'id' | 'codexHome'>): InjectedProfileFault | undefined;
|
|
14
|
+
private findFault;
|
|
15
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
function defaultErrorType(category) {
|
|
2
|
+
switch (category) {
|
|
3
|
+
case 'auth':
|
|
4
|
+
return 'authentication';
|
|
5
|
+
case 'rate_limit':
|
|
6
|
+
return 'rate_limit';
|
|
7
|
+
case 'connection':
|
|
8
|
+
return 'connection';
|
|
9
|
+
case 'transient':
|
|
10
|
+
return 'transient';
|
|
11
|
+
case 'fatal':
|
|
12
|
+
return 'fatal';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function defaultStatusCode(category) {
|
|
16
|
+
switch (category) {
|
|
17
|
+
case 'auth':
|
|
18
|
+
return 401;
|
|
19
|
+
case 'rate_limit':
|
|
20
|
+
return 429;
|
|
21
|
+
case 'connection':
|
|
22
|
+
return undefined;
|
|
23
|
+
case 'transient':
|
|
24
|
+
return 504;
|
|
25
|
+
case 'fatal':
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function defaultMessage(profile, category) {
|
|
30
|
+
return `Injected ${category} failure for profile ${profile.id} (${profile.codexHome})`;
|
|
31
|
+
}
|
|
32
|
+
function normalizeFault(value) {
|
|
33
|
+
if (typeof value === 'string') {
|
|
34
|
+
return { category: value };
|
|
35
|
+
}
|
|
36
|
+
if (!value || typeof value !== 'object') {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const raw = value;
|
|
40
|
+
if (typeof raw.category !== 'string') {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const remaining = typeof raw.remaining === 'number' && Number.isFinite(raw.remaining)
|
|
44
|
+
? Math.max(0, Math.trunc(raw.remaining))
|
|
45
|
+
: undefined;
|
|
46
|
+
return {
|
|
47
|
+
category: raw.category,
|
|
48
|
+
remaining,
|
|
49
|
+
message: typeof raw.message === 'string' ? raw.message : undefined,
|
|
50
|
+
errorType: typeof raw.errorType === 'string' ? raw.errorType : undefined,
|
|
51
|
+
statusCode: typeof raw.statusCode === 'number' && Number.isFinite(raw.statusCode)
|
|
52
|
+
? Math.trunc(raw.statusCode)
|
|
53
|
+
: undefined,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export class ProfileFaultPlanner {
|
|
57
|
+
faults = new Map();
|
|
58
|
+
constructor(raw = process.env.CLI_CODEX_WORKER_PROFILE_FAULTS) {
|
|
59
|
+
if (!raw) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
let parsed;
|
|
63
|
+
try {
|
|
64
|
+
parsed = JSON.parse(raw);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw new Error(`Failed to parse CLI_CODEX_WORKER_PROFILE_FAULTS: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
|
+
}
|
|
69
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
70
|
+
throw new Error('CLI_CODEX_WORKER_PROFILE_FAULTS must be a JSON object');
|
|
71
|
+
}
|
|
72
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
73
|
+
const fault = normalizeFault(value);
|
|
74
|
+
if (fault) {
|
|
75
|
+
this.faults.set(key, fault);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
static fromEnvironment() {
|
|
80
|
+
return new ProfileFaultPlanner();
|
|
81
|
+
}
|
|
82
|
+
takeFault(profile) {
|
|
83
|
+
const fault = this.findFault(profile);
|
|
84
|
+
if (!fault) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
if (fault.remaining !== undefined) {
|
|
88
|
+
fault.remaining -= 1;
|
|
89
|
+
if (fault.remaining <= 0) {
|
|
90
|
+
this.faults.delete(profile.codexHome);
|
|
91
|
+
this.faults.delete(profile.id);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
category: fault.category,
|
|
96
|
+
remaining: fault.remaining,
|
|
97
|
+
message: fault.message ?? defaultMessage(profile, fault.category),
|
|
98
|
+
errorType: fault.errorType ?? defaultErrorType(fault.category),
|
|
99
|
+
statusCode: fault.statusCode ?? defaultStatusCode(fault.category),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
findFault(profile) {
|
|
103
|
+
const byHome = this.faults.get(profile.codexHome);
|
|
104
|
+
if (byHome) {
|
|
105
|
+
return byHome;
|
|
106
|
+
}
|
|
107
|
+
return this.faults.get(profile.id);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=profile-faults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-faults.js","sourceRoot":"","sources":["../../../src/core/profile-faults.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { WorkerFailureCategory, AccountProfileState } from './types.js';
|
|
2
|
+
export declare class ProfileManager {
|
|
3
|
+
private readonly cooldowns;
|
|
4
|
+
private readonly now;
|
|
5
|
+
private readonly profiles;
|
|
6
|
+
private currentIndex;
|
|
7
|
+
constructor(options?: {
|
|
8
|
+
profileDirs?: string[] | undefined;
|
|
9
|
+
cooldownMs?: number | undefined;
|
|
10
|
+
cooldowns?: Partial<Record<WorkerFailureCategory, number>> | undefined;
|
|
11
|
+
now?: (() => number) | undefined;
|
|
12
|
+
persistedProfiles?: AccountProfileState[] | undefined;
|
|
13
|
+
});
|
|
14
|
+
static fromEnvironment(persistedProfiles?: AccountProfileState[]): ProfileManager;
|
|
15
|
+
getCandidateProfiles(): AccountProfileState[];
|
|
16
|
+
getCurrentProfile(): AccountProfileState;
|
|
17
|
+
markFailure(reason: string): void;
|
|
18
|
+
markFailure(profileId: string, category: WorkerFailureCategory, reason: string): void;
|
|
19
|
+
markSuccess(profileId: string): void;
|
|
20
|
+
getCooldownMs(category: WorkerFailureCategory): number;
|
|
21
|
+
getProfiles(): AccountProfileState[];
|
|
22
|
+
toPersistedState(): AccountProfileState[];
|
|
23
|
+
private resetExpiredCooldowns;
|
|
24
|
+
private findFirstAvailableIndex;
|
|
25
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const DEFAULT_PROFILE_COOLDOWNS = {
|
|
4
|
+
auth: 5 * 60_000,
|
|
5
|
+
rate_limit: 15 * 60_000,
|
|
6
|
+
connection: 60_000,
|
|
7
|
+
transient: 30_000,
|
|
8
|
+
fatal: 0,
|
|
9
|
+
};
|
|
10
|
+
function defaultProfileDir() {
|
|
11
|
+
return join(homedir(), '.codex');
|
|
12
|
+
}
|
|
13
|
+
function dedupeProfileDirs(profileDirs) {
|
|
14
|
+
const seen = new Set();
|
|
15
|
+
const result = [];
|
|
16
|
+
for (const dir of profileDirs) {
|
|
17
|
+
const normalized = dir.trim();
|
|
18
|
+
if (!normalized || seen.has(normalized)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
seen.add(normalized);
|
|
22
|
+
result.push(normalized);
|
|
23
|
+
}
|
|
24
|
+
return result.length > 0 ? result : [defaultProfileDir()];
|
|
25
|
+
}
|
|
26
|
+
function buildCooldowns(options) {
|
|
27
|
+
const cooldowns = {
|
|
28
|
+
...DEFAULT_PROFILE_COOLDOWNS,
|
|
29
|
+
};
|
|
30
|
+
if (options?.cooldownMs !== undefined) {
|
|
31
|
+
cooldowns.auth = options.cooldownMs;
|
|
32
|
+
cooldowns.rate_limit = options.cooldownMs;
|
|
33
|
+
cooldowns.connection = options.cooldownMs;
|
|
34
|
+
cooldowns.transient = options.cooldownMs;
|
|
35
|
+
}
|
|
36
|
+
for (const [category, value] of Object.entries(options?.cooldowns ?? {})) {
|
|
37
|
+
if (value !== undefined) {
|
|
38
|
+
cooldowns[category] = value;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return cooldowns;
|
|
42
|
+
}
|
|
43
|
+
export class ProfileManager {
|
|
44
|
+
cooldowns;
|
|
45
|
+
now;
|
|
46
|
+
profiles;
|
|
47
|
+
currentIndex = 0;
|
|
48
|
+
constructor(options) {
|
|
49
|
+
this.cooldowns = buildCooldowns({
|
|
50
|
+
cooldownMs: options?.cooldownMs,
|
|
51
|
+
cooldowns: options?.cooldowns,
|
|
52
|
+
});
|
|
53
|
+
this.now = options?.now ?? Date.now;
|
|
54
|
+
const configuredDirs = dedupeProfileDirs(options?.profileDirs ?? [defaultProfileDir()]);
|
|
55
|
+
const persistedByDir = new Map((options?.persistedProfiles ?? []).map((profile) => [profile.codexHome, profile]));
|
|
56
|
+
this.profiles = configuredDirs.map((configDir, index) => {
|
|
57
|
+
const persisted = persistedByDir.get(configDir);
|
|
58
|
+
return {
|
|
59
|
+
id: persisted?.id ?? `profile-${index + 1}`,
|
|
60
|
+
codexHome: configDir,
|
|
61
|
+
cooldownUntil: persisted?.cooldownUntil,
|
|
62
|
+
failureCount: persisted?.failureCount ?? 0,
|
|
63
|
+
lastFailureReason: persisted?.lastFailureReason,
|
|
64
|
+
lastFailureCategory: persisted?.lastFailureCategory,
|
|
65
|
+
lastFailureAt: persisted?.lastFailureAt,
|
|
66
|
+
lastSuccessAt: persisted?.lastSuccessAt,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
this.currentIndex = this.findFirstAvailableIndex();
|
|
70
|
+
}
|
|
71
|
+
static fromEnvironment(persistedProfiles) {
|
|
72
|
+
const raw = process.env.CODEX_HOME_DIRS;
|
|
73
|
+
const dirs = raw
|
|
74
|
+
? raw.split(':').map((entry) => entry.trim()).filter(Boolean)
|
|
75
|
+
: [process.env.CODEX_HOME?.trim() || defaultProfileDir()];
|
|
76
|
+
return new ProfileManager({ profileDirs: dirs, persistedProfiles });
|
|
77
|
+
}
|
|
78
|
+
getCandidateProfiles() {
|
|
79
|
+
this.resetExpiredCooldowns();
|
|
80
|
+
return this.profiles
|
|
81
|
+
.filter((profile) => profile.cooldownUntil === undefined || profile.cooldownUntil <= this.now())
|
|
82
|
+
.map((profile) => ({ ...profile }));
|
|
83
|
+
}
|
|
84
|
+
getCurrentProfile() {
|
|
85
|
+
this.resetExpiredCooldowns();
|
|
86
|
+
const profile = this.profiles[this.currentIndex] ?? this.profiles[0];
|
|
87
|
+
if (!profile) {
|
|
88
|
+
throw new Error('No profiles configured');
|
|
89
|
+
}
|
|
90
|
+
return { ...profile };
|
|
91
|
+
}
|
|
92
|
+
markFailure(profileIdOrReason, category, reason) {
|
|
93
|
+
const usingTypedSignature = reason !== undefined;
|
|
94
|
+
const profile = usingTypedSignature
|
|
95
|
+
? this.profiles.find((entry) => entry.id === profileIdOrReason)
|
|
96
|
+
: this.profiles[this.currentIndex];
|
|
97
|
+
if (!profile) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const failureCategory = usingTypedSignature ? category : 'transient';
|
|
101
|
+
const failureReason = usingTypedSignature ? reason : profileIdOrReason;
|
|
102
|
+
profile.failureCount += 1;
|
|
103
|
+
profile.lastFailureReason = failureReason;
|
|
104
|
+
profile.lastFailureCategory = failureCategory;
|
|
105
|
+
profile.lastFailureAt = new Date(this.now()).toISOString();
|
|
106
|
+
const cooldownMs = this.getCooldownMs(failureCategory);
|
|
107
|
+
profile.cooldownUntil = cooldownMs > 0 ? this.now() + cooldownMs : undefined;
|
|
108
|
+
if (!usingTypedSignature) {
|
|
109
|
+
const nextIndex = this.findFirstAvailableIndex();
|
|
110
|
+
if (nextIndex !== -1) {
|
|
111
|
+
this.currentIndex = nextIndex;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
markSuccess(profileId) {
|
|
116
|
+
const profile = this.profiles.find((entry) => entry.id === profileId);
|
|
117
|
+
if (!profile) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
profile.cooldownUntil = undefined;
|
|
121
|
+
profile.lastSuccessAt = new Date(this.now()).toISOString();
|
|
122
|
+
const nextIndex = this.findFirstAvailableIndex();
|
|
123
|
+
if (nextIndex !== -1) {
|
|
124
|
+
this.currentIndex = nextIndex;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
getCooldownMs(category) {
|
|
128
|
+
return this.cooldowns[category];
|
|
129
|
+
}
|
|
130
|
+
getProfiles() {
|
|
131
|
+
return this.profiles.map((profile) => ({ ...profile }));
|
|
132
|
+
}
|
|
133
|
+
toPersistedState() {
|
|
134
|
+
return this.profiles.map((profile) => ({
|
|
135
|
+
id: profile.id,
|
|
136
|
+
codexHome: profile.codexHome,
|
|
137
|
+
cooldownUntil: profile.cooldownUntil,
|
|
138
|
+
failureCount: profile.failureCount,
|
|
139
|
+
lastFailureReason: profile.lastFailureReason,
|
|
140
|
+
lastFailureCategory: profile.lastFailureCategory,
|
|
141
|
+
lastFailureAt: profile.lastFailureAt,
|
|
142
|
+
lastSuccessAt: profile.lastSuccessAt,
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
resetExpiredCooldowns() {
|
|
146
|
+
const now = this.now();
|
|
147
|
+
for (const profile of this.profiles) {
|
|
148
|
+
if (profile.cooldownUntil !== undefined && profile.cooldownUntil <= now) {
|
|
149
|
+
profile.cooldownUntil = undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const nextIndex = this.findFirstAvailableIndex();
|
|
153
|
+
if (nextIndex !== -1) {
|
|
154
|
+
this.currentIndex = nextIndex;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
findFirstAvailableIndex() {
|
|
158
|
+
const now = this.now();
|
|
159
|
+
return this.profiles.findIndex((profile) => profile.cooldownUntil === undefined || profile.cooldownUntil <= now);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=profile-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-manager.js","sourceRoot":"","sources":["../../../src/core/profile-manager.ts"],"names":[],"mappings":"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"}
|