@openclaw/codex 2026.9.1 → 2026.9.3
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/README.md +2 -0
- package/dist/api.js +18 -23
- package/dist/apply-B6el6hdO.js +357 -0
- package/dist/{attempt-client-cleanup-DYHcRQAa.js → attempt-client-cleanup-D6cR54TV.js} +113 -49
- package/dist/{attempt-context-DmQUNWwT.js → attempt-context-AO4DSjE0.js} +11 -9
- package/dist/{event-projector-usage-C5mcrGjp.js → attempt-notifications--H8zXR5-.js} +3 -89
- package/dist/auth-cache-key-Kq6oerr6.js +498 -0
- package/dist/auth-profile-CwzO4_RG.js +43 -0
- package/dist/auth-profile-selection-DFu9e167.js +45 -0
- package/dist/{binding-connection-E6uDsPlx.js → binding-connection-QqgcPCgk.js} +18 -3
- package/dist/{bounded-turn-wzJrwKKe.js → bounded-turn-lRpmZHFv.js} +54 -150
- package/dist/build-state-6RL6qohz.js +19 -0
- package/dist/{capabilities-dIjNVCYH.js → capabilities-BeqLPbtM.js} +2 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/client-BEKu4yDx.js +3983 -0
- package/dist/command-dispatch-CisT9Jqq.js +21 -0
- package/dist/{command-formatters-CLHhEB1Q.js → command-formatters-DeTfrapr.js} +2 -2
- package/dist/{command-handlers-CTGb2csu.js → command-handlers-BfIsJEuA.js} +158 -76
- package/dist/command-rpc-BMqRQOFX.js +226 -0
- package/dist/{compact-_t0HQrUS.js → compact-CGJZ2rlb.js} +89 -49
- package/dist/config-JDfTI4VI.js +106 -0
- package/dist/{config-BhmfC1s6.js → config-options-jnIFvwxD.js} +208 -654
- package/dist/config-runtime-BWf6JLWG.js +11 -0
- package/dist/config-utils-C57JiJrU.js +69 -0
- package/dist/conversation-binding-CxOlHiix.js +889 -0
- package/dist/{plugin-marketplace-discovery-CfFlKqDl.js → conversation-control-CUCrSIQI.js} +36 -155
- package/dist/doctor-contract-api.js +8 -9
- package/dist/{dynamic-tools-BU9tmlYm.js → dynamic-tools-D-JBoaLt.js} +734 -698
- package/dist/{effective-mcp-catalog-DzYBW4h1.js → effective-mcp-catalog-J_5Ep5Um.js} +4 -3
- package/dist/{elicitation-input-DMkeki8d.js → elicitation-input-DPoK8F7w.js} +8 -22
- package/dist/ephemeral-turn-DSwzP8YY.js +101 -0
- package/dist/{event-projector-assistant-message-DHRFXKbS.js → event-projector-assistant-message-BmBM4qBV.js} +23 -27
- package/dist/event-projector-usage-CIyrYYid.js +102 -0
- package/dist/{harness-DXVZ5II5.js → harness-FR6eQgyO.js} +47 -17
- package/dist/harness.js +1 -1
- package/dist/history-rejection-B4nOXNXF.js +13 -0
- package/dist/{image-payload-sanitizer-CnfoUPCE.js → image-payload-sanitizer-tupAr-2o.js} +29 -15
- package/dist/incognito-session-uhrBF6wJ.js +15 -0
- package/dist/index.js +413 -2893
- package/dist/{isolated-completion-kg9kv4iH.js → isolated-completion-DHBefrzg.js} +12 -21
- package/dist/{managed-binary-4-Vjz5GH.js → managed-binary-DrjjRRUD.js} +17 -84
- package/dist/managed-thread-store-D1t5jh3G.js +66 -0
- package/dist/media-understanding-provider.js +4 -1
- package/dist/{model-catalog-CUM68Hkl.js → model-catalog-B_6M04Wo.js} +6 -5
- package/dist/{models-sYnEc0gd.js → models-P9k2qAof.js} +4 -4
- package/dist/native-execution-policy-umd0tgh4.js +128 -0
- package/dist/{native-subagent-monitor-CnH147jH.js → native-subagent-monitor-BbCUKRwC.js} +76 -48
- package/dist/node-cli-sessions-rj0ysJwM.js +527 -0
- package/dist/{node-exec-server.runtime-CstNHCmC.js → node-exec-server.runtime-BY_ctYnT.js} +54 -23
- package/dist/plan-BMJdMOEF.js +711 -0
- package/dist/plugin-activation-BQK-f5sV.js +133 -0
- package/dist/{thread-resume-C7pyVKeW.js → plugin-app-cache-key-CdSQzWyX.js} +5 -53
- package/dist/{plugin-approval-roundtrip-CNe-Xrjx.js → plugin-approval-roundtrip-DeW95wB5.js} +1 -1
- package/dist/plugin-inventory-CoRCzWW4.js +325 -0
- package/dist/plugin-marketplace-discovery-3akBizzF.js +134 -0
- package/dist/{plugin-metadata-cache-BFrPhb2c.js → plugin-metadata-cache-DgNfRAGA.js} +13 -9
- package/dist/protocol-CAAcVIKF.js +275 -0
- package/dist/{provider-capabilities-DW5p4k9w.js → provider-capabilities-W4tfK5Y5.js} +2 -2
- package/dist/{rate-limits-CawQJfUS.js → rate-limits-Bqnx1N4z.js} +1 -1
- package/dist/request-CGvGOpeR.js +198 -0
- package/dist/{run-attempt-D1hJO4fX.js → run-attempt-DwKds3DN.js} +1498 -1028
- package/dist/{runtime-artifact-C3jVimFn.js → runtime-artifact-T-NwqeSH.js} +28 -28
- package/dist/sandbox-guard-BcT66fWy.js +165 -0
- package/dist/{session-binding-BHuTCRZQ.js → session-binding-CKSepwIC.js} +118 -324
- package/dist/session-binding-record-CaZjYwNS.js +256 -0
- package/dist/session-catalog-HaDcp7Sv.js +1533 -0
- package/dist/session-catalog-adoption-BKLtSrwi.js +251 -0
- package/dist/session-catalog-archive-D0i2pGj2.js +56 -0
- package/dist/session-catalog-home-id-D7-aLiNt.js +190 -0
- package/dist/session-catalog-node-adoption-BUuDYY8R.js +182 -0
- package/dist/session-catalog-node-continue-CBtc4wkI.js +238 -0
- package/dist/session-catalog-parsing-CdD3JhdM.js +280 -0
- package/dist/session-catalog-provenance-DkJHo735.js +124 -0
- package/dist/{session-cli-CmFEXMAM.js → session-cli-CbgaHh0f.js} +3 -2
- package/dist/session-history-Cz-tOOYj.js +96 -0
- package/dist/{session-upstream-marker-C351-5Qw.js → session-history-import-DFN7sWRU.js} +5 -49
- package/dist/session-history-read-cxPUxyVV.js +50 -0
- package/dist/session-history-worker-runtime.js +60 -0
- package/dist/{settled-turn-context-D3SNWtUn.js → session-history.worker-CNEvGaU5.js} +75 -69
- package/dist/session-history.worker.js +2 -0
- package/dist/{session-initialization-BeWzjGiR.js → session-initialization-Jo86C60I.js} +2 -1
- package/dist/{session-permission-policy-DeWVTCMj.js → session-permission-policy-B22InTp_.js} +4 -7
- package/dist/{session-retirement-BujDjXVF.js → session-retirement-BSNG_mhf.js} +8 -7
- package/dist/session-upstream-marker-D15C9NHp.js +46 -0
- package/dist/settled-turn-context-Du6gdUDd.js +45 -0
- package/dist/{settled-turn-finalizer-BVJx4yoc.js → settled-turn-finalizer-BuLUrZl2.js} +54 -42
- package/dist/shared-client-CVhez2Uo.js +2911 -0
- package/dist/{side-question-BTZAII4l.js → side-question-DLbr2vUU.js} +135 -191
- package/dist/source-Da-h6f7e.js +518 -0
- package/dist/thread-archive-guard-D1bP04Tf.js +53 -0
- package/dist/{thread-lifecycle-DAcEJ_Om.js → thread-lifecycle-D1pzRwHB.js} +467 -977
- package/dist/{thread-ownership-zGokd8i1.js → thread-ownership-D6oASVRu.js} +15 -17
- package/dist/{thread-policy-g4KbJPzp.js → thread-policy-D8kI7yAO.js} +2 -2
- package/dist/thread-resume-T5cveyxA.js +52 -0
- package/dist/timeout-BVw8aaM1.js +33 -0
- package/dist/transcript-mirror-attestation-DibE0krH.js +89 -0
- package/dist/{transcript-mirror-DTUxFWa_.js → transcript-mirror-t5TOccct.js} +111 -379
- package/dist/{transport-stdio-CyPldczm.js → transport-stdio-BGjHoYLr.js} +80 -48
- package/dist/{upstream-session-fork-CYlBIGVt.js → upstream-session-fork-De-sLJ2r.js} +94 -166
- package/dist/{usage-Bj-rrzkR.js → usage-CPPTmBvZ.js} +4 -3
- package/dist/version-omm6IPI3.js +12 -0
- package/dist/{web-search-provider.runtime-D2FWSK4w.js → web-search-provider.runtime-CSVgQL0w.js} +3 -3
- package/openclaw.plugin.json +22 -1
- package/package.json +6 -6
- package/dist/request-DYAI5FQE.js +0 -475
- package/dist/session-catalog-yyvTWFOw.js +0 -3120
- package/dist/session-history-C5J1AKzG.js +0 -87
- package/dist/shared-client-DxcfF9KX.js +0 -7494
- package/dist/{auth-binding-Ds_QVm-X.js → auth-binding-Co2Vfcf_.js} +1 -1
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
+
import { m as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-utils-C57JiJrU.js";
|
|
3
|
+
import { r as buildCodexPluginAppCacheKey, s as defaultCodexAppInventoryCache } from "./plugin-app-cache-key-CdSQzWyX.js";
|
|
4
|
+
import { o as withCodexAppServerJsonClient } from "./request-CGvGOpeR.js";
|
|
5
|
+
import "./config-JDfTI4VI.js";
|
|
6
|
+
import { i as pluginReadParams, n as isOpenAiCuratedMarketplace } from "./plugin-inventory-CoRCzWW4.js";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import fs from "node:fs/promises";
|
|
10
|
+
import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
11
|
+
import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
|
|
12
|
+
import { pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
13
|
+
import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
|
|
14
|
+
//#region extensions/codex/src/migration/helpers.ts
|
|
15
|
+
async function exists(filePath) {
|
|
16
|
+
return await pathExists(filePath);
|
|
17
|
+
}
|
|
18
|
+
async function isDirectory(filePath) {
|
|
19
|
+
if (!filePath) return false;
|
|
20
|
+
try {
|
|
21
|
+
return (await fs.stat(filePath)).isDirectory();
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function resolveUserHomeDir() {
|
|
27
|
+
return process.env.HOME?.trim() || os.homedir();
|
|
28
|
+
}
|
|
29
|
+
function resolveHomePath(value) {
|
|
30
|
+
if (value === "~") return resolveUserHomeDir();
|
|
31
|
+
if (value.startsWith("~/")) return path.join(resolveUserHomeDir(), value.slice(2));
|
|
32
|
+
return path.resolve(value);
|
|
33
|
+
}
|
|
34
|
+
function sanitizeName(value) {
|
|
35
|
+
return value.trim().toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 64);
|
|
36
|
+
}
|
|
37
|
+
async function readJsonObject(filePath) {
|
|
38
|
+
if (!filePath) return {};
|
|
39
|
+
const { value: parsed } = await readJsonFileWithFallback(filePath, {});
|
|
40
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region extensions/codex/src/migration/source-files.ts
|
|
44
|
+
const SKILL_FILENAME = "SKILL.md";
|
|
45
|
+
const MAX_SCAN_DEPTH = 6;
|
|
46
|
+
const MAX_DISCOVERED_DIRS = 2e3;
|
|
47
|
+
async function safeReadDir(dir) {
|
|
48
|
+
return await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
49
|
+
}
|
|
50
|
+
async function discoverSkillDirs(params) {
|
|
51
|
+
if (!params.root || !await isDirectory(params.root)) return [];
|
|
52
|
+
const discovered = [];
|
|
53
|
+
async function visit(dir, depth) {
|
|
54
|
+
if (discovered.length >= MAX_DISCOVERED_DIRS || depth > MAX_SCAN_DEPTH) return;
|
|
55
|
+
const name = path.basename(dir);
|
|
56
|
+
if (params.excludeSystem && depth === 1 && name === ".system") return;
|
|
57
|
+
if (await exists(path.join(dir, SKILL_FILENAME))) {
|
|
58
|
+
discovered.push({
|
|
59
|
+
name,
|
|
60
|
+
source: dir,
|
|
61
|
+
sourceLabel: params.sourceLabel
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
for (const entry of await safeReadDir(dir)) if (entry.isDirectory()) await visit(path.join(dir, entry.name), depth + 1);
|
|
66
|
+
}
|
|
67
|
+
await visit(params.root, 0);
|
|
68
|
+
return discovered;
|
|
69
|
+
}
|
|
70
|
+
async function discoverPluginDirs(codexHome) {
|
|
71
|
+
const root = path.join(codexHome, "plugins", "cache");
|
|
72
|
+
if (!await isDirectory(root)) return [];
|
|
73
|
+
const discovered = /* @__PURE__ */ new Map();
|
|
74
|
+
async function visit(dir, depth) {
|
|
75
|
+
if (discovered.size >= MAX_DISCOVERED_DIRS || depth > MAX_SCAN_DEPTH) return;
|
|
76
|
+
const manifestPath = path.join(dir, ".codex-plugin", "plugin.json");
|
|
77
|
+
if (await exists(manifestPath)) {
|
|
78
|
+
const manifest = await readJsonObject(manifestPath);
|
|
79
|
+
const manifestName = typeof manifest.name === "string" ? manifest.name.trim() : "";
|
|
80
|
+
discovered.set(dir, {
|
|
81
|
+
name: manifestName || path.basename(dir),
|
|
82
|
+
source: dir,
|
|
83
|
+
migratable: false,
|
|
84
|
+
message: "Cached Codex plugin bundle found. Review manually unless the plugin is also installed in the source Codex app-server inventory"
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
for (const entry of await safeReadDir(dir)) if (entry.isDirectory()) await visit(path.join(dir, entry.name), depth + 1);
|
|
89
|
+
}
|
|
90
|
+
await visit(root, 0);
|
|
91
|
+
return [...discovered.values()].toSorted((a, b) => a.source.localeCompare(b.source));
|
|
92
|
+
}
|
|
93
|
+
async function discoverCodexMemoryFile(candidate) {
|
|
94
|
+
try {
|
|
95
|
+
const stat = await fs.lstat(candidate.path);
|
|
96
|
+
if (stat.isSymbolicLink()) throw new Error(`Codex memory source must not be a symbolic link: ${candidate.path}`);
|
|
97
|
+
if (!stat.isFile()) throw new Error(`Codex memory source must be a regular file: ${candidate.path}`);
|
|
98
|
+
return candidate;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return;
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function discoverCodexMemorySources(codexHome) {
|
|
105
|
+
const memoriesDir = path.join(codexHome, "memories");
|
|
106
|
+
return (await Promise.all([{
|
|
107
|
+
id: "memory:codex:MEMORY.md",
|
|
108
|
+
label: "Codex consolidated memory",
|
|
109
|
+
name: "MEMORY.md"
|
|
110
|
+
}, {
|
|
111
|
+
id: "memory:codex:memory_summary.md",
|
|
112
|
+
label: "Codex memory summary",
|
|
113
|
+
name: "memory_summary.md"
|
|
114
|
+
}].map(async (candidate) => await discoverCodexMemoryFile({
|
|
115
|
+
id: candidate.id,
|
|
116
|
+
label: candidate.label,
|
|
117
|
+
path: path.join(memoriesDir, candidate.name)
|
|
118
|
+
})))).filter((entry) => entry !== void 0);
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region extensions/codex/src/migration/source.ts
|
|
122
|
+
var source_exports = /* @__PURE__ */ __exportAll({
|
|
123
|
+
codexPluginMigrationSubscriptionWarning: () => codexPluginMigrationSubscriptionWarning,
|
|
124
|
+
discoverCodexSource: () => discoverCodexSource,
|
|
125
|
+
hasCodexSource: () => hasCodexSource
|
|
126
|
+
});
|
|
127
|
+
function defaultCodexHome() {
|
|
128
|
+
const configuredHome = process.env.CODEX_HOME;
|
|
129
|
+
return resolveHomePath(configuredHome !== void 0 && configuredHome.length > 0 ? configuredHome : "~/.codex");
|
|
130
|
+
}
|
|
131
|
+
function personalAgentsSkillsDir() {
|
|
132
|
+
return path.join(resolveUserHomeDir(), ".agents", "skills");
|
|
133
|
+
}
|
|
134
|
+
async function discoverInstalledCuratedPlugins(codexHome, options = {}) {
|
|
135
|
+
const startOptions = sourceCodexAppServerStartOptions(codexHome);
|
|
136
|
+
try {
|
|
137
|
+
return await withCodexAppServerJsonClient({
|
|
138
|
+
timeoutMs: 6e4,
|
|
139
|
+
startOptions,
|
|
140
|
+
authProfileId: null,
|
|
141
|
+
isolated: true
|
|
142
|
+
}, async (request) => {
|
|
143
|
+
const requestOptions = {
|
|
144
|
+
startOptions,
|
|
145
|
+
request
|
|
146
|
+
};
|
|
147
|
+
const response = await request({
|
|
148
|
+
method: "plugin/installed",
|
|
149
|
+
requestParams: { cwds: [] }
|
|
150
|
+
});
|
|
151
|
+
const curatedSyncRoot = path.join(codexHome, ".tmp", "plugins");
|
|
152
|
+
const curatedMarketplaceErrors = response.marketplaceLoadErrors.filter((error) => isPathInside(curatedSyncRoot, error.marketplacePath));
|
|
153
|
+
if (curatedMarketplaceErrors.length > 0) return {
|
|
154
|
+
plugins: [],
|
|
155
|
+
error: curatedMarketplaceErrors.map((error) => error.message).join("; ")
|
|
156
|
+
};
|
|
157
|
+
const installed = discoverInstalledCuratedPluginSources(response);
|
|
158
|
+
return { plugins: (options.evaluatePluginMigrationEligibility === true ? await withPluginMigrationEligibility({
|
|
159
|
+
plugins: installed,
|
|
160
|
+
requestOptions,
|
|
161
|
+
verifyPluginApps: options.verifyPluginApps === true
|
|
162
|
+
}) : installed.map(({ plugin }) => plugin)).toSorted((left, right) => (left.pluginName ?? left.name).localeCompare(right.pluginName ?? right.name)) };
|
|
163
|
+
});
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return {
|
|
166
|
+
plugins: [],
|
|
167
|
+
error: coerceErrorMessage(error)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function sourceCodexAppServerStartOptions(codexHome) {
|
|
172
|
+
return {
|
|
173
|
+
transport: "stdio",
|
|
174
|
+
command: "codex",
|
|
175
|
+
commandSource: "managed",
|
|
176
|
+
managedCommandOrder: "desktop-first",
|
|
177
|
+
args: [
|
|
178
|
+
"app-server",
|
|
179
|
+
"--listen",
|
|
180
|
+
"stdio://"
|
|
181
|
+
],
|
|
182
|
+
headers: {},
|
|
183
|
+
env: {
|
|
184
|
+
CODEX_HOME: codexHome,
|
|
185
|
+
HOME: path.dirname(codexHome)
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function buildInstalledPluginSource(plugin) {
|
|
190
|
+
const pluginName = pluginNameFromSummary(plugin);
|
|
191
|
+
if (!pluginName) return;
|
|
192
|
+
return {
|
|
193
|
+
name: plugin.name,
|
|
194
|
+
pluginName,
|
|
195
|
+
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
196
|
+
source: `${CODEX_PLUGINS_MARKETPLACE_NAME}/${pluginName}`,
|
|
197
|
+
migratable: true,
|
|
198
|
+
installed: plugin.installed,
|
|
199
|
+
enabled: plugin.enabled
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function discoverInstalledCuratedPluginSources(response) {
|
|
203
|
+
const installedByName = /* @__PURE__ */ new Map();
|
|
204
|
+
for (const marketplace of response.marketplaces) {
|
|
205
|
+
if (!isOpenAiCuratedMarketplace(marketplace)) continue;
|
|
206
|
+
const remote = !marketplace.path;
|
|
207
|
+
for (const summary of marketplace.plugins) {
|
|
208
|
+
if (!summary.installed) continue;
|
|
209
|
+
const plugin = buildInstalledPluginSource(summary);
|
|
210
|
+
if (!plugin?.pluginName) continue;
|
|
211
|
+
const existing = installedByName.get(plugin.pluginName);
|
|
212
|
+
if (existing && (!remote || existing.remote)) continue;
|
|
213
|
+
installedByName.set(plugin.pluginName, {
|
|
214
|
+
plugin,
|
|
215
|
+
marketplace: marketplaceRef(marketplace),
|
|
216
|
+
...remote ? { readPluginName: summary.remotePluginId?.trim() || void 0 } : { readPluginName: plugin.pluginName },
|
|
217
|
+
remote
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return Array.from(installedByName.values());
|
|
222
|
+
}
|
|
223
|
+
function marketplaceRef(marketplace) {
|
|
224
|
+
return {
|
|
225
|
+
name: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
226
|
+
...marketplace.path ? { path: marketplace.path } : {},
|
|
227
|
+
...!marketplace.path ? { remoteMarketplaceName: marketplace.name } : {}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
async function withPluginMigrationEligibility(params) {
|
|
231
|
+
const pending = [];
|
|
232
|
+
const evaluated = [];
|
|
233
|
+
for (const { plugin, marketplace, readPluginName } of params.plugins) {
|
|
234
|
+
if (plugin.enabled !== true) {
|
|
235
|
+
evaluated.push({
|
|
236
|
+
...plugin,
|
|
237
|
+
migratable: false,
|
|
238
|
+
migrationBlock: { code: "plugin_disabled" },
|
|
239
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" is installed in Codex but disabled; enable it in Codex before migrating it to OpenClaw.`
|
|
240
|
+
});
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
const detail = await readPluginDetail(params.requestOptions, marketplace, plugin, readPluginName);
|
|
244
|
+
if (!detail.ok) {
|
|
245
|
+
evaluated.push({
|
|
246
|
+
...plugin,
|
|
247
|
+
migratable: false,
|
|
248
|
+
migrationBlock: {
|
|
249
|
+
code: "plugin_read_unavailable",
|
|
250
|
+
error: detail.error
|
|
251
|
+
},
|
|
252
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" detail could not be read: ${detail.error}`
|
|
253
|
+
});
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (detail.detail.apps.length === 0) {
|
|
257
|
+
evaluated.push({
|
|
258
|
+
...plugin,
|
|
259
|
+
migratable: true
|
|
260
|
+
});
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const apps = detail.detail.apps.map(sourcePluginAppFact).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
264
|
+
pending.push({
|
|
265
|
+
plugin,
|
|
266
|
+
apps
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
if (pending.length === 0) return evaluated;
|
|
270
|
+
let sourceAccount;
|
|
271
|
+
let sourceAccountError;
|
|
272
|
+
try {
|
|
273
|
+
sourceAccount = await readSourceCodexAccount(params.requestOptions);
|
|
274
|
+
if (sourceAccount === "missing") sourceAccountError = "Codex app-server did not report an authenticated source account.";
|
|
275
|
+
} catch (error) {
|
|
276
|
+
sourceAccountError = coerceErrorMessage(error);
|
|
277
|
+
}
|
|
278
|
+
if (sourceAccountError && !params.verifyPluginApps) {
|
|
279
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
280
|
+
...plugin,
|
|
281
|
+
migratable: false,
|
|
282
|
+
migrationBlock: {
|
|
283
|
+
code: "codex_account_unavailable",
|
|
284
|
+
apps,
|
|
285
|
+
error: sourceAccountError
|
|
286
|
+
},
|
|
287
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but the source Codex app-server account could not be read: ${sourceAccountError}`
|
|
288
|
+
});
|
|
289
|
+
return evaluated;
|
|
290
|
+
}
|
|
291
|
+
if (sourceAccount === "non_chatgpt") {
|
|
292
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
293
|
+
...plugin,
|
|
294
|
+
migratable: false,
|
|
295
|
+
migrationBlock: {
|
|
296
|
+
code: "codex_subscription_required",
|
|
297
|
+
apps
|
|
298
|
+
},
|
|
299
|
+
message: codexSubscriptionRequiredMessage(plugin)
|
|
300
|
+
});
|
|
301
|
+
return evaluated;
|
|
302
|
+
}
|
|
303
|
+
if (!params.verifyPluginApps) {
|
|
304
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
305
|
+
...plugin,
|
|
306
|
+
apps,
|
|
307
|
+
migratable: true
|
|
308
|
+
});
|
|
309
|
+
return evaluated;
|
|
310
|
+
}
|
|
311
|
+
const snapshot = await refreshSourceAppInventory(params.requestOptions).catch((error) => {
|
|
312
|
+
const message = coerceErrorMessage(error);
|
|
313
|
+
for (const { plugin, apps } of pending) evaluated.push({
|
|
314
|
+
...plugin,
|
|
315
|
+
migratable: false,
|
|
316
|
+
migrationBlock: {
|
|
317
|
+
code: "app_inventory_unavailable",
|
|
318
|
+
apps,
|
|
319
|
+
error: message
|
|
320
|
+
},
|
|
321
|
+
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but source app inventory could not be read: ${message}`
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
if (!snapshot) return evaluated;
|
|
325
|
+
const appInfoById = new Map(snapshot.apps.map((app) => [app.id, app]));
|
|
326
|
+
const installedAppsById = new Map(snapshot.installedApps.map((app) => [app.id, app]));
|
|
327
|
+
for (const { plugin, apps: declaredApps } of pending) {
|
|
328
|
+
const apps = declaredApps.map((app) => sourcePluginAppFactWithInventory(app, appInfoById.get(app.id), installedAppsById.get(app.id))).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
329
|
+
const blockCode = migrationBlockCodeForApps(apps);
|
|
330
|
+
if (!blockCode) {
|
|
331
|
+
evaluated.push({
|
|
332
|
+
...plugin,
|
|
333
|
+
apps,
|
|
334
|
+
migratable: true
|
|
335
|
+
});
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
evaluated.push({
|
|
339
|
+
...plugin,
|
|
340
|
+
migratable: false,
|
|
341
|
+
migrationBlock: {
|
|
342
|
+
code: blockCode,
|
|
343
|
+
apps
|
|
344
|
+
},
|
|
345
|
+
message: appInventoryBlockMessage(plugin, apps, blockCode)
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return evaluated;
|
|
349
|
+
}
|
|
350
|
+
async function readSourceCodexAccount(options) {
|
|
351
|
+
const response = await options.request({
|
|
352
|
+
method: "account/read",
|
|
353
|
+
requestParams: { refreshToken: false }
|
|
354
|
+
});
|
|
355
|
+
if (!response.account || typeof response.account !== "object" || Array.isArray(response.account)) return "missing";
|
|
356
|
+
switch (response.account.type) {
|
|
357
|
+
case "chatgpt": return "chatgpt";
|
|
358
|
+
case "apiKey":
|
|
359
|
+
case "amazonBedrock": return "non_chatgpt";
|
|
360
|
+
default: return "missing";
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async function readPluginDetail(options, marketplace, plugin, readPluginName) {
|
|
364
|
+
if (!readPluginName) return {
|
|
365
|
+
ok: false,
|
|
366
|
+
error: `Codex remote plugin "${plugin.pluginName ?? plugin.name}" has no readable remote plugin id.`
|
|
367
|
+
};
|
|
368
|
+
try {
|
|
369
|
+
return {
|
|
370
|
+
ok: true,
|
|
371
|
+
detail: (await options.request({
|
|
372
|
+
method: "plugin/read",
|
|
373
|
+
requestParams: pluginReadParams(marketplace, readPluginName)
|
|
374
|
+
})).plugin
|
|
375
|
+
};
|
|
376
|
+
} catch (error) {
|
|
377
|
+
return {
|
|
378
|
+
ok: false,
|
|
379
|
+
error: coerceErrorMessage(error)
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async function refreshSourceAppInventory(options) {
|
|
384
|
+
const key = buildCodexPluginAppCacheKey({ appServer: { start: options.startOptions } });
|
|
385
|
+
const request = async (method, requestParams) => await options.request({
|
|
386
|
+
method,
|
|
387
|
+
requestParams
|
|
388
|
+
});
|
|
389
|
+
return await defaultCodexAppInventoryCache.refreshNow({
|
|
390
|
+
key,
|
|
391
|
+
request,
|
|
392
|
+
forceRefetch: true
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
function sourcePluginAppFact(app) {
|
|
396
|
+
return {
|
|
397
|
+
id: app.id,
|
|
398
|
+
name: app.name
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
function sourcePluginAppFactWithInventory(app, info, installedApp) {
|
|
402
|
+
if (!installedApp) return app;
|
|
403
|
+
if (!info) return installedApp.enabled ? {
|
|
404
|
+
...app,
|
|
405
|
+
isAccessible: false,
|
|
406
|
+
isEnabled: true
|
|
407
|
+
} : {
|
|
408
|
+
...app,
|
|
409
|
+
isEnabled: false
|
|
410
|
+
};
|
|
411
|
+
if (!installedApp.enabled) return {
|
|
412
|
+
...app,
|
|
413
|
+
isAccessible: info.isAccessible,
|
|
414
|
+
isEnabled: false
|
|
415
|
+
};
|
|
416
|
+
return {
|
|
417
|
+
...app,
|
|
418
|
+
isAccessible: info.isAccessible && installedApp.callable,
|
|
419
|
+
isEnabled: info.isEnabled,
|
|
420
|
+
...!installedApp.callable ? { isCallable: false } : {}
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function migrationBlockCodeForApps(apps) {
|
|
424
|
+
if (apps.some((app) => app.isAccessible === false)) return "app_inaccessible";
|
|
425
|
+
if (apps.some((app) => app.isEnabled === false)) return "app_disabled";
|
|
426
|
+
if (apps.some((app) => app.isAccessible === void 0 || app.isEnabled === void 0)) return "app_missing";
|
|
427
|
+
}
|
|
428
|
+
function appInventoryBlockMessage(plugin, apps, code) {
|
|
429
|
+
const status = code === "app_inaccessible" ? apps.some((app) => app.isCallable === false) ? "not callable" : "inaccessible" : code === "app_disabled" ? "disabled" : "missing";
|
|
430
|
+
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];
|
|
431
|
+
const appLabel = blocking ? ` app "${blocking.name}"` : " an owned app";
|
|
432
|
+
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 OpenClaw.`;
|
|
433
|
+
}
|
|
434
|
+
function codexPluginMigrationSubscriptionWarning() {
|
|
435
|
+
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; OpenClaw auth or API-key auth does not satisfy Codex app connector access.";
|
|
436
|
+
}
|
|
437
|
+
function codexSubscriptionRequiredMessage(plugin) {
|
|
438
|
+
return `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but ${codexPluginMigrationSubscriptionWarning()}`;
|
|
439
|
+
}
|
|
440
|
+
function pluginNameFromSummary(summary) {
|
|
441
|
+
const candidates = [summary.name, summary.id];
|
|
442
|
+
for (const candidate of candidates) {
|
|
443
|
+
const trimmed = candidate.trim();
|
|
444
|
+
if (!trimmed) continue;
|
|
445
|
+
const marketplaceSuffix = [
|
|
446
|
+
`@${CODEX_PLUGINS_MARKETPLACE_NAME}-remote`,
|
|
447
|
+
`@openai-api-curated`,
|
|
448
|
+
`@${CODEX_PLUGINS_MARKETPLACE_NAME}`
|
|
449
|
+
].find((suffix) => trimmed.endsWith(suffix));
|
|
450
|
+
const normalized = ((marketplaceSuffix ? trimmed.slice(0, -marketplaceSuffix.length) : trimmed).split("/").at(-1)?.trim())?.toLowerCase().replaceAll(/\s+/gu, "-");
|
|
451
|
+
if (normalized) return normalized;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
async function discoverCodexSource(options = {}) {
|
|
455
|
+
const codexHome = resolveHomePath(options.input?.trim() || defaultCodexHome());
|
|
456
|
+
const codexSkillsDir = path.join(codexHome, "skills");
|
|
457
|
+
const agentsSkillsDir = personalAgentsSkillsDir();
|
|
458
|
+
const configPath = path.join(codexHome, "config.toml");
|
|
459
|
+
const authPath = path.join(codexHome, "auth.json");
|
|
460
|
+
const modelsCachePath = path.join(codexHome, "models_cache.json");
|
|
461
|
+
const hooksPath = path.join(codexHome, "hooks", "hooks.json");
|
|
462
|
+
const memoryFiles = await discoverCodexMemorySources(codexHome);
|
|
463
|
+
const codexSkills = options.memoryOnly ? [] : await discoverSkillDirs({
|
|
464
|
+
root: codexSkillsDir,
|
|
465
|
+
sourceLabel: "Codex skill",
|
|
466
|
+
excludeSystem: true
|
|
467
|
+
});
|
|
468
|
+
const personalAgentSkills = options.memoryOnly ? [] : await discoverSkillDirs({
|
|
469
|
+
root: agentsSkillsDir,
|
|
470
|
+
sourceLabel: "personal AgentSkill"
|
|
471
|
+
});
|
|
472
|
+
const sourcePluginDiscovery = options.memoryOnly ? { plugins: [] } : await discoverInstalledCuratedPlugins(codexHome, options);
|
|
473
|
+
const sourcePluginNames = new Set(sourcePluginDiscovery.plugins.flatMap((plugin) => plugin.pluginName ? [plugin.pluginName] : []));
|
|
474
|
+
const cachedPlugins = (options.memoryOnly ? [] : await discoverPluginDirs(codexHome)).filter((plugin) => {
|
|
475
|
+
const normalizedName = sanitizePluginName(plugin.name);
|
|
476
|
+
return !sourcePluginNames.has(normalizedName);
|
|
477
|
+
});
|
|
478
|
+
const plugins = [...sourcePluginDiscovery.plugins, ...cachedPlugins].toSorted((a, b) => a.source.localeCompare(b.source));
|
|
479
|
+
const archivePaths = [];
|
|
480
|
+
if (!options.memoryOnly && await exists(configPath)) archivePaths.push({
|
|
481
|
+
id: "archive:config.toml",
|
|
482
|
+
path: configPath,
|
|
483
|
+
relativePath: "config.toml",
|
|
484
|
+
message: "Codex config is archived for manual review; it is not activated automatically"
|
|
485
|
+
});
|
|
486
|
+
if (!options.memoryOnly && await exists(hooksPath)) archivePaths.push({
|
|
487
|
+
id: "archive:hooks/hooks.json",
|
|
488
|
+
path: hooksPath,
|
|
489
|
+
relativePath: "hooks/hooks.json",
|
|
490
|
+
message: "Codex native hooks are archived for manual review because they can execute commands"
|
|
491
|
+
});
|
|
492
|
+
const skills = [...codexSkills, ...personalAgentSkills].toSorted((a, b) => a.source.localeCompare(b.source));
|
|
493
|
+
const hasAuth = !options.memoryOnly && await exists(authPath);
|
|
494
|
+
const high = Boolean(memoryFiles.length || codexSkills.length || plugins.length || archivePaths.length || hasAuth);
|
|
495
|
+
const medium = personalAgentSkills.length > 0;
|
|
496
|
+
return {
|
|
497
|
+
root: codexHome,
|
|
498
|
+
confidence: high ? "high" : medium ? "medium" : "low",
|
|
499
|
+
codexHome,
|
|
500
|
+
...await isDirectory(codexSkillsDir) ? { codexSkillsDir } : {},
|
|
501
|
+
...await isDirectory(agentsSkillsDir) ? { personalAgentsSkillsDir: agentsSkillsDir } : {},
|
|
502
|
+
...hasAuth ? { authPath } : {},
|
|
503
|
+
...await exists(modelsCachePath) ? { modelsCachePath } : {},
|
|
504
|
+
memoryFiles,
|
|
505
|
+
skills,
|
|
506
|
+
plugins,
|
|
507
|
+
...sourcePluginDiscovery.error ? { pluginDiscoveryError: sourcePluginDiscovery.error } : {},
|
|
508
|
+
archivePaths
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function hasCodexSource(source) {
|
|
512
|
+
return source.confidence !== "low";
|
|
513
|
+
}
|
|
514
|
+
function sanitizePluginName(value) {
|
|
515
|
+
return value.trim().toLowerCase().replaceAll(/\s+/gu, "-");
|
|
516
|
+
}
|
|
517
|
+
//#endregion
|
|
518
|
+
export { exists as a, sanitizeName as c, source_exports as i, discoverCodexSource as n, readJsonObject as o, hasCodexSource as r, resolveHomePath as s, codexPluginMigrationSubscriptionWarning as t };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { o as isJsonObject } from "./protocol-CAAcVIKF.js";
|
|
2
|
+
import { normalizeBoundedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
|
+
//#region extensions/codex/src/app-server/thread-archive-guard.ts
|
|
4
|
+
const DESCENDANT_PAGE_LIMIT = 100;
|
|
5
|
+
const MAX_DESCENDANT_PAGES = 100;
|
|
6
|
+
const MAX_THREAD_ID_LENGTH = 256;
|
|
7
|
+
const MAX_CURSOR_LENGTH = 4096;
|
|
8
|
+
function readNextCursor(value) {
|
|
9
|
+
if (value === void 0 || value === null) return;
|
|
10
|
+
if (typeof value !== "string" || !value.trim() || value.length > MAX_CURSOR_LENGTH) throw new Error("Codex app-server returned an invalid descendant-list cursor");
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Native archive includes the spawned subtree. Enumerate that same subtree first so an
|
|
15
|
+
* OpenClaw-owned descendant cannot be stopped as an undocumented side effect.
|
|
16
|
+
*/
|
|
17
|
+
async function assertCodexArchiveDescendantsUnowned(params) {
|
|
18
|
+
const ancestorThreadId = normalizeBoundedOptionalString(params.threadId, MAX_THREAD_ID_LENGTH);
|
|
19
|
+
if (!ancestorThreadId) throw new Error("cannot verify Codex archive descendants for an invalid thread id");
|
|
20
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
21
|
+
const seenThreadIds = /* @__PURE__ */ new Set([ancestorThreadId]);
|
|
22
|
+
let cursor;
|
|
23
|
+
for (let pageIndex = 0; pageIndex < MAX_DESCENDANT_PAGES; pageIndex += 1) {
|
|
24
|
+
const response = await params.listPage({
|
|
25
|
+
ancestorThreadId,
|
|
26
|
+
archived: false,
|
|
27
|
+
limit: DESCENDANT_PAGE_LIMIT,
|
|
28
|
+
sortKey: "created_at",
|
|
29
|
+
sortDirection: "desc",
|
|
30
|
+
useStateDbOnly: true,
|
|
31
|
+
...cursor ? { cursor } : {}
|
|
32
|
+
});
|
|
33
|
+
if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex app-server returned an invalid descendant-list response");
|
|
34
|
+
if (response.data.length > DESCENDANT_PAGE_LIMIT) throw new Error("Codex app-server exceeded the descendant-list page limit");
|
|
35
|
+
for (const value of response.data) {
|
|
36
|
+
if (!isJsonObject(value)) throw new Error("Codex app-server returned an invalid descendant thread");
|
|
37
|
+
const descendantThreadId = normalizeBoundedOptionalString(value.id, MAX_THREAD_ID_LENGTH);
|
|
38
|
+
if (!descendantThreadId) throw new Error("Codex app-server returned a descendant without a valid thread id");
|
|
39
|
+
if (seenThreadIds.has(descendantThreadId)) throw new Error("Codex app-server returned a cyclic descendant thread list");
|
|
40
|
+
seenThreadIds.add(descendantThreadId);
|
|
41
|
+
await params.assertDescendantIdle(descendantThreadId);
|
|
42
|
+
if (await params.bindingStore.hasOtherThreadOwner(descendantThreadId)) throw new Error("cannot archive a Codex thread while a spawned descendant is owned by an OpenClaw session");
|
|
43
|
+
}
|
|
44
|
+
const nextCursor = readNextCursor(response.nextCursor);
|
|
45
|
+
if (!nextCursor) return;
|
|
46
|
+
if (seenCursors.has(nextCursor)) throw new Error("Codex app-server returned a repeated descendant-list cursor");
|
|
47
|
+
seenCursors.add(nextCursor);
|
|
48
|
+
cursor = nextCursor;
|
|
49
|
+
}
|
|
50
|
+
throw new Error("Codex descendant enumeration exceeded its safety limit");
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { assertCodexArchiveDescendantsUnowned as t };
|