@gakr-gakr/codex 0.1.0 → 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/dist/client-DNN2uyJW.js +642 -0
- package/dist/client-factory-Bu9OClHJ.js +9 -0
- package/dist/command-formatters-BpPOTePl.js +520 -0
- package/dist/command-handlers-BBs7Vws9.js +1533 -0
- package/dist/compact-CDboBy7o.js +329 -0
- package/dist/computer-use-DCZB46Sw.js +367 -0
- package/dist/config-CLMSw0p2.js +510 -0
- package/dist/doctor-contract-api.js +53 -0
- package/dist/harness.js +51 -0
- package/dist/index.js +1171 -0
- package/dist/media-understanding-provider.js +335 -0
- package/dist/models-jLA2SIvd.js +110 -0
- package/dist/node-cli-sessions-BLRDs_US.js +1216 -0
- package/dist/plugin-activation-CEy_oYpx.js +452 -0
- package/dist/prompt-overlay.js +12 -0
- package/dist/protocol-C9UWI98H.js +9 -0
- package/dist/protocol-validators-BGBspNmF.js +5988 -0
- package/dist/provider-catalog.js +84 -0
- package/dist/provider-discovery.js +33 -0
- package/dist/provider.js +150 -0
- package/dist/rate-limit-cache-9LxQdE0K.js +24 -0
- package/dist/request-DbSPeTcV.js +89 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/run-attempt-BoEwzQCv.js +5463 -0
- package/dist/session-binding-e2GFp9VH.js +222 -0
- package/dist/shared-client-D7Vy0glq.js +631 -0
- package/dist/side-question-BDLuEzFP.js +668 -0
- package/dist/test-api.js +49 -0
- package/dist/thread-lifecycle-Clo0EHMk.js +1565 -0
- package/dist/vision-tools-Cofrv35p.js +1379 -0
- package/package.json +16 -1
- package/doctor-contract-api.ts +0 -68
- package/harness.ts +0 -72
- package/index.ts +0 -124
- package/media-understanding-provider.ts +0 -521
- package/prompt-overlay.ts +0 -21
- package/provider-catalog.ts +0 -83
- package/provider-discovery.ts +0 -45
- package/provider.ts +0 -243
- package/src/app-server/app-inventory-cache.ts +0 -324
- package/src/app-server/approval-bridge.ts +0 -1211
- package/src/app-server/auth-bridge.ts +0 -614
- package/src/app-server/capabilities.ts +0 -27
- package/src/app-server/client-factory.ts +0 -24
- package/src/app-server/client.ts +0 -715
- package/src/app-server/compact.ts +0 -512
- package/src/app-server/computer-use.ts +0 -683
- package/src/app-server/config.ts +0 -1038
- package/src/app-server/context-engine-projection.ts +0 -403
- package/src/app-server/dynamic-tool-diagnostics.ts +0 -73
- package/src/app-server/dynamic-tool-profile.ts +0 -70
- package/src/app-server/dynamic-tools.ts +0 -623
- package/src/app-server/elicitation-bridge.ts +0 -783
- package/src/app-server/event-projector.ts +0 -2065
- package/src/app-server/image-payload-sanitizer.ts +0 -167
- package/src/app-server/local-runtime-attribution.ts +0 -39
- package/src/app-server/managed-binary.ts +0 -193
- package/src/app-server/models.ts +0 -172
- package/src/app-server/native-hook-relay.ts +0 -150
- package/src/app-server/native-subagent-task-mirror.ts +0 -497
- package/src/app-server/plugin-activation.ts +0 -283
- package/src/app-server/plugin-app-cache-key.ts +0 -74
- package/src/app-server/plugin-approval-roundtrip.ts +0 -122
- package/src/app-server/plugin-inventory.ts +0 -357
- package/src/app-server/plugin-thread-config.ts +0 -455
- package/src/app-server/protocol-generated/json/DynamicToolCallParams.json +0 -33
- package/src/app-server/protocol-generated/json/v2/ErrorNotification.json +0 -199
- package/src/app-server/protocol-generated/json/v2/GetAccountResponse.json +0 -102
- package/src/app-server/protocol-generated/json/v2/ModelListResponse.json +0 -227
- package/src/app-server/protocol-generated/json/v2/ThreadResumeResponse.json +0 -2630
- package/src/app-server/protocol-generated/json/v2/ThreadStartResponse.json +0 -2630
- package/src/app-server/protocol-generated/json/v2/TurnCompletedNotification.json +0 -1659
- package/src/app-server/protocol-generated/json/v2/TurnStartResponse.json +0 -1655
- package/src/app-server/protocol-validators.ts +0 -203
- package/src/app-server/protocol.ts +0 -520
- package/src/app-server/rate-limit-cache.ts +0 -48
- package/src/app-server/rate-limits.ts +0 -583
- package/src/app-server/request.ts +0 -73
- package/src/app-server/run-attempt.ts +0 -4862
- package/src/app-server/session-binding.ts +0 -398
- package/src/app-server/session-history.ts +0 -44
- package/src/app-server/shared-client.ts +0 -289
- package/src/app-server/side-question.ts +0 -1009
- package/src/app-server/test-support.ts +0 -48
- package/src/app-server/thread-lifecycle.ts +0 -959
- package/src/app-server/timeout.ts +0 -9
- package/src/app-server/tool-progress-normalization.ts +0 -77
- package/src/app-server/trajectory.ts +0 -368
- package/src/app-server/transcript-mirror.ts +0 -208
- package/src/app-server/transport-stdio.ts +0 -107
- package/src/app-server/transport-websocket.ts +0 -90
- package/src/app-server/transport.ts +0 -117
- package/src/app-server/user-input-bridge.ts +0 -316
- package/src/app-server/version.ts +0 -4
- package/src/app-server/vision-tools.ts +0 -12
- package/src/command-account.ts +0 -544
- package/src/command-formatters.ts +0 -426
- package/src/command-handlers.ts +0 -2021
- package/src/command-plugins-management.ts +0 -137
- package/src/command-rpc.ts +0 -142
- package/src/commands.ts +0 -65
- package/src/conversation-binding-data.ts +0 -124
- package/src/conversation-binding.ts +0 -561
- package/src/conversation-control.ts +0 -303
- package/src/conversation-turn-collector.ts +0 -186
- package/src/conversation-turn-input.ts +0 -106
- package/src/migration/apply.ts +0 -501
- package/src/migration/helpers.ts +0 -55
- package/src/migration/plan.ts +0 -461
- package/src/migration/provider.ts +0 -41
- package/src/migration/source.ts +0 -643
- package/src/migration/targets.ts +0 -25
- package/src/node-cli-sessions.ts +0 -711
- package/test-api.ts +0 -95
- package/tsconfig.json +0 -16
package/dist/index.js
ADDED
|
@@ -0,0 +1,1171 @@
|
|
|
1
|
+
import { createCodexAppServerAgentHarness } from "./harness.js";
|
|
2
|
+
import { c as resolveCodexAppServerRuntimeOptions, s as readCodexPluginConfig, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-CLMSw0p2.js";
|
|
3
|
+
import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
|
4
|
+
import { buildCodexProvider } from "./provider.js";
|
|
5
|
+
import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, t as requestCodexAppServerJson } from "./request-DbSPeTcV.js";
|
|
6
|
+
import { r as formatCodexDisplayText } from "./command-formatters-BpPOTePl.js";
|
|
7
|
+
import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, i as getSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndWait, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-D7Vy0glq.js";
|
|
8
|
+
import { a as resolveCodexCliSessionForBindingOnNode, c as handleCodexConversationInboundClaim, i as listCodexCliSessionsOnNode, n as createCodexCliSessionNodeInvokePolicies, o as resumeCodexCliSessionOnNode, s as handleCodexConversationBindingResolved, t as createCodexCliSessionNodeHostCommands } from "./node-cli-sessions-BLRDs_US.js";
|
|
9
|
+
import { a as defaultCodexAppInventoryCache, n as pluginReadParams, t as ensureCodexPluginActivation } from "./plugin-activation-CEy_oYpx.js";
|
|
10
|
+
import { mutateConfigFile } from "autobot/plugin-sdk/config-mutation";
|
|
11
|
+
import { resolveLivePluginConfigObject } from "autobot/plugin-sdk/plugin-config-runtime";
|
|
12
|
+
import { definePluginEntry } from "autobot/plugin-sdk/plugin-entry";
|
|
13
|
+
import os from "node:os";
|
|
14
|
+
import fs from "node:fs/promises";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { resolveAgentConfig, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "autobot/plugin-sdk/agent-runtime";
|
|
17
|
+
import { pathExists } from "autobot/plugin-sdk/security-runtime";
|
|
18
|
+
import { MIGRATION_REASON_TARGET_EXISTS, applyMigrationManualItem, createMigrationItem, createMigrationManualItem, hasMigrationConfigPatchConflict, markMigrationItemConflict, markMigrationItemError, markMigrationItemSkipped, readMigrationConfigPath, summarizeMigrationItems, writeMigrationConfigPath } from "autobot/plugin-sdk/migration";
|
|
19
|
+
import { archiveMigrationItem, copyMigrationFileItem, withCachedMigrationConfigRuntime, writeMigrationReport } from "autobot/plugin-sdk/migration-runtime";
|
|
20
|
+
import { readJsonFileWithFallback } from "autobot/plugin-sdk/json-store";
|
|
21
|
+
//#region extensions/codex/src/commands.ts
|
|
22
|
+
function createCodexCommand(options) {
|
|
23
|
+
return {
|
|
24
|
+
name: "codex",
|
|
25
|
+
description: "Inspect and control the Codex app-server harness",
|
|
26
|
+
ownership: "reserved",
|
|
27
|
+
agentPromptGuidance: [{
|
|
28
|
+
text: "Native Codex app-server plugin is available (`/codex ...`). For Codex bind/control/thread/resume/steer/stop requests, prefer `/codex bind`, `/codex threads`, `/codex resume`, `/codex steer`, and `/codex stop` over ACP.",
|
|
29
|
+
surfaces: ["pi_main"]
|
|
30
|
+
}, {
|
|
31
|
+
text: "Use ACP for Codex only when the user explicitly asks for ACP/acpx or wants to test the ACP path.",
|
|
32
|
+
surfaces: ["pi_main"]
|
|
33
|
+
}],
|
|
34
|
+
acceptsArgs: true,
|
|
35
|
+
requireAuth: true,
|
|
36
|
+
handler: (ctx) => handleCodexCommand(ctx, options)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function handleCodexCommand(ctx, options = {}) {
|
|
40
|
+
const { loadSubcommandHandler, ...subcommandOptions } = options;
|
|
41
|
+
try {
|
|
42
|
+
return await (loadSubcommandHandler ? await loadSubcommandHandler() : await loadDefaultCodexSubcommandHandler())(ctx, subcommandOptions);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return { text: `Codex command failed: ${formatCodexDisplayText(describeControlFailure(error))}` };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function loadDefaultCodexSubcommandHandler() {
|
|
48
|
+
const { handleCodexSubcommand } = await import("./command-handlers-BBs7Vws9.js");
|
|
49
|
+
return handleCodexSubcommand;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region extensions/codex/src/migration/helpers.ts
|
|
53
|
+
async function exists(filePath) {
|
|
54
|
+
return await pathExists(filePath);
|
|
55
|
+
}
|
|
56
|
+
async function isDirectory(filePath) {
|
|
57
|
+
if (!filePath) return false;
|
|
58
|
+
try {
|
|
59
|
+
return (await fs.stat(filePath)).isDirectory();
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function resolveUserHomeDir() {
|
|
65
|
+
return process.env.HOME?.trim() || os.homedir();
|
|
66
|
+
}
|
|
67
|
+
function resolveHomePath(value) {
|
|
68
|
+
if (value === "~") return resolveUserHomeDir();
|
|
69
|
+
if (value.startsWith("~/")) return path.join(resolveUserHomeDir(), value.slice(2));
|
|
70
|
+
return path.resolve(value);
|
|
71
|
+
}
|
|
72
|
+
function sanitizeName(value) {
|
|
73
|
+
return value.trim().toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 64);
|
|
74
|
+
}
|
|
75
|
+
async function readJsonObject(filePath) {
|
|
76
|
+
if (!filePath) return {};
|
|
77
|
+
const { value: parsed } = await readJsonFileWithFallback(filePath, {});
|
|
78
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region extensions/codex/src/migration/source.ts
|
|
82
|
+
const SKILL_FILENAME = "SKILL.md";
|
|
83
|
+
const MAX_SCAN_DEPTH = 6;
|
|
84
|
+
const MAX_DISCOVERED_DIRS = 2e3;
|
|
85
|
+
function defaultCodexHome() {
|
|
86
|
+
return resolveHomePath(process.env.CODEX_HOME?.trim() || "~/.codex");
|
|
87
|
+
}
|
|
88
|
+
function personalAgentsSkillsDir() {
|
|
89
|
+
return path.join(resolveUserHomeDir(), ".agents", "skills");
|
|
90
|
+
}
|
|
91
|
+
async function safeReadDir(dir) {
|
|
92
|
+
return await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
93
|
+
}
|
|
94
|
+
async function discoverSkillDirs(params) {
|
|
95
|
+
if (!params.root || !await isDirectory(params.root)) return [];
|
|
96
|
+
const discovered = [];
|
|
97
|
+
async function visit(dir, depth) {
|
|
98
|
+
if (discovered.length >= MAX_DISCOVERED_DIRS || depth > MAX_SCAN_DEPTH) return;
|
|
99
|
+
const name = path.basename(dir);
|
|
100
|
+
if (params.excludeSystem && depth === 1 && name === ".system") return;
|
|
101
|
+
if (await exists(path.join(dir, SKILL_FILENAME))) {
|
|
102
|
+
discovered.push({
|
|
103
|
+
name,
|
|
104
|
+
source: dir,
|
|
105
|
+
sourceLabel: params.sourceLabel
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
for (const entry of await safeReadDir(dir)) {
|
|
110
|
+
if (!entry.isDirectory()) continue;
|
|
111
|
+
await visit(path.join(dir, entry.name), depth + 1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
await visit(params.root, 0);
|
|
115
|
+
return discovered;
|
|
116
|
+
}
|
|
117
|
+
async function discoverPluginDirs(codexHome) {
|
|
118
|
+
const root = path.join(codexHome, "plugins", "cache");
|
|
119
|
+
if (!await isDirectory(root)) return [];
|
|
120
|
+
const discovered = /* @__PURE__ */ new Map();
|
|
121
|
+
async function visit(dir, depth) {
|
|
122
|
+
if (discovered.size >= MAX_DISCOVERED_DIRS || depth > MAX_SCAN_DEPTH) return;
|
|
123
|
+
const manifestPath = path.join(dir, ".codex-plugin", "plugin.json");
|
|
124
|
+
if (await exists(manifestPath)) {
|
|
125
|
+
const manifest = await readJsonObject(manifestPath);
|
|
126
|
+
const name = (typeof manifest.name === "string" ? manifest.name.trim() : "") || path.basename(dir);
|
|
127
|
+
discovered.set(dir, {
|
|
128
|
+
name,
|
|
129
|
+
source: dir,
|
|
130
|
+
manifestPath,
|
|
131
|
+
sourceKind: "cache",
|
|
132
|
+
migratable: false,
|
|
133
|
+
message: "Cached Codex plugin bundle found. Review manually unless the plugin is also installed in the source Codex app-server inventory"
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
for (const entry of await safeReadDir(dir)) {
|
|
138
|
+
if (!entry.isDirectory()) continue;
|
|
139
|
+
await visit(path.join(dir, entry.name), depth + 1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
await visit(root, 0);
|
|
143
|
+
return [...discovered.values()].toSorted((a, b) => a.source.localeCompare(b.source));
|
|
144
|
+
}
|
|
145
|
+
async function discoverInstalledCuratedPlugins(codexHome, options = {}) {
|
|
146
|
+
const requestOptions = { startOptions: sourceCodexAppServerStartOptions(codexHome) };
|
|
147
|
+
try {
|
|
148
|
+
const marketplace = (await requestSourceCodexAppServerJson(requestOptions, {
|
|
149
|
+
method: "plugin/list",
|
|
150
|
+
requestParams: { cwds: [] }
|
|
151
|
+
})).marketplaces.find((entry) => entry.name === CODEX_PLUGINS_MARKETPLACE_NAME);
|
|
152
|
+
if (!marketplace) return {
|
|
153
|
+
plugins: [],
|
|
154
|
+
error: `Codex marketplace ${CODEX_PLUGINS_MARKETPLACE_NAME} was not found in source plugin inventory.`
|
|
155
|
+
};
|
|
156
|
+
const plugins = marketplace.plugins.filter((plugin) => plugin.installed).map((plugin) => buildInstalledPluginSource(plugin)).filter((plugin) => plugin !== void 0);
|
|
157
|
+
return { plugins: (options.evaluatePluginMigrationEligibility === true ? await withPluginMigrationEligibility({
|
|
158
|
+
plugins,
|
|
159
|
+
marketplace: marketplaceRef(marketplace),
|
|
160
|
+
requestOptions,
|
|
161
|
+
verifyPluginApps: options.verifyPluginApps === true
|
|
162
|
+
}) : plugins).toSorted((a, b) => (a.pluginName ?? a.name).localeCompare(b.pluginName ?? b.name)) };
|
|
163
|
+
} catch (error) {
|
|
164
|
+
return {
|
|
165
|
+
plugins: [],
|
|
166
|
+
error: error instanceof Error ? error.message : String(error)
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function sourceCodexAppServerStartOptions(codexHome) {
|
|
171
|
+
return {
|
|
172
|
+
transport: "stdio",
|
|
173
|
+
command: "codex",
|
|
174
|
+
commandSource: "managed",
|
|
175
|
+
args: [
|
|
176
|
+
"app-server",
|
|
177
|
+
"--listen",
|
|
178
|
+
"stdio://"
|
|
179
|
+
],
|
|
180
|
+
headers: {},
|
|
181
|
+
env: {
|
|
182
|
+
CODEX_HOME: codexHome,
|
|
183
|
+
HOME: path.dirname(codexHome)
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
async function requestSourceCodexAppServerJson(options, params) {
|
|
188
|
+
return await requestCodexAppServerJson({
|
|
189
|
+
method: params.method,
|
|
190
|
+
requestParams: params.requestParams,
|
|
191
|
+
timeoutMs: 6e4,
|
|
192
|
+
startOptions: options.startOptions,
|
|
193
|
+
authProfileId: null,
|
|
194
|
+
isolated: true
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function buildInstalledPluginSource(plugin) {
|
|
198
|
+
const pluginName = pluginNameFromSummary(plugin);
|
|
199
|
+
if (!pluginName) return;
|
|
200
|
+
return {
|
|
201
|
+
name: plugin.name,
|
|
202
|
+
pluginName,
|
|
203
|
+
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
204
|
+
source: `${CODEX_PLUGINS_MARKETPLACE_NAME}/${pluginName}`,
|
|
205
|
+
sourceKind: "app-server",
|
|
206
|
+
migratable: true,
|
|
207
|
+
installed: plugin.installed,
|
|
208
|
+
enabled: plugin.enabled
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function marketplaceRef(marketplace) {
|
|
212
|
+
return {
|
|
213
|
+
name: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
214
|
+
...marketplace.path ? { path: marketplace.path } : {},
|
|
215
|
+
...!marketplace.path ? { remoteMarketplaceName: marketplace.name } : {}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
async function withPluginMigrationEligibility(params) {
|
|
219
|
+
const pending = [];
|
|
220
|
+
const evaluated = [];
|
|
221
|
+
for (const plugin of params.plugins) {
|
|
222
|
+
if (plugin.enabled !== true) {
|
|
223
|
+
evaluated.push({
|
|
224
|
+
...plugin,
|
|
225
|
+
migratable: false,
|
|
226
|
+
migrationBlock: { code: "plugin_disabled" },
|
|
227
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" is installed in Codex but disabled; enable it in Codex before migrating it to AutoBot.`
|
|
228
|
+
});
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const detail = await readPluginDetail(params.requestOptions, params.marketplace, plugin);
|
|
232
|
+
if (!detail.ok) {
|
|
233
|
+
evaluated.push({
|
|
234
|
+
...plugin,
|
|
235
|
+
migratable: false,
|
|
236
|
+
migrationBlock: {
|
|
237
|
+
code: "plugin_read_unavailable",
|
|
238
|
+
error: detail.error
|
|
239
|
+
},
|
|
240
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" detail could not be read: ${detail.error}`
|
|
241
|
+
});
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (detail.detail.apps.length === 0) {
|
|
245
|
+
evaluated.push({
|
|
246
|
+
...plugin,
|
|
247
|
+
migratable: true
|
|
248
|
+
});
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const apps = detail.detail.apps.map(sourcePluginAppFact).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
252
|
+
pending.push({
|
|
253
|
+
plugin,
|
|
254
|
+
apps
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
if (pending.length === 0) return evaluated;
|
|
258
|
+
let sourceAccount;
|
|
259
|
+
try {
|
|
260
|
+
sourceAccount = await readSourceCodexAccount(params.requestOptions);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (!params.verifyPluginApps) {
|
|
263
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
264
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
265
|
+
...plugin,
|
|
266
|
+
migratable: false,
|
|
267
|
+
migrationBlock: {
|
|
268
|
+
code: "codex_account_unavailable",
|
|
269
|
+
apps,
|
|
270
|
+
error: message
|
|
271
|
+
},
|
|
272
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but the source Codex app-server account could not be read: ${message}`
|
|
273
|
+
});
|
|
274
|
+
return evaluated;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (sourceAccount && sourceAccount !== "chatgpt") {
|
|
278
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
279
|
+
...plugin,
|
|
280
|
+
migratable: false,
|
|
281
|
+
migrationBlock: {
|
|
282
|
+
code: "codex_subscription_required",
|
|
283
|
+
apps
|
|
284
|
+
},
|
|
285
|
+
message: codexSubscriptionRequiredMessage(plugin)
|
|
286
|
+
});
|
|
287
|
+
return evaluated;
|
|
288
|
+
}
|
|
289
|
+
if (!params.verifyPluginApps) {
|
|
290
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
291
|
+
...plugin,
|
|
292
|
+
apps,
|
|
293
|
+
migratable: true
|
|
294
|
+
});
|
|
295
|
+
return evaluated;
|
|
296
|
+
}
|
|
297
|
+
const snapshot = await refreshSourceAppInventory(params.requestOptions).catch((error) => {
|
|
298
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
299
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
300
|
+
...plugin,
|
|
301
|
+
migratable: false,
|
|
302
|
+
migrationBlock: {
|
|
303
|
+
code: "app_inventory_unavailable",
|
|
304
|
+
apps,
|
|
305
|
+
error: message
|
|
306
|
+
},
|
|
307
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but source app inventory could not be read: ${message}`
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
if (!snapshot) return evaluated;
|
|
311
|
+
const appInfoById = new Map(snapshot.apps.map((app) => [app.id, app]));
|
|
312
|
+
for (const { plugin, apps: declaredApps } of pending) {
|
|
313
|
+
const apps = declaredApps.map((app) => sourcePluginAppFactWithInventory(app, appInfoById.get(app.id))).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
314
|
+
const blockCode = migrationBlockCodeForApps(apps);
|
|
315
|
+
if (!blockCode) {
|
|
316
|
+
evaluated.push({
|
|
317
|
+
...plugin,
|
|
318
|
+
apps,
|
|
319
|
+
migratable: true
|
|
320
|
+
});
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
evaluated.push({
|
|
324
|
+
...plugin,
|
|
325
|
+
migratable: false,
|
|
326
|
+
migrationBlock: {
|
|
327
|
+
code: blockCode,
|
|
328
|
+
apps
|
|
329
|
+
},
|
|
330
|
+
message: appInventoryBlockMessage(plugin, apps, blockCode)
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
return evaluated;
|
|
334
|
+
}
|
|
335
|
+
async function readSourceCodexAccount(options) {
|
|
336
|
+
const response = await requestSourceCodexAppServerJson(options, {
|
|
337
|
+
method: "account/read",
|
|
338
|
+
requestParams: { refreshToken: false }
|
|
339
|
+
});
|
|
340
|
+
if (!response.account || typeof response.account !== "object" || Array.isArray(response.account)) return "missing";
|
|
341
|
+
return response.account.type === "chatgpt" ? "chatgpt" : "non_chatgpt";
|
|
342
|
+
}
|
|
343
|
+
async function readPluginDetail(options, marketplace, plugin) {
|
|
344
|
+
try {
|
|
345
|
+
return {
|
|
346
|
+
ok: true,
|
|
347
|
+
detail: (await requestSourceCodexAppServerJson(options, {
|
|
348
|
+
method: "plugin/read",
|
|
349
|
+
requestParams: pluginReadParams(marketplace, plugin.pluginName ?? plugin.name)
|
|
350
|
+
})).plugin
|
|
351
|
+
};
|
|
352
|
+
} catch (error) {
|
|
353
|
+
return {
|
|
354
|
+
ok: false,
|
|
355
|
+
error: error instanceof Error ? error.message : String(error)
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async function refreshSourceAppInventory(options) {
|
|
360
|
+
const key = buildCodexPluginAppCacheKey({ appServer: { start: options.startOptions } });
|
|
361
|
+
const request = async (method, requestParams) => await requestSourceCodexAppServerJson(options, {
|
|
362
|
+
method,
|
|
363
|
+
requestParams
|
|
364
|
+
});
|
|
365
|
+
return await defaultCodexAppInventoryCache.refreshNow({
|
|
366
|
+
key,
|
|
367
|
+
request,
|
|
368
|
+
forceRefetch: true
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
function sourcePluginAppFact(app) {
|
|
372
|
+
return {
|
|
373
|
+
id: app.id,
|
|
374
|
+
name: app.name,
|
|
375
|
+
needsAuth: app.needsAuth
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function sourcePluginAppFactWithInventory(app, info) {
|
|
379
|
+
if (!info) return app;
|
|
380
|
+
return {
|
|
381
|
+
...app,
|
|
382
|
+
isAccessible: info.isAccessible,
|
|
383
|
+
isEnabled: info.isEnabled
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function migrationBlockCodeForApps(apps) {
|
|
387
|
+
if (apps.some((app) => app.isAccessible === false)) return "app_inaccessible";
|
|
388
|
+
if (apps.some((app) => app.isEnabled === false)) return "app_disabled";
|
|
389
|
+
if (apps.some((app) => app.isAccessible === void 0 || app.isEnabled === void 0)) return "app_missing";
|
|
390
|
+
}
|
|
391
|
+
function appInventoryBlockMessage(plugin, apps, code) {
|
|
392
|
+
const status = code === "app_inaccessible" ? "inaccessible" : code === "app_disabled" ? "disabled" : "missing";
|
|
393
|
+
const blocking = apps.find((app) => code === "app_inaccessible" ? app.isAccessible === false : code === "app_disabled" ? app.isEnabled === false : app.isAccessible === void 0 || app.isEnabled === void 0) ?? apps[0];
|
|
394
|
+
const appLabel = blocking ? ` app "${blocking.name}"` : " an owned app";
|
|
395
|
+
return `Codex plugin "${plugin.pluginName ?? plugin.name}" owns${appLabel} but the source app inventory reports it is ${status}; authenticate or enable the app in Codex before migrating it to AutoBot.`;
|
|
396
|
+
}
|
|
397
|
+
function codexPluginMigrationSubscriptionWarning() {
|
|
398
|
+
return "Codex app-backed plugin migration requires the Codex app-server source account to be logged in with a ChatGPT subscription account. Log in to the Codex app with subscription auth; AutoBot auth or API-key auth does not satisfy Codex app connector access.";
|
|
399
|
+
}
|
|
400
|
+
function codexSubscriptionRequiredMessage(plugin) {
|
|
401
|
+
return `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but ${codexPluginMigrationSubscriptionWarning()}`;
|
|
402
|
+
}
|
|
403
|
+
function pluginNameFromSummary(summary) {
|
|
404
|
+
const candidates = [summary.id, summary.name];
|
|
405
|
+
for (const candidate of candidates) {
|
|
406
|
+
const trimmed = candidate.trim();
|
|
407
|
+
if (!trimmed) continue;
|
|
408
|
+
const normalized = ((trimmed.endsWith(`@openai-curated`) ? trimmed.slice(0, -`@${CODEX_PLUGINS_MARKETPLACE_NAME}`.length) : trimmed).split("/").at(-1)?.trim())?.toLowerCase().replaceAll(/\s+/gu, "-");
|
|
409
|
+
if (normalized) return normalized;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
async function discoverCodexSource(inputOrOptions) {
|
|
413
|
+
const options = typeof inputOrOptions === "string" || inputOrOptions === void 0 ? { input: inputOrOptions } : inputOrOptions;
|
|
414
|
+
const codexHome = resolveHomePath(options.input?.trim() || defaultCodexHome());
|
|
415
|
+
const codexSkillsDir = path.join(codexHome, "skills");
|
|
416
|
+
const agentsSkillsDir = personalAgentsSkillsDir();
|
|
417
|
+
const configPath = path.join(codexHome, "config.toml");
|
|
418
|
+
const hooksPath = path.join(codexHome, "hooks", "hooks.json");
|
|
419
|
+
const codexSkills = await discoverSkillDirs({
|
|
420
|
+
root: codexSkillsDir,
|
|
421
|
+
sourceLabel: "Codex skill",
|
|
422
|
+
excludeSystem: true
|
|
423
|
+
});
|
|
424
|
+
const personalAgentSkills = await discoverSkillDirs({
|
|
425
|
+
root: agentsSkillsDir,
|
|
426
|
+
sourceLabel: "personal AgentSkill"
|
|
427
|
+
});
|
|
428
|
+
const sourcePluginDiscovery = await discoverInstalledCuratedPlugins(codexHome, options);
|
|
429
|
+
const sourcePluginNames = new Set(sourcePluginDiscovery.plugins.flatMap((plugin) => plugin.pluginName ? [plugin.pluginName] : []));
|
|
430
|
+
const cachedPlugins = (await discoverPluginDirs(codexHome)).filter((plugin) => {
|
|
431
|
+
const normalizedName = sanitizePluginName(plugin.name);
|
|
432
|
+
return !sourcePluginNames.has(normalizedName);
|
|
433
|
+
});
|
|
434
|
+
const plugins = [...sourcePluginDiscovery.plugins, ...cachedPlugins].toSorted((a, b) => a.source.localeCompare(b.source));
|
|
435
|
+
const archivePaths = [];
|
|
436
|
+
if (await exists(configPath)) archivePaths.push({
|
|
437
|
+
id: "archive:config.toml",
|
|
438
|
+
path: configPath,
|
|
439
|
+
relativePath: "config.toml",
|
|
440
|
+
message: "Codex config is archived for manual review; it is not activated automatically"
|
|
441
|
+
});
|
|
442
|
+
if (await exists(hooksPath)) archivePaths.push({
|
|
443
|
+
id: "archive:hooks/hooks.json",
|
|
444
|
+
path: hooksPath,
|
|
445
|
+
relativePath: "hooks/hooks.json",
|
|
446
|
+
message: "Codex native hooks are archived for manual review because they can execute commands"
|
|
447
|
+
});
|
|
448
|
+
const skills = [...codexSkills, ...personalAgentSkills].toSorted((a, b) => a.source.localeCompare(b.source));
|
|
449
|
+
const high = Boolean(codexSkills.length || plugins.length || archivePaths.length);
|
|
450
|
+
const medium = personalAgentSkills.length > 0;
|
|
451
|
+
return {
|
|
452
|
+
root: codexHome,
|
|
453
|
+
confidence: high ? "high" : medium ? "medium" : "low",
|
|
454
|
+
codexHome,
|
|
455
|
+
...await isDirectory(codexSkillsDir) ? { codexSkillsDir } : {},
|
|
456
|
+
...await isDirectory(agentsSkillsDir) ? { personalAgentsSkillsDir: agentsSkillsDir } : {},
|
|
457
|
+
...await exists(configPath) ? { configPath } : {},
|
|
458
|
+
...await exists(hooksPath) ? { hooksPath } : {},
|
|
459
|
+
skills,
|
|
460
|
+
plugins,
|
|
461
|
+
...sourcePluginDiscovery.error ? { pluginDiscoveryError: sourcePluginDiscovery.error } : {},
|
|
462
|
+
archivePaths
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function hasCodexSource(source) {
|
|
466
|
+
return source.confidence !== "low";
|
|
467
|
+
}
|
|
468
|
+
function sanitizePluginName(value) {
|
|
469
|
+
return value.trim().toLowerCase().replaceAll(/\s+/gu, "-");
|
|
470
|
+
}
|
|
471
|
+
//#endregion
|
|
472
|
+
//#region extensions/codex/src/migration/targets.ts
|
|
473
|
+
function resolveCodexMigrationTargets(ctx) {
|
|
474
|
+
const cfg = ctx.config;
|
|
475
|
+
const agentId = resolveDefaultAgentId(cfg);
|
|
476
|
+
const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
|
|
477
|
+
const configuredAgentDir = resolveAgentConfig(cfg, agentId)?.agentDir?.trim();
|
|
478
|
+
return {
|
|
479
|
+
workspaceDir,
|
|
480
|
+
agentDir: ctx.runtime?.agent?.resolveAgentDir(cfg, agentId) ?? (configuredAgentDir ? resolveHomePath(configuredAgentDir) : void 0) ?? path.join(ctx.stateDir, "agents", agentId, "agent")
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
//#endregion
|
|
484
|
+
//#region extensions/codex/src/migration/plan.ts
|
|
485
|
+
const CODEX_PLUGIN_CONFIG_ITEM_ID = "config:codex-plugins";
|
|
486
|
+
const CODEX_PLUGIN_CONFIG_PATH = [
|
|
487
|
+
"plugins",
|
|
488
|
+
"entries",
|
|
489
|
+
"codex"
|
|
490
|
+
];
|
|
491
|
+
const CODEX_PLUGIN_ENABLED_PATH = [
|
|
492
|
+
"plugins",
|
|
493
|
+
"entries",
|
|
494
|
+
"codex",
|
|
495
|
+
"enabled"
|
|
496
|
+
];
|
|
497
|
+
const CODEX_PLUGIN_NATIVE_CONFIG_PATH = [
|
|
498
|
+
"plugins",
|
|
499
|
+
"entries",
|
|
500
|
+
"codex",
|
|
501
|
+
"config",
|
|
502
|
+
"codexPlugins"
|
|
503
|
+
];
|
|
504
|
+
const MIGRATION_REASON_PLUGIN_EXISTS = "plugin exists";
|
|
505
|
+
const CODEX_PLUGIN_SOURCE_APP_VERIFICATION_UNVERIFIED = "not_run";
|
|
506
|
+
function uniqueSkillName(skill, counts) {
|
|
507
|
+
const base = sanitizeName(skill.name) || "codex-skill";
|
|
508
|
+
if ((counts.get(base) ?? 0) <= 1) return base;
|
|
509
|
+
return sanitizeName([
|
|
510
|
+
"codex",
|
|
511
|
+
sanitizeName(path.basename(path.dirname(skill.source))),
|
|
512
|
+
base
|
|
513
|
+
].filter(Boolean).join("-")) || base;
|
|
514
|
+
}
|
|
515
|
+
async function buildSkillItems(params) {
|
|
516
|
+
const baseCounts = /* @__PURE__ */ new Map();
|
|
517
|
+
for (const skill of params.skills) {
|
|
518
|
+
const base = sanitizeName(skill.name) || "codex-skill";
|
|
519
|
+
baseCounts.set(base, (baseCounts.get(base) ?? 0) + 1);
|
|
520
|
+
}
|
|
521
|
+
const resolvedCounts = /* @__PURE__ */ new Map();
|
|
522
|
+
const planned = params.skills.map((skill) => {
|
|
523
|
+
const name = uniqueSkillName(skill, baseCounts);
|
|
524
|
+
resolvedCounts.set(name, (resolvedCounts.get(name) ?? 0) + 1);
|
|
525
|
+
return {
|
|
526
|
+
skill,
|
|
527
|
+
name,
|
|
528
|
+
target: path.join(params.workspaceDir, "skills", name)
|
|
529
|
+
};
|
|
530
|
+
});
|
|
531
|
+
const items = [];
|
|
532
|
+
for (const item of planned) {
|
|
533
|
+
const collides = (resolvedCounts.get(item.name) ?? 0) > 1;
|
|
534
|
+
const targetExists = await exists(item.target);
|
|
535
|
+
items.push(createMigrationItem({
|
|
536
|
+
id: `skill:${item.name}`,
|
|
537
|
+
kind: "skill",
|
|
538
|
+
action: "copy",
|
|
539
|
+
source: item.skill.source,
|
|
540
|
+
target: item.target,
|
|
541
|
+
status: collides ? "conflict" : targetExists && !params.overwrite ? "conflict" : "planned",
|
|
542
|
+
reason: collides ? `multiple Codex skills normalize to "${item.name}"` : targetExists && !params.overwrite ? MIGRATION_REASON_TARGET_EXISTS : void 0,
|
|
543
|
+
message: `Copy ${item.skill.sourceLabel} into this AutoBot agent workspace.`,
|
|
544
|
+
details: {
|
|
545
|
+
skillName: item.name,
|
|
546
|
+
sourceLabel: item.skill.sourceLabel
|
|
547
|
+
}
|
|
548
|
+
}));
|
|
549
|
+
}
|
|
550
|
+
return items;
|
|
551
|
+
}
|
|
552
|
+
function uniquePluginConfigKey(plugin, counts, usedCounts) {
|
|
553
|
+
const base = sanitizeName(plugin.pluginName ?? plugin.name) || "codex-plugin";
|
|
554
|
+
if ((counts.get(base) ?? 0) <= 1) return base;
|
|
555
|
+
const next = (usedCounts.get(base) ?? 0) + 1;
|
|
556
|
+
usedCounts.set(base, next);
|
|
557
|
+
return sanitizeName(`${base}-${next}`) || base;
|
|
558
|
+
}
|
|
559
|
+
function readExistingCodexPluginEntries(config) {
|
|
560
|
+
const entries = readMigrationConfigPath(config, [...CODEX_PLUGIN_NATIVE_CONFIG_PATH, "plugins"]);
|
|
561
|
+
return isRecord(entries) ? entries : {};
|
|
562
|
+
}
|
|
563
|
+
function hasExistingCodexPluginEntry(existingEntries, configKey, pluginName) {
|
|
564
|
+
if (existingEntries[configKey] !== void 0) return true;
|
|
565
|
+
return Object.values(existingEntries).some((entry) => {
|
|
566
|
+
if (!isRecord(entry)) return false;
|
|
567
|
+
return entry.pluginName === pluginName;
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
function buildPluginItems(ctx, plugins) {
|
|
571
|
+
const baseCounts = /* @__PURE__ */ new Map();
|
|
572
|
+
for (const plugin of plugins.filter((entry) => entry.migratable)) {
|
|
573
|
+
const base = sanitizeName(plugin.pluginName ?? plugin.name) || "codex-plugin";
|
|
574
|
+
baseCounts.set(base, (baseCounts.get(base) ?? 0) + 1);
|
|
575
|
+
}
|
|
576
|
+
const existingPluginEntries = readExistingCodexPluginEntries(ctx.config);
|
|
577
|
+
const usedCounts = /* @__PURE__ */ new Map();
|
|
578
|
+
let manualIndex = 0;
|
|
579
|
+
const items = [];
|
|
580
|
+
for (const plugin of plugins) {
|
|
581
|
+
if (plugin.migratable && plugin.marketplaceName === "openai-curated" && plugin.pluginName) {
|
|
582
|
+
const configKey = uniquePluginConfigKey(plugin, baseCounts, usedCounts);
|
|
583
|
+
const conflict = !ctx.overwrite && hasExistingCodexPluginEntry(existingPluginEntries, configKey, plugin.pluginName);
|
|
584
|
+
items.push(createMigrationItem({
|
|
585
|
+
id: `plugin:${configKey}`,
|
|
586
|
+
kind: "plugin",
|
|
587
|
+
action: "install",
|
|
588
|
+
status: conflict ? "conflict" : "planned",
|
|
589
|
+
reason: conflict ? MIGRATION_REASON_PLUGIN_EXISTS : void 0,
|
|
590
|
+
source: plugin.source,
|
|
591
|
+
target: `plugins.entries.codex.config.codexPlugins.plugins.${configKey}`,
|
|
592
|
+
message: `Install Codex plugin "${plugin.pluginName}" in the AutoBot-managed Codex app-server runtime.`,
|
|
593
|
+
details: {
|
|
594
|
+
configKey,
|
|
595
|
+
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
596
|
+
pluginName: plugin.pluginName,
|
|
597
|
+
sourceInstalled: plugin.installed === true,
|
|
598
|
+
sourceEnabled: plugin.enabled === true,
|
|
599
|
+
...plugin.apps && plugin.apps.length > 0 && !shouldVerifyPluginApps(ctx) ? { sourceAppVerification: CODEX_PLUGIN_SOURCE_APP_VERIFICATION_UNVERIFIED } : {}
|
|
600
|
+
}
|
|
601
|
+
}));
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
manualIndex += 1;
|
|
605
|
+
if (plugin.migrationBlock && plugin.pluginName) {
|
|
606
|
+
const details = {
|
|
607
|
+
pluginName: plugin.pluginName,
|
|
608
|
+
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
609
|
+
...plugin.migrationBlock.apps ? { apps: plugin.migrationBlock.apps } : {},
|
|
610
|
+
...plugin.migrationBlock.error ? { error: plugin.migrationBlock.error } : {}
|
|
611
|
+
};
|
|
612
|
+
items.push(createMigrationItem({
|
|
613
|
+
id: `plugin:${sanitizeName(plugin.name) || sanitizeName(path.basename(plugin.source))}:${manualIndex}`,
|
|
614
|
+
kind: "manual",
|
|
615
|
+
action: "manual",
|
|
616
|
+
source: plugin.source,
|
|
617
|
+
status: "skipped",
|
|
618
|
+
reason: plugin.migrationBlock.code,
|
|
619
|
+
message: plugin.message ?? `Codex native plugin "${plugin.name}" was found but not activated automatically.`,
|
|
620
|
+
details: { ...details }
|
|
621
|
+
}));
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
items.push(createMigrationManualItem({
|
|
625
|
+
id: `plugin:${sanitizeName(plugin.name) || sanitizeName(path.basename(plugin.source))}:${manualIndex}`,
|
|
626
|
+
source: plugin.source,
|
|
627
|
+
message: plugin.message ?? `Codex native plugin "${plugin.name}" was found but not activated automatically.`,
|
|
628
|
+
recommendation: "Review the plugin bundle first, then install trusted compatible plugins with autobot plugins install <path>."
|
|
629
|
+
}));
|
|
630
|
+
}
|
|
631
|
+
return items;
|
|
632
|
+
}
|
|
633
|
+
function shouldVerifyPluginApps(ctx) {
|
|
634
|
+
return ctx.providerOptions?.verifyPluginApps === true;
|
|
635
|
+
}
|
|
636
|
+
function readCodexPluginMigrationConfigEntry(item, enabled) {
|
|
637
|
+
const configKey = item.details?.configKey;
|
|
638
|
+
const marketplaceName = item.details?.marketplaceName;
|
|
639
|
+
const pluginName = item.details?.pluginName;
|
|
640
|
+
if (item.kind !== "plugin" || item.action !== "install" || typeof configKey !== "string" || marketplaceName !== "openai-curated" || typeof pluginName !== "string") return;
|
|
641
|
+
return {
|
|
642
|
+
configKey,
|
|
643
|
+
pluginName,
|
|
644
|
+
enabled
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
function readExistingAllowDestructiveActions(config) {
|
|
648
|
+
const value = readMigrationConfigPath(config, [...CODEX_PLUGIN_NATIVE_CONFIG_PATH, "allow_destructive_actions"]);
|
|
649
|
+
return typeof value === "boolean" ? value : void 0;
|
|
650
|
+
}
|
|
651
|
+
function isRecord(value) {
|
|
652
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
653
|
+
}
|
|
654
|
+
function buildCodexPluginsConfigValue(entries, params = {}) {
|
|
655
|
+
const plugins = Object.fromEntries(entries.toSorted((a, b) => a.configKey.localeCompare(b.configKey)).map((entry) => [entry.configKey, {
|
|
656
|
+
enabled: entry.enabled,
|
|
657
|
+
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
658
|
+
pluginName: entry.pluginName
|
|
659
|
+
}]));
|
|
660
|
+
return {
|
|
661
|
+
enabled: true,
|
|
662
|
+
config: { codexPlugins: {
|
|
663
|
+
enabled: true,
|
|
664
|
+
allow_destructive_actions: params.config === void 0 ? true : readExistingAllowDestructiveActions(params.config) ?? true,
|
|
665
|
+
plugins
|
|
666
|
+
} }
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
function hasCodexPluginConfigConflict(config, value) {
|
|
670
|
+
const enabled = readMigrationConfigPath(config, CODEX_PLUGIN_ENABLED_PATH);
|
|
671
|
+
if (enabled !== void 0 && enabled !== true) return true;
|
|
672
|
+
const nativeConfig = value.config?.codexPlugins;
|
|
673
|
+
if (!isRecord(nativeConfig)) return hasMigrationConfigPatchConflict(config, CODEX_PLUGIN_NATIVE_CONFIG_PATH, nativeConfig);
|
|
674
|
+
const existingNativeConfig = readMigrationConfigPath(config, CODEX_PLUGIN_NATIVE_CONFIG_PATH);
|
|
675
|
+
if (existingNativeConfig === void 0) return false;
|
|
676
|
+
if (!isRecord(existingNativeConfig)) return true;
|
|
677
|
+
if (existingNativeConfig.enabled !== void 0 && existingNativeConfig.enabled !== true) return true;
|
|
678
|
+
const allowDestructiveActions = nativeConfig.allow_destructive_actions;
|
|
679
|
+
if (existingNativeConfig.allow_destructive_actions !== void 0 && existingNativeConfig.allow_destructive_actions !== allowDestructiveActions) return true;
|
|
680
|
+
const plugins = nativeConfig.plugins;
|
|
681
|
+
if (!isRecord(plugins)) return false;
|
|
682
|
+
return Object.entries(plugins).some(([configKey, plugin]) => {
|
|
683
|
+
if (!isRecord(plugin)) return existingNativeConfig[configKey] !== void 0;
|
|
684
|
+
return hasExistingCodexPluginEntry(readExistingCodexPluginEntries(config), configKey, typeof plugin.pluginName === "string" ? plugin.pluginName : configKey);
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
function buildPluginConfigItem(ctx, pluginItems) {
|
|
688
|
+
const entries = pluginItems.filter((item) => item.status === "planned").map((item) => readCodexPluginMigrationConfigEntry(item, true)).filter((entry) => entry !== void 0);
|
|
689
|
+
if (entries.length === 0) return;
|
|
690
|
+
const value = buildCodexPluginsConfigValue(entries, { config: ctx.config });
|
|
691
|
+
const conflict = !ctx.overwrite && hasCodexPluginConfigConflict(ctx.config, value);
|
|
692
|
+
return createMigrationItem({
|
|
693
|
+
id: CODEX_PLUGIN_CONFIG_ITEM_ID,
|
|
694
|
+
kind: "config",
|
|
695
|
+
action: "merge",
|
|
696
|
+
target: "plugins.entries.codex.config.codexPlugins",
|
|
697
|
+
status: conflict ? "conflict" : "planned",
|
|
698
|
+
reason: conflict ? MIGRATION_REASON_TARGET_EXISTS : void 0,
|
|
699
|
+
message: "Enable AutoBot's Codex plugin integration and record migrated source-installed curated plugins.",
|
|
700
|
+
details: {
|
|
701
|
+
path: [...CODEX_PLUGIN_CONFIG_PATH],
|
|
702
|
+
value
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
async function buildCodexMigrationPlan(ctx) {
|
|
707
|
+
const targets = resolveCodexMigrationTargets(ctx);
|
|
708
|
+
const source = await discoverCodexSource({
|
|
709
|
+
input: ctx.source,
|
|
710
|
+
evaluatePluginMigrationEligibility: true,
|
|
711
|
+
verifyPluginApps: shouldVerifyPluginApps(ctx)
|
|
712
|
+
});
|
|
713
|
+
if (!hasCodexSource(source)) throw new Error(`Codex state was not found at ${source.root}. Pass --from <path> if it lives elsewhere.`);
|
|
714
|
+
const items = [];
|
|
715
|
+
items.push(...await buildSkillItems({
|
|
716
|
+
skills: source.skills,
|
|
717
|
+
workspaceDir: targets.workspaceDir,
|
|
718
|
+
overwrite: ctx.overwrite
|
|
719
|
+
}));
|
|
720
|
+
const pluginItems = buildPluginItems(ctx, source.plugins);
|
|
721
|
+
items.push(...pluginItems);
|
|
722
|
+
const pluginConfigItem = buildPluginConfigItem(ctx, pluginItems);
|
|
723
|
+
if (pluginConfigItem) items.push(pluginConfigItem);
|
|
724
|
+
for (const archivePath of source.archivePaths) items.push(createMigrationItem({
|
|
725
|
+
id: archivePath.id,
|
|
726
|
+
kind: "archive",
|
|
727
|
+
action: "archive",
|
|
728
|
+
source: archivePath.path,
|
|
729
|
+
message: archivePath.message ?? "Archived in the migration report for manual review; not imported into live config.",
|
|
730
|
+
details: { archiveRelativePath: archivePath.relativePath }
|
|
731
|
+
}));
|
|
732
|
+
const warnings = [
|
|
733
|
+
...items.some((item) => item.status === "conflict") ? ["Conflicts were found. Re-run with --overwrite to replace conflicting migration targets after item-level backups."] : [],
|
|
734
|
+
...source.pluginDiscoveryError ? [`Codex app-server plugin inventory discovery failed: ${source.pluginDiscoveryError}. Cached plugin bundles, if any, are advisory only.`] : [],
|
|
735
|
+
...source.plugins.some((plugin) => plugin.migrationBlock?.code === "codex_subscription_required") ? [codexPluginMigrationSubscriptionWarning()] : []
|
|
736
|
+
];
|
|
737
|
+
return {
|
|
738
|
+
providerId: "codex",
|
|
739
|
+
source: source.root,
|
|
740
|
+
target: targets.workspaceDir,
|
|
741
|
+
summary: summarizeMigrationItems(items),
|
|
742
|
+
items,
|
|
743
|
+
warnings,
|
|
744
|
+
nextSteps: ["Run autobot doctor after applying the migration.", "Review skipped or auth-required Codex plugin/config/hook items before exposing them in AutoBot sessions."],
|
|
745
|
+
metadata: {
|
|
746
|
+
agentDir: targets.agentDir,
|
|
747
|
+
codexHome: source.codexHome,
|
|
748
|
+
codexSkillsDir: source.codexSkillsDir,
|
|
749
|
+
personalAgentsSkillsDir: source.personalAgentsSkillsDir
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
//#endregion
|
|
754
|
+
//#region extensions/codex/src/migration/apply.ts
|
|
755
|
+
const CODEX_PLUGIN_AUTH_REQUIRED_REASON = "auth_required";
|
|
756
|
+
const CODEX_PLUGIN_NOT_SELECTED_REASON = "not selected for migration";
|
|
757
|
+
const CODEX_CONFIG_PATCH_MODE_RETURN = "return";
|
|
758
|
+
const CODEX_PLUGIN_LOAD_WARNING = "Some Codex plugins could not be migrated. Run `autobot migrate codex` after onboarding.";
|
|
759
|
+
const TARGET_CODEX_MARKETPLACE_DISCOVERY_POLL_MS = 250;
|
|
760
|
+
const TARGET_CODEX_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 3e4;
|
|
761
|
+
const TARGET_CODEX_MARKETPLACE_DISCOVERY_TIMEOUT_ENV = "AUTOBOT_CODEX_MIGRATION_PLUGIN_LIST_TIMEOUT_MS";
|
|
762
|
+
var CodexPluginConfigConflictError = class extends Error {
|
|
763
|
+
constructor(reason) {
|
|
764
|
+
super(reason);
|
|
765
|
+
this.reason = reason;
|
|
766
|
+
this.name = "CodexPluginConfigConflictError";
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
function shouldReturnCodexPluginConfigPatch(ctx) {
|
|
770
|
+
return ctx.providerOptions?.configPatchMode === CODEX_CONFIG_PATCH_MODE_RETURN;
|
|
771
|
+
}
|
|
772
|
+
function prepareTargetCodexAppServer(ctx) {
|
|
773
|
+
const appServer = resolveTargetCodexAppServer(ctx);
|
|
774
|
+
const targets = resolveCodexMigrationTargets(ctx);
|
|
775
|
+
let warmedClient;
|
|
776
|
+
const ready = getSharedCodexAppServerClient({
|
|
777
|
+
startOptions: appServer.start,
|
|
778
|
+
timeoutMs: 6e4,
|
|
779
|
+
agentDir: targets.agentDir,
|
|
780
|
+
config: ctx.config
|
|
781
|
+
}).then((client) => {
|
|
782
|
+
warmedClient = client;
|
|
783
|
+
}, () => void 0);
|
|
784
|
+
return { async dispose() {
|
|
785
|
+
await ready;
|
|
786
|
+
await clearSharedCodexAppServerClientIfCurrentAndWait(warmedClient, {
|
|
787
|
+
exitTimeoutMs: 2e3,
|
|
788
|
+
forceKillDelayMs: 250
|
|
789
|
+
});
|
|
790
|
+
} };
|
|
791
|
+
}
|
|
792
|
+
async function applyCodexMigrationPlan(params) {
|
|
793
|
+
const plan = params.plan ?? await buildCodexMigrationPlan(params.ctx);
|
|
794
|
+
const reportDir = params.ctx.reportDir ?? path.join(params.ctx.stateDir, "migration", "codex");
|
|
795
|
+
const items = [];
|
|
796
|
+
const runtime = withCachedMigrationConfigRuntime(params.ctx.runtime ?? params.runtime, params.ctx.config);
|
|
797
|
+
const applyCtx = {
|
|
798
|
+
...params.ctx,
|
|
799
|
+
runtime
|
|
800
|
+
};
|
|
801
|
+
for (const item of plan.items) {
|
|
802
|
+
if (item.status !== "planned") {
|
|
803
|
+
items.push(item);
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
if (item.id === "config:codex-plugins") items.push(await applyCodexPluginConfigItem(applyCtx, item, items));
|
|
807
|
+
else if (item.kind === "plugin" && item.action === "install") items.push(await applyCodexPluginInstallItem(applyCtx, item));
|
|
808
|
+
else if (item.kind === "manual") items.push(applyMigrationManualItem(item));
|
|
809
|
+
else if (item.action === "archive") items.push(await archiveMigrationItem(item, reportDir));
|
|
810
|
+
else items.push(await copyMigrationFileItem(item, reportDir, { overwrite: params.ctx.overwrite }));
|
|
811
|
+
}
|
|
812
|
+
const result = {
|
|
813
|
+
...plan,
|
|
814
|
+
items,
|
|
815
|
+
summary: summarizeMigrationItems(items),
|
|
816
|
+
backupPath: params.ctx.backupPath,
|
|
817
|
+
reportDir
|
|
818
|
+
};
|
|
819
|
+
if (items.some(isCodexPluginLoadWarningItem)) {
|
|
820
|
+
result.warnings = [...new Set([...result.warnings ?? [], CODEX_PLUGIN_LOAD_WARNING])];
|
|
821
|
+
result.nextSteps = [...new Set([CODEX_PLUGIN_LOAD_WARNING, ...result.nextSteps ?? []])];
|
|
822
|
+
}
|
|
823
|
+
await writeMigrationReport(result, { title: "Codex Migration Report" });
|
|
824
|
+
return result;
|
|
825
|
+
}
|
|
826
|
+
async function applyCodexPluginInstallItem(ctx, item) {
|
|
827
|
+
const policy = readCodexPluginPolicy(item);
|
|
828
|
+
if (!policy) return {
|
|
829
|
+
...markMigrationItemError(item, "invalid Codex plugin migration item"),
|
|
830
|
+
details: {
|
|
831
|
+
...item.details,
|
|
832
|
+
code: "invalid_plugin_item"
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
try {
|
|
836
|
+
const appCacheKey = await buildTargetCodexPluginAppCacheKey(ctx);
|
|
837
|
+
const appServer = resolveTargetCodexAppServer(ctx);
|
|
838
|
+
const result = await ensureCodexPluginActivation({
|
|
839
|
+
identity: policy,
|
|
840
|
+
installEvenIfActive: true,
|
|
841
|
+
request: async (method, requestParams) => await requestTargetCodexAppServerJson({
|
|
842
|
+
method,
|
|
843
|
+
requestParams,
|
|
844
|
+
timeoutMs: 6e4,
|
|
845
|
+
startOptions: appServer.start,
|
|
846
|
+
agentDir: resolveCodexMigrationTargets(ctx).agentDir,
|
|
847
|
+
config: ctx.config,
|
|
848
|
+
isolated: false
|
|
849
|
+
}),
|
|
850
|
+
appCache: defaultCodexAppInventoryCache,
|
|
851
|
+
appCacheKey
|
|
852
|
+
});
|
|
853
|
+
const baseDetails = {
|
|
854
|
+
...item.details,
|
|
855
|
+
code: result.reason,
|
|
856
|
+
activationReason: result.reason,
|
|
857
|
+
...codexPluginActivationReportState(result),
|
|
858
|
+
installAttempted: result.installAttempted,
|
|
859
|
+
diagnostics: result.diagnostics.map((diagnostic) => diagnostic.message)
|
|
860
|
+
};
|
|
861
|
+
if (result.ok) return {
|
|
862
|
+
...item,
|
|
863
|
+
status: "migrated",
|
|
864
|
+
...result.reason === "already_active" ? { reason: "already active" } : {},
|
|
865
|
+
details: baseDetails
|
|
866
|
+
};
|
|
867
|
+
if (result.reason === CODEX_PLUGIN_AUTH_REQUIRED_REASON) return {
|
|
868
|
+
...item,
|
|
869
|
+
status: "skipped",
|
|
870
|
+
reason: CODEX_PLUGIN_AUTH_REQUIRED_REASON,
|
|
871
|
+
details: {
|
|
872
|
+
...baseDetails,
|
|
873
|
+
appsNeedingAuth: sanitizeAppsNeedingAuth(result.installResponse?.appsNeedingAuth ?? [])
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
if (result.reason === "plugin_missing" || result.reason === "marketplace_missing") return {
|
|
877
|
+
...item,
|
|
878
|
+
status: "warning",
|
|
879
|
+
reason: result.reason,
|
|
880
|
+
message: `Codex plugin "${policy.pluginName}" could not be migrated automatically`,
|
|
881
|
+
details: {
|
|
882
|
+
...baseDetails,
|
|
883
|
+
warningReason: CODEX_PLUGIN_LOAD_WARNING
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
return {
|
|
887
|
+
...item,
|
|
888
|
+
status: "error",
|
|
889
|
+
reason: result.reason,
|
|
890
|
+
details: baseDetails
|
|
891
|
+
};
|
|
892
|
+
} catch (error) {
|
|
893
|
+
if (isCodexPluginInventoryLoadError(error)) return {
|
|
894
|
+
...item,
|
|
895
|
+
status: "warning",
|
|
896
|
+
reason: "plugin_inventory_unavailable",
|
|
897
|
+
message: `Codex plugin "${policy.pluginName}" could not be migrated automatically`,
|
|
898
|
+
details: {
|
|
899
|
+
...item.details,
|
|
900
|
+
code: "plugin_inventory_unavailable",
|
|
901
|
+
warningReason: CODEX_PLUGIN_LOAD_WARNING,
|
|
902
|
+
diagnostic: formatCodexMigrationError(error)
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
return {
|
|
906
|
+
...item,
|
|
907
|
+
status: "error",
|
|
908
|
+
reason: formatCodexMigrationError(error),
|
|
909
|
+
details: {
|
|
910
|
+
...item.details,
|
|
911
|
+
code: "plugin_install_failed"
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function isCodexPluginInventoryLoadError(error) {
|
|
917
|
+
return formatCodexMigrationError(error).includes("codex app-server plugin/list timed out");
|
|
918
|
+
}
|
|
919
|
+
function formatCodexMigrationError(error) {
|
|
920
|
+
return error instanceof Error ? error.message : String(error);
|
|
921
|
+
}
|
|
922
|
+
function resolveTargetCodexAppServer(ctx) {
|
|
923
|
+
return resolveCodexAppServerRuntimeOptions({ pluginConfig: readCodexPluginConfig(ctx.config) });
|
|
924
|
+
}
|
|
925
|
+
async function requestTargetCodexAppServerJson(params) {
|
|
926
|
+
if (params.method !== "plugin/list") return await requestCodexAppServerJson(params);
|
|
927
|
+
const deadline = Date.now() + params.timeoutMs;
|
|
928
|
+
const discoveryTimeoutMs = targetCodexMarketplaceDiscoveryTimeoutMs();
|
|
929
|
+
const discoveryDeadline = Math.min(deadline, Date.now() + discoveryTimeoutMs);
|
|
930
|
+
let lastResponse;
|
|
931
|
+
let attempt = 0;
|
|
932
|
+
do {
|
|
933
|
+
attempt += 1;
|
|
934
|
+
const remainingMs = Math.max(1, discoveryDeadline - Date.now());
|
|
935
|
+
lastResponse = await requestCodexAppServerJson({
|
|
936
|
+
...params,
|
|
937
|
+
timeoutMs: remainingMs
|
|
938
|
+
});
|
|
939
|
+
if (hasOpenAiCuratedMarketplace(lastResponse)) return lastResponse;
|
|
940
|
+
if (Date.now() >= discoveryDeadline) return lastResponse;
|
|
941
|
+
await sleep(Math.min(TARGET_CODEX_MARKETPLACE_DISCOVERY_POLL_MS, discoveryDeadline - Date.now()));
|
|
942
|
+
} while (Date.now() < discoveryDeadline);
|
|
943
|
+
return lastResponse;
|
|
944
|
+
}
|
|
945
|
+
function hasOpenAiCuratedMarketplace(response) {
|
|
946
|
+
if (!response || typeof response !== "object" || !("marketplaces" in response)) return false;
|
|
947
|
+
const marketplaces = response.marketplaces;
|
|
948
|
+
return Array.isArray(marketplaces) && marketplaces.some((marketplace) => marketplace && typeof marketplace === "object" && marketplace.name === "openai-curated");
|
|
949
|
+
}
|
|
950
|
+
function targetCodexMarketplaceDiscoveryTimeoutMs() {
|
|
951
|
+
const configured = Number(process.env[TARGET_CODEX_MARKETPLACE_DISCOVERY_TIMEOUT_ENV]);
|
|
952
|
+
if (Number.isFinite(configured) && configured >= 0) return configured;
|
|
953
|
+
return TARGET_CODEX_MARKETPLACE_DISCOVERY_TIMEOUT_MS;
|
|
954
|
+
}
|
|
955
|
+
function isCodexPluginLoadWarningItem(item) {
|
|
956
|
+
return item.kind === "plugin" && item.action === "install" && item.status === "warning" && item.details?.warningReason === CODEX_PLUGIN_LOAD_WARNING;
|
|
957
|
+
}
|
|
958
|
+
async function sleep(ms) {
|
|
959
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
960
|
+
}
|
|
961
|
+
async function buildTargetCodexPluginAppCacheKey(ctx) {
|
|
962
|
+
const targets = resolveCodexMigrationTargets(ctx);
|
|
963
|
+
const appServer = resolveTargetCodexAppServer(ctx);
|
|
964
|
+
const authProfileId = resolveCodexAppServerAuthProfileIdForAgent({
|
|
965
|
+
agentDir: targets.agentDir,
|
|
966
|
+
config: ctx.config
|
|
967
|
+
});
|
|
968
|
+
const accountId = await resolveCodexAppServerAuthAccountCacheKey({
|
|
969
|
+
authProfileId,
|
|
970
|
+
agentDir: targets.agentDir,
|
|
971
|
+
config: ctx.config
|
|
972
|
+
});
|
|
973
|
+
const envApiKeyFingerprint = authProfileId ? void 0 : resolveCodexAppServerEnvApiKeyCacheKey({ startOptions: appServer.start });
|
|
974
|
+
return buildCodexPluginAppCacheKey({
|
|
975
|
+
appServer,
|
|
976
|
+
agentDir: targets.agentDir,
|
|
977
|
+
authProfileId,
|
|
978
|
+
accountId,
|
|
979
|
+
envApiKeyFingerprint
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
async function applyCodexPluginConfigItem(ctx, item, appliedItems) {
|
|
983
|
+
const entries = appliedItems.map(readAppliedPluginConfigEntry).filter((entry) => entry !== void 0);
|
|
984
|
+
if (entries.length === 0) return markMigrationItemSkipped(item, "no selected Codex plugins");
|
|
985
|
+
const returnPatch = shouldReturnCodexPluginConfigPatch(ctx);
|
|
986
|
+
const configApi = ctx.runtime?.config;
|
|
987
|
+
const currentConfig = returnPatch ? ctx.config : configApi?.current?.();
|
|
988
|
+
if (!currentConfig) return markMigrationItemError(item, "config runtime unavailable");
|
|
989
|
+
const value = buildCodexPluginsConfigValue(entries, { config: currentConfig });
|
|
990
|
+
if (!ctx.overwrite && hasCodexPluginConfigConflict(currentConfig, value)) return markMigrationItemConflict(item, MIGRATION_REASON_TARGET_EXISTS);
|
|
991
|
+
const migratedItem = {
|
|
992
|
+
...item,
|
|
993
|
+
status: "migrated",
|
|
994
|
+
details: {
|
|
995
|
+
...item.details,
|
|
996
|
+
path: [...CODEX_PLUGIN_CONFIG_PATH],
|
|
997
|
+
value
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
if (returnPatch) return migratedItem;
|
|
1001
|
+
if (!configApi?.mutateConfigFile) return markMigrationItemError(item, "config runtime unavailable");
|
|
1002
|
+
try {
|
|
1003
|
+
await configApi.mutateConfigFile({
|
|
1004
|
+
base: "runtime",
|
|
1005
|
+
afterWrite: { mode: "auto" },
|
|
1006
|
+
mutate(draft) {
|
|
1007
|
+
if (!ctx.overwrite && hasCodexPluginConfigConflict(draft, value)) throw new CodexPluginConfigConflictError(MIGRATION_REASON_TARGET_EXISTS);
|
|
1008
|
+
writeMigrationConfigPath(draft, CODEX_PLUGIN_CONFIG_PATH, value);
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
return migratedItem;
|
|
1012
|
+
} catch (error) {
|
|
1013
|
+
if (error instanceof CodexPluginConfigConflictError) return markMigrationItemConflict(item, error.reason);
|
|
1014
|
+
return markMigrationItemError(item, error instanceof Error ? error.message : String(error));
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
function readAppliedPluginConfigEntry(item) {
|
|
1018
|
+
if (item.status === "migrated") return readCodexPluginMigrationConfigEntry(item, true);
|
|
1019
|
+
if (item.status === "skipped" && item.reason !== CODEX_PLUGIN_NOT_SELECTED_REASON && item.reason === CODEX_PLUGIN_AUTH_REQUIRED_REASON) return readCodexPluginMigrationConfigEntry(item, false);
|
|
1020
|
+
}
|
|
1021
|
+
function readCodexPluginPolicy(item) {
|
|
1022
|
+
const configKey = item.details?.configKey;
|
|
1023
|
+
const marketplaceName = item.details?.marketplaceName;
|
|
1024
|
+
const pluginName = item.details?.pluginName;
|
|
1025
|
+
if (typeof configKey !== "string" || marketplaceName !== "openai-curated" || typeof pluginName !== "string") return;
|
|
1026
|
+
return {
|
|
1027
|
+
configKey,
|
|
1028
|
+
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
1029
|
+
pluginName,
|
|
1030
|
+
enabled: true,
|
|
1031
|
+
allowDestructiveActions: true
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
function codexPluginActivationReportState(result) {
|
|
1035
|
+
switch (result.reason) {
|
|
1036
|
+
case "already_active":
|
|
1037
|
+
case "installed": return {
|
|
1038
|
+
installed: true,
|
|
1039
|
+
enabled: true
|
|
1040
|
+
};
|
|
1041
|
+
case "auth_required": return {
|
|
1042
|
+
installed: true,
|
|
1043
|
+
enabled: false
|
|
1044
|
+
};
|
|
1045
|
+
case "disabled":
|
|
1046
|
+
case "marketplace_missing":
|
|
1047
|
+
case "plugin_missing": return {
|
|
1048
|
+
installed: false,
|
|
1049
|
+
enabled: false
|
|
1050
|
+
};
|
|
1051
|
+
case "refresh_failed": return {
|
|
1052
|
+
installed: true,
|
|
1053
|
+
enabled: false
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
return result.reason;
|
|
1057
|
+
}
|
|
1058
|
+
function sanitizeAppsNeedingAuth(apps) {
|
|
1059
|
+
return apps.map((app) => ({
|
|
1060
|
+
id: app.id,
|
|
1061
|
+
name: app.name,
|
|
1062
|
+
needsAuth: app.needsAuth
|
|
1063
|
+
}));
|
|
1064
|
+
}
|
|
1065
|
+
//#endregion
|
|
1066
|
+
//#region extensions/codex/src/migration/provider.ts
|
|
1067
|
+
function buildCodexMigrationProvider(params = {}) {
|
|
1068
|
+
return {
|
|
1069
|
+
id: "codex",
|
|
1070
|
+
label: "Codex",
|
|
1071
|
+
description: "Inventory and promote Codex CLI skills while keeping Codex native plugins and hooks explicit.",
|
|
1072
|
+
async detect(ctx) {
|
|
1073
|
+
const source = await discoverCodexSource({ input: ctx.source });
|
|
1074
|
+
const found = hasCodexSource(source);
|
|
1075
|
+
return {
|
|
1076
|
+
found,
|
|
1077
|
+
source: source.root,
|
|
1078
|
+
label: "Codex",
|
|
1079
|
+
confidence: found ? source.confidence : "low",
|
|
1080
|
+
message: found ? "Codex state found." : "Codex state not found."
|
|
1081
|
+
};
|
|
1082
|
+
},
|
|
1083
|
+
plan: buildCodexMigrationPlan,
|
|
1084
|
+
prepareApply(ctx) {
|
|
1085
|
+
return prepareTargetCodexAppServer(ctx);
|
|
1086
|
+
},
|
|
1087
|
+
async apply(ctx, plan) {
|
|
1088
|
+
return await applyCodexMigrationPlan({
|
|
1089
|
+
ctx,
|
|
1090
|
+
plan,
|
|
1091
|
+
runtime: params.runtime
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
//#endregion
|
|
1097
|
+
//#region extensions/codex/index.ts
|
|
1098
|
+
var codex_default = definePluginEntry({
|
|
1099
|
+
id: "codex",
|
|
1100
|
+
name: "Codex",
|
|
1101
|
+
description: "Codex app-server harness and Codex-managed GPT model catalog.",
|
|
1102
|
+
register(api) {
|
|
1103
|
+
const resolveCurrentPluginConfig = () => resolveLivePluginConfigObject(api.runtime.config?.current ? () => api.runtime.config.current() : void 0, "codex", api.pluginConfig) ?? api.pluginConfig;
|
|
1104
|
+
api.registerAgentHarness(createCodexAppServerAgentHarness({ resolvePluginConfig: resolveCurrentPluginConfig }));
|
|
1105
|
+
api.registerProvider(buildCodexProvider({ pluginConfig: api.pluginConfig }));
|
|
1106
|
+
api.registerMediaUnderstandingProvider(buildCodexMediaUnderstandingProvider({ pluginConfig: api.pluginConfig }));
|
|
1107
|
+
api.registerMigrationProvider(buildCodexMigrationProvider({ runtime: api.runtime }));
|
|
1108
|
+
for (const command of createCodexCliSessionNodeHostCommands()) api.registerNodeHostCommand(command);
|
|
1109
|
+
for (const policy of createCodexCliSessionNodeInvokePolicies()) api.registerNodeInvokePolicy(policy);
|
|
1110
|
+
api.registerCommand(createCodexCommand({
|
|
1111
|
+
pluginConfig: api.pluginConfig,
|
|
1112
|
+
deps: {
|
|
1113
|
+
listCodexCliSessionsOnNode: (params) => listCodexCliSessionsOnNode({
|
|
1114
|
+
runtime: api.runtime,
|
|
1115
|
+
...params
|
|
1116
|
+
}),
|
|
1117
|
+
resolveCodexCliSessionForBindingOnNode: (params) => resolveCodexCliSessionForBindingOnNode({
|
|
1118
|
+
runtime: api.runtime,
|
|
1119
|
+
...params
|
|
1120
|
+
}),
|
|
1121
|
+
codexPluginsManagementIo: {
|
|
1122
|
+
readConfig: () => {
|
|
1123
|
+
const plugins = (api.runtime.config?.current?.() ?? {}).plugins;
|
|
1124
|
+
if (!plugins || typeof plugins !== "object") return Promise.resolve({});
|
|
1125
|
+
const entries = plugins.entries;
|
|
1126
|
+
if (!entries || typeof entries !== "object") return Promise.resolve({});
|
|
1127
|
+
const codexEntry = entries.codex;
|
|
1128
|
+
if (!codexEntry || typeof codexEntry !== "object") return Promise.resolve({});
|
|
1129
|
+
const config = codexEntry.config;
|
|
1130
|
+
if (!config || typeof config !== "object") return Promise.resolve({});
|
|
1131
|
+
const codexPlugins = config.codexPlugins;
|
|
1132
|
+
if (!codexPlugins || typeof codexPlugins !== "object") return Promise.resolve({});
|
|
1133
|
+
const declared = codexPlugins.plugins;
|
|
1134
|
+
if (!declared || typeof declared !== "object") return Promise.resolve({ enabled: codexPlugins.enabled === true });
|
|
1135
|
+
return Promise.resolve({
|
|
1136
|
+
enabled: codexPlugins.enabled === true,
|
|
1137
|
+
plugins: declared
|
|
1138
|
+
});
|
|
1139
|
+
},
|
|
1140
|
+
mutate: async (update) => {
|
|
1141
|
+
await mutateConfigFile({ mutate: (draft) => {
|
|
1142
|
+
const root = draft;
|
|
1143
|
+
root.plugins = root.plugins ?? {};
|
|
1144
|
+
const pluginsBlock = root.plugins;
|
|
1145
|
+
pluginsBlock.entries = pluginsBlock.entries ?? {};
|
|
1146
|
+
const entries = pluginsBlock.entries;
|
|
1147
|
+
entries.codex = entries.codex ?? {};
|
|
1148
|
+
const codexEntry = entries.codex;
|
|
1149
|
+
codexEntry.config = codexEntry.config ?? {};
|
|
1150
|
+
const config = codexEntry.config;
|
|
1151
|
+
config.codexPlugins = config.codexPlugins ?? {};
|
|
1152
|
+
const codexPlugins = config.codexPlugins;
|
|
1153
|
+
codexPlugins.plugins = codexPlugins.plugins ?? {};
|
|
1154
|
+
update(codexPlugins);
|
|
1155
|
+
} });
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}));
|
|
1160
|
+
api.on("inbound_claim", (event, ctx) => handleCodexConversationInboundClaim(event, ctx, {
|
|
1161
|
+
pluginConfig: resolveCurrentPluginConfig(),
|
|
1162
|
+
resumeCodexCliSessionOnNode: (params) => resumeCodexCliSessionOnNode({
|
|
1163
|
+
runtime: api.runtime,
|
|
1164
|
+
...params
|
|
1165
|
+
})
|
|
1166
|
+
}));
|
|
1167
|
+
api.onConversationBindingResolved?.(handleCodexConversationBindingResolved);
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
//#endregion
|
|
1171
|
+
export { codex_default as default };
|