@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.
Files changed (109) hide show
  1. package/README.md +2 -0
  2. package/dist/api.js +18 -23
  3. package/dist/apply-B6el6hdO.js +357 -0
  4. package/dist/{attempt-client-cleanup-DYHcRQAa.js → attempt-client-cleanup-D6cR54TV.js} +113 -49
  5. package/dist/{attempt-context-DmQUNWwT.js → attempt-context-AO4DSjE0.js} +11 -9
  6. package/dist/{event-projector-usage-C5mcrGjp.js → attempt-notifications--H8zXR5-.js} +3 -89
  7. package/dist/auth-cache-key-Kq6oerr6.js +498 -0
  8. package/dist/auth-profile-CwzO4_RG.js +43 -0
  9. package/dist/auth-profile-selection-DFu9e167.js +45 -0
  10. package/dist/{binding-connection-E6uDsPlx.js → binding-connection-QqgcPCgk.js} +18 -3
  11. package/dist/{bounded-turn-wzJrwKKe.js → bounded-turn-lRpmZHFv.js} +54 -150
  12. package/dist/build-state-6RL6qohz.js +19 -0
  13. package/dist/{capabilities-dIjNVCYH.js → capabilities-BeqLPbtM.js} +2 -1
  14. package/dist/cli-metadata.js +1 -1
  15. package/dist/client-BEKu4yDx.js +3983 -0
  16. package/dist/command-dispatch-CisT9Jqq.js +21 -0
  17. package/dist/{command-formatters-CLHhEB1Q.js → command-formatters-DeTfrapr.js} +2 -2
  18. package/dist/{command-handlers-CTGb2csu.js → command-handlers-BfIsJEuA.js} +158 -76
  19. package/dist/command-rpc-BMqRQOFX.js +226 -0
  20. package/dist/{compact-_t0HQrUS.js → compact-CGJZ2rlb.js} +89 -49
  21. package/dist/config-JDfTI4VI.js +106 -0
  22. package/dist/{config-BhmfC1s6.js → config-options-jnIFvwxD.js} +208 -654
  23. package/dist/config-runtime-BWf6JLWG.js +11 -0
  24. package/dist/config-utils-C57JiJrU.js +69 -0
  25. package/dist/conversation-binding-CxOlHiix.js +889 -0
  26. package/dist/{plugin-marketplace-discovery-CfFlKqDl.js → conversation-control-CUCrSIQI.js} +36 -155
  27. package/dist/doctor-contract-api.js +8 -9
  28. package/dist/{dynamic-tools-BU9tmlYm.js → dynamic-tools-D-JBoaLt.js} +734 -698
  29. package/dist/{effective-mcp-catalog-DzYBW4h1.js → effective-mcp-catalog-J_5Ep5Um.js} +4 -3
  30. package/dist/{elicitation-input-DMkeki8d.js → elicitation-input-DPoK8F7w.js} +8 -22
  31. package/dist/ephemeral-turn-DSwzP8YY.js +101 -0
  32. package/dist/{event-projector-assistant-message-DHRFXKbS.js → event-projector-assistant-message-BmBM4qBV.js} +23 -27
  33. package/dist/event-projector-usage-CIyrYYid.js +102 -0
  34. package/dist/{harness-DXVZ5II5.js → harness-FR6eQgyO.js} +47 -17
  35. package/dist/harness.js +1 -1
  36. package/dist/history-rejection-B4nOXNXF.js +13 -0
  37. package/dist/{image-payload-sanitizer-CnfoUPCE.js → image-payload-sanitizer-tupAr-2o.js} +29 -15
  38. package/dist/incognito-session-uhrBF6wJ.js +15 -0
  39. package/dist/index.js +413 -2893
  40. package/dist/{isolated-completion-kg9kv4iH.js → isolated-completion-DHBefrzg.js} +12 -21
  41. package/dist/{managed-binary-4-Vjz5GH.js → managed-binary-DrjjRRUD.js} +17 -84
  42. package/dist/managed-thread-store-D1t5jh3G.js +66 -0
  43. package/dist/media-understanding-provider.js +4 -1
  44. package/dist/{model-catalog-CUM68Hkl.js → model-catalog-B_6M04Wo.js} +6 -5
  45. package/dist/{models-sYnEc0gd.js → models-P9k2qAof.js} +4 -4
  46. package/dist/native-execution-policy-umd0tgh4.js +128 -0
  47. package/dist/{native-subagent-monitor-CnH147jH.js → native-subagent-monitor-BbCUKRwC.js} +76 -48
  48. package/dist/node-cli-sessions-rj0ysJwM.js +527 -0
  49. package/dist/{node-exec-server.runtime-CstNHCmC.js → node-exec-server.runtime-BY_ctYnT.js} +54 -23
  50. package/dist/plan-BMJdMOEF.js +711 -0
  51. package/dist/plugin-activation-BQK-f5sV.js +133 -0
  52. package/dist/{thread-resume-C7pyVKeW.js → plugin-app-cache-key-CdSQzWyX.js} +5 -53
  53. package/dist/{plugin-approval-roundtrip-CNe-Xrjx.js → plugin-approval-roundtrip-DeW95wB5.js} +1 -1
  54. package/dist/plugin-inventory-CoRCzWW4.js +325 -0
  55. package/dist/plugin-marketplace-discovery-3akBizzF.js +134 -0
  56. package/dist/{plugin-metadata-cache-BFrPhb2c.js → plugin-metadata-cache-DgNfRAGA.js} +13 -9
  57. package/dist/protocol-CAAcVIKF.js +275 -0
  58. package/dist/{provider-capabilities-DW5p4k9w.js → provider-capabilities-W4tfK5Y5.js} +2 -2
  59. package/dist/{rate-limits-CawQJfUS.js → rate-limits-Bqnx1N4z.js} +1 -1
  60. package/dist/request-CGvGOpeR.js +198 -0
  61. package/dist/{run-attempt-D1hJO4fX.js → run-attempt-DwKds3DN.js} +1498 -1028
  62. package/dist/{runtime-artifact-C3jVimFn.js → runtime-artifact-T-NwqeSH.js} +28 -28
  63. package/dist/sandbox-guard-BcT66fWy.js +165 -0
  64. package/dist/{session-binding-BHuTCRZQ.js → session-binding-CKSepwIC.js} +118 -324
  65. package/dist/session-binding-record-CaZjYwNS.js +256 -0
  66. package/dist/session-catalog-HaDcp7Sv.js +1533 -0
  67. package/dist/session-catalog-adoption-BKLtSrwi.js +251 -0
  68. package/dist/session-catalog-archive-D0i2pGj2.js +56 -0
  69. package/dist/session-catalog-home-id-D7-aLiNt.js +190 -0
  70. package/dist/session-catalog-node-adoption-BUuDYY8R.js +182 -0
  71. package/dist/session-catalog-node-continue-CBtc4wkI.js +238 -0
  72. package/dist/session-catalog-parsing-CdD3JhdM.js +280 -0
  73. package/dist/session-catalog-provenance-DkJHo735.js +124 -0
  74. package/dist/{session-cli-CmFEXMAM.js → session-cli-CbgaHh0f.js} +3 -2
  75. package/dist/session-history-Cz-tOOYj.js +96 -0
  76. package/dist/{session-upstream-marker-C351-5Qw.js → session-history-import-DFN7sWRU.js} +5 -49
  77. package/dist/session-history-read-cxPUxyVV.js +50 -0
  78. package/dist/session-history-worker-runtime.js +60 -0
  79. package/dist/{settled-turn-context-D3SNWtUn.js → session-history.worker-CNEvGaU5.js} +75 -69
  80. package/dist/session-history.worker.js +2 -0
  81. package/dist/{session-initialization-BeWzjGiR.js → session-initialization-Jo86C60I.js} +2 -1
  82. package/dist/{session-permission-policy-DeWVTCMj.js → session-permission-policy-B22InTp_.js} +4 -7
  83. package/dist/{session-retirement-BujDjXVF.js → session-retirement-BSNG_mhf.js} +8 -7
  84. package/dist/session-upstream-marker-D15C9NHp.js +46 -0
  85. package/dist/settled-turn-context-Du6gdUDd.js +45 -0
  86. package/dist/{settled-turn-finalizer-BVJx4yoc.js → settled-turn-finalizer-BuLUrZl2.js} +54 -42
  87. package/dist/shared-client-CVhez2Uo.js +2911 -0
  88. package/dist/{side-question-BTZAII4l.js → side-question-DLbr2vUU.js} +135 -191
  89. package/dist/source-Da-h6f7e.js +518 -0
  90. package/dist/thread-archive-guard-D1bP04Tf.js +53 -0
  91. package/dist/{thread-lifecycle-DAcEJ_Om.js → thread-lifecycle-D1pzRwHB.js} +467 -977
  92. package/dist/{thread-ownership-zGokd8i1.js → thread-ownership-D6oASVRu.js} +15 -17
  93. package/dist/{thread-policy-g4KbJPzp.js → thread-policy-D8kI7yAO.js} +2 -2
  94. package/dist/thread-resume-T5cveyxA.js +52 -0
  95. package/dist/timeout-BVw8aaM1.js +33 -0
  96. package/dist/transcript-mirror-attestation-DibE0krH.js +89 -0
  97. package/dist/{transcript-mirror-DTUxFWa_.js → transcript-mirror-t5TOccct.js} +111 -379
  98. package/dist/{transport-stdio-CyPldczm.js → transport-stdio-BGjHoYLr.js} +80 -48
  99. package/dist/{upstream-session-fork-CYlBIGVt.js → upstream-session-fork-De-sLJ2r.js} +94 -166
  100. package/dist/{usage-Bj-rrzkR.js → usage-CPPTmBvZ.js} +4 -3
  101. package/dist/version-omm6IPI3.js +12 -0
  102. package/dist/{web-search-provider.runtime-D2FWSK4w.js → web-search-provider.runtime-CSVgQL0w.js} +3 -3
  103. package/openclaw.plugin.json +22 -1
  104. package/package.json +6 -6
  105. package/dist/request-DYAI5FQE.js +0 -475
  106. package/dist/session-catalog-yyvTWFOw.js +0 -3120
  107. package/dist/session-history-C5J1AKzG.js +0 -87
  108. package/dist/shared-client-DxcfF9KX.js +0 -7494
  109. 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 };