@kodelyth/codex 2026.5.42 → 2026.6.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/package.json +16 -1
- package/doctor-contract-api.test.ts +0 -44
- package/doctor-contract-api.ts +0 -68
- package/harness.ts +0 -72
- package/index.test.ts +0 -230
- package/index.ts +0 -66
- package/media-understanding-provider.test.ts +0 -486
- package/media-understanding-provider.ts +0 -521
- package/prompt-overlay-runtime-contract.test.ts +0 -48
- package/prompt-overlay.ts +0 -21
- package/provider-catalog.ts +0 -83
- package/provider-discovery.ts +0 -45
- package/provider.test.ts +0 -384
- package/provider.ts +0 -243
- package/src/app-server/app-inventory-cache.test.ts +0 -176
- package/src/app-server/app-inventory-cache.ts +0 -324
- package/src/app-server/approval-bridge.test.ts +0 -1471
- package/src/app-server/approval-bridge.ts +0 -1211
- package/src/app-server/auth-bridge.test.ts +0 -1449
- package/src/app-server/auth-bridge.ts +0 -614
- package/src/app-server/auth-profile-runtime-contract.test.ts +0 -239
- package/src/app-server/capabilities.ts +0 -27
- package/src/app-server/client-factory.ts +0 -24
- package/src/app-server/client.test.ts +0 -563
- package/src/app-server/client.ts +0 -715
- package/src/app-server/compact.test.ts +0 -710
- package/src/app-server/compact.ts +0 -500
- package/src/app-server/computer-use.test.ts +0 -788
- package/src/app-server/computer-use.ts +0 -683
- package/src/app-server/config.test.ts +0 -879
- package/src/app-server/config.ts +0 -1038
- package/src/app-server/context-engine-projection.test.ts +0 -252
- package/src/app-server/context-engine-projection.ts +0 -403
- package/src/app-server/delivery-no-reply-runtime-contract.test.ts +0 -80
- package/src/app-server/dynamic-tool-diagnostics.ts +0 -73
- package/src/app-server/dynamic-tool-profile.ts +0 -69
- package/src/app-server/dynamic-tools.test.ts +0 -1302
- package/src/app-server/dynamic-tools.ts +0 -623
- package/src/app-server/elicitation-bridge.test.ts +0 -1056
- package/src/app-server/elicitation-bridge.ts +0 -783
- package/src/app-server/event-projector.test.ts +0 -2668
- package/src/app-server/event-projector.ts +0 -2057
- package/src/app-server/image-payload-sanitizer.test.ts +0 -49
- package/src/app-server/image-payload-sanitizer.ts +0 -167
- package/src/app-server/klaw-owned-tool-runtime-contract.test.ts +0 -456
- package/src/app-server/local-runtime-attribution.ts +0 -39
- package/src/app-server/managed-binary.test.ts +0 -139
- package/src/app-server/managed-binary.ts +0 -193
- package/src/app-server/models.test.ts +0 -246
- package/src/app-server/models.ts +0 -172
- package/src/app-server/native-hook-relay.test.ts +0 -271
- package/src/app-server/native-hook-relay.ts +0 -150
- package/src/app-server/native-subagent-task-mirror.test.ts +0 -573
- package/src/app-server/native-subagent-task-mirror.ts +0 -497
- package/src/app-server/outcome-fallback-runtime-contract.test.ts +0 -404
- package/src/app-server/plugin-activation.test.ts +0 -336
- 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.test.ts +0 -355
- package/src/app-server/plugin-inventory.ts +0 -357
- package/src/app-server/plugin-thread-config.test.ts +0 -865
- 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.test.ts +0 -75
- 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.test.ts +0 -202
- package/src/app-server/rate-limits.ts +0 -583
- package/src/app-server/request.ts +0 -73
- package/src/app-server/run-attempt.context-engine.test.ts +0 -1004
- package/src/app-server/run-attempt.test.ts +0 -9477
- package/src/app-server/run-attempt.ts +0 -4683
- package/src/app-server/run-attempt.vision-tools.test.ts +0 -35
- package/src/app-server/schema-normalization-runtime-contract.test.ts +0 -206
- package/src/app-server/session-binding.test.ts +0 -303
- package/src/app-server/session-binding.ts +0 -398
- package/src/app-server/session-history.ts +0 -44
- package/src/app-server/shared-client.test.ts +0 -589
- package/src/app-server/shared-client.ts +0 -289
- package/src/app-server/side-question.test.ts +0 -1175
- package/src/app-server/side-question.ts +0 -1007
- package/src/app-server/test-support.ts +0 -48
- package/src/app-server/thread-lifecycle.test.ts +0 -447
- package/src/app-server/thread-lifecycle.ts +0 -939
- package/src/app-server/thread-lifecycle.user-mcp-servers.test.ts +0 -442
- package/src/app-server/timeout.ts +0 -9
- package/src/app-server/tool-progress-normalization.ts +0 -77
- package/src/app-server/trajectory.test.ts +0 -205
- package/src/app-server/trajectory.ts +0 -365
- package/src/app-server/transcript-mirror.test.ts +0 -524
- package/src/app-server/transcript-mirror.ts +0 -208
- package/src/app-server/transcript-repair-runtime-contract.test.ts +0 -44
- package/src/app-server/transport-stdio.test.ts +0 -171
- package/src/app-server/transport-stdio.ts +0 -107
- package/src/app-server/transport-websocket.test.ts +0 -69
- package/src/app-server/transport-websocket.ts +0 -90
- package/src/app-server/transport.ts +0 -117
- package/src/app-server/user-input-bridge.test.ts +0 -249
- 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 -425
- package/src/command-handlers.ts +0 -2004
- package/src/command-rpc.test.ts +0 -16
- package/src/command-rpc.ts +0 -142
- package/src/commands.test.ts +0 -3312
- package/src/commands.ts +0 -65
- package/src/conversation-binding-data.ts +0 -124
- package/src/conversation-binding.test.ts +0 -599
- package/src/conversation-binding.ts +0 -561
- package/src/conversation-control.test.ts +0 -126
- package/src/conversation-control.ts +0 -303
- package/src/conversation-turn-collector.test.ts +0 -191
- package/src/conversation-turn-collector.ts +0 -186
- package/src/conversation-turn-input.test.ts +0 -141
- package/src/conversation-turn-input.ts +0 -106
- package/src/manifest.test.ts +0 -20
- 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.test.ts +0 -1741
- 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.test.ts +0 -180
- package/src/node-cli-sessions.ts +0 -711
- package/test-api.ts +0 -82
- package/tsconfig.json +0 -16
|
@@ -1,865 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { CodexAppInventoryCache } from "./app-inventory-cache.js";
|
|
3
|
-
import { CODEX_PLUGINS_MARKETPLACE_NAME } from "./config.js";
|
|
4
|
-
import {
|
|
5
|
-
buildCodexPluginThreadConfig,
|
|
6
|
-
buildCodexPluginThreadConfigInputFingerprint,
|
|
7
|
-
isCodexPluginThreadBindingStale,
|
|
8
|
-
mergeCodexThreadConfigs,
|
|
9
|
-
shouldBuildCodexPluginThreadConfig,
|
|
10
|
-
} from "./plugin-thread-config.js";
|
|
11
|
-
import type { v2 } from "./protocol.js";
|
|
12
|
-
|
|
13
|
-
describe("Codex plugin thread config", () => {
|
|
14
|
-
it("defaults destructive app access on for accessible migrated plugin apps", async () => {
|
|
15
|
-
const appCache = new CodexAppInventoryCache();
|
|
16
|
-
await appCache.refreshNow({
|
|
17
|
-
key: "runtime",
|
|
18
|
-
nowMs: 0,
|
|
19
|
-
request: async () => ({
|
|
20
|
-
data: [appInfo("google-calendar-app", true)],
|
|
21
|
-
nextCursor: null,
|
|
22
|
-
}),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const config = await buildCodexPluginThreadConfig({
|
|
26
|
-
pluginConfig: {
|
|
27
|
-
codexPlugins: {
|
|
28
|
-
enabled: true,
|
|
29
|
-
plugins: {
|
|
30
|
-
"google-calendar": {
|
|
31
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
32
|
-
pluginName: "google-calendar",
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
appCache,
|
|
38
|
-
appCacheKey: "runtime",
|
|
39
|
-
nowMs: 1,
|
|
40
|
-
request: async (method) => {
|
|
41
|
-
if (method === "plugin/list") {
|
|
42
|
-
return pluginList([pluginSummary("google-calendar", { installed: true, enabled: true })]);
|
|
43
|
-
}
|
|
44
|
-
if (method === "plugin/read") {
|
|
45
|
-
return pluginDetail(
|
|
46
|
-
"google-calendar",
|
|
47
|
-
[appSummary("google-calendar-app")],
|
|
48
|
-
["google-calendar"],
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
throw new Error(`unexpected request ${method}`);
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
expect(config.configPatch).toEqual({
|
|
56
|
-
apps: {
|
|
57
|
-
_default: {
|
|
58
|
-
enabled: false,
|
|
59
|
-
destructive_enabled: false,
|
|
60
|
-
open_world_enabled: false,
|
|
61
|
-
},
|
|
62
|
-
"google-calendar-app": {
|
|
63
|
-
enabled: true,
|
|
64
|
-
destructive_enabled: true,
|
|
65
|
-
open_world_enabled: true,
|
|
66
|
-
default_tools_approval_mode: "auto",
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
expect(config.policyContext.apps["google-calendar-app"]).toEqual({
|
|
71
|
-
configKey: "google-calendar",
|
|
72
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
73
|
-
pluginName: "google-calendar",
|
|
74
|
-
allowDestructiveActions: true,
|
|
75
|
-
mcpServerNames: ["google-calendar"],
|
|
76
|
-
});
|
|
77
|
-
expect(config.diagnostics).toStrictEqual([]);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("maps destructive app access from global and per-plugin policy", async () => {
|
|
81
|
-
const pluginOverrideDisabled = await buildReadyGoogleCalendarThreadConfig({
|
|
82
|
-
codexPlugins: {
|
|
83
|
-
enabled: true,
|
|
84
|
-
allow_destructive_actions: true,
|
|
85
|
-
plugins: {
|
|
86
|
-
"google-calendar": {
|
|
87
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
88
|
-
pluginName: "google-calendar",
|
|
89
|
-
allow_destructive_actions: false,
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const disabledApps = pluginOverrideDisabled.configPatch?.apps as
|
|
96
|
-
| Record<string, unknown>
|
|
97
|
-
| undefined;
|
|
98
|
-
expect(disabledApps?.["google-calendar-app"]).toEqual({
|
|
99
|
-
enabled: true,
|
|
100
|
-
destructive_enabled: false,
|
|
101
|
-
open_world_enabled: true,
|
|
102
|
-
default_tools_approval_mode: "auto",
|
|
103
|
-
});
|
|
104
|
-
expect(disabledApps?.["google-calendar-app"]).not.toHaveProperty("default_tools_enabled");
|
|
105
|
-
expect(disabledApps?.["google-calendar-app"]).not.toHaveProperty("tools");
|
|
106
|
-
expect(
|
|
107
|
-
pluginOverrideDisabled.policyContext.apps["google-calendar-app"]?.allowDestructiveActions,
|
|
108
|
-
).toBe(false);
|
|
109
|
-
|
|
110
|
-
const pluginOverrideEnabled = await buildReadyGoogleCalendarThreadConfig({
|
|
111
|
-
codexPlugins: {
|
|
112
|
-
enabled: true,
|
|
113
|
-
allow_destructive_actions: false,
|
|
114
|
-
plugins: {
|
|
115
|
-
"google-calendar": {
|
|
116
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
117
|
-
pluginName: "google-calendar",
|
|
118
|
-
allow_destructive_actions: true,
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const enabledApps = pluginOverrideEnabled.configPatch?.apps as
|
|
125
|
-
| Record<string, unknown>
|
|
126
|
-
| undefined;
|
|
127
|
-
expect(enabledApps?.["google-calendar-app"]).toEqual({
|
|
128
|
-
enabled: true,
|
|
129
|
-
destructive_enabled: true,
|
|
130
|
-
open_world_enabled: true,
|
|
131
|
-
default_tools_approval_mode: "auto",
|
|
132
|
-
});
|
|
133
|
-
expect(
|
|
134
|
-
pluginOverrideEnabled.policyContext.apps["google-calendar-app"]?.allowDestructiveActions,
|
|
135
|
-
).toBe(true);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("builds a restrictive app config when native plugin support is disabled", async () => {
|
|
139
|
-
expect(
|
|
140
|
-
shouldBuildCodexPluginThreadConfig({
|
|
141
|
-
codexPlugins: { enabled: false },
|
|
142
|
-
}),
|
|
143
|
-
).toBe(true);
|
|
144
|
-
|
|
145
|
-
const config = await buildCodexPluginThreadConfig({
|
|
146
|
-
pluginConfig: { codexPlugins: { enabled: false } },
|
|
147
|
-
appCacheKey: "runtime",
|
|
148
|
-
request: async (method) => {
|
|
149
|
-
throw new Error(`unexpected request ${method}`);
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
expect(config.enabled).toBe(false);
|
|
154
|
-
expect(config.configPatch).toEqual({
|
|
155
|
-
apps: {
|
|
156
|
-
_default: {
|
|
157
|
-
enabled: false,
|
|
158
|
-
destructive_enabled: false,
|
|
159
|
-
open_world_enabled: false,
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
});
|
|
163
|
-
expect(config.diagnostics).toStrictEqual([]);
|
|
164
|
-
expect(config.policyContext.apps).toStrictEqual({});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it("does not let per-plugin enablement override disabled native plugin support", async () => {
|
|
168
|
-
expect(
|
|
169
|
-
shouldBuildCodexPluginThreadConfig({
|
|
170
|
-
codexPlugins: {
|
|
171
|
-
enabled: false,
|
|
172
|
-
plugins: {
|
|
173
|
-
"google-calendar": {
|
|
174
|
-
enabled: true,
|
|
175
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
176
|
-
pluginName: "google-calendar",
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
}),
|
|
181
|
-
).toBe(true);
|
|
182
|
-
|
|
183
|
-
const config = await buildCodexPluginThreadConfig({
|
|
184
|
-
pluginConfig: {
|
|
185
|
-
codexPlugins: {
|
|
186
|
-
enabled: false,
|
|
187
|
-
plugins: {
|
|
188
|
-
"google-calendar": {
|
|
189
|
-
enabled: true,
|
|
190
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
191
|
-
pluginName: "google-calendar",
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
appCacheKey: "runtime",
|
|
197
|
-
request: async (method) => {
|
|
198
|
-
throw new Error(`unexpected request ${method}`);
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
expect(config.enabled).toBe(false);
|
|
203
|
-
expect(config.configPatch).toEqual({
|
|
204
|
-
apps: {
|
|
205
|
-
_default: {
|
|
206
|
-
enabled: false,
|
|
207
|
-
destructive_enabled: false,
|
|
208
|
-
open_world_enabled: false,
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
expect(config.policyContext.apps).toStrictEqual({});
|
|
213
|
-
expect(config.diagnostics).toStrictEqual([]);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it("waits for the initial app inventory before exposing plugin apps", async () => {
|
|
217
|
-
const appCache = new CodexAppInventoryCache();
|
|
218
|
-
const appListParams: v2.AppsListParams[] = [];
|
|
219
|
-
const request = vi.fn(async (method: string, params?: unknown) => {
|
|
220
|
-
if (method === "app/list") {
|
|
221
|
-
appListParams.push(params as v2.AppsListParams);
|
|
222
|
-
return { data: [appInfo("google-calendar-app", true)], nextCursor: null };
|
|
223
|
-
}
|
|
224
|
-
if (method === "plugin/list") {
|
|
225
|
-
return pluginList([pluginSummary("google-calendar", { installed: true, enabled: true })]);
|
|
226
|
-
}
|
|
227
|
-
if (method === "plugin/read") {
|
|
228
|
-
return pluginDetail("google-calendar", [appSummary("google-calendar-app")]);
|
|
229
|
-
}
|
|
230
|
-
throw new Error(`unexpected request ${method}`);
|
|
231
|
-
});
|
|
232
|
-
const config = await buildCodexPluginThreadConfig({
|
|
233
|
-
pluginConfig: {
|
|
234
|
-
codexPlugins: {
|
|
235
|
-
enabled: true,
|
|
236
|
-
plugins: {
|
|
237
|
-
"google-calendar": {
|
|
238
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
239
|
-
pluginName: "google-calendar",
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
},
|
|
243
|
-
},
|
|
244
|
-
appCache,
|
|
245
|
-
appCacheKey: "runtime",
|
|
246
|
-
request,
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
expect(config.configPatch).toEqual({
|
|
250
|
-
apps: {
|
|
251
|
-
_default: {
|
|
252
|
-
enabled: false,
|
|
253
|
-
destructive_enabled: false,
|
|
254
|
-
open_world_enabled: false,
|
|
255
|
-
},
|
|
256
|
-
"google-calendar-app": {
|
|
257
|
-
enabled: true,
|
|
258
|
-
destructive_enabled: true,
|
|
259
|
-
open_world_enabled: true,
|
|
260
|
-
default_tools_approval_mode: "auto",
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
});
|
|
264
|
-
expect(config.policyContext.apps["google-calendar-app"]).toEqual({
|
|
265
|
-
configKey: "google-calendar",
|
|
266
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
267
|
-
pluginName: "google-calendar",
|
|
268
|
-
allowDestructiveActions: true,
|
|
269
|
-
mcpServerNames: [],
|
|
270
|
-
});
|
|
271
|
-
expect(config.diagnostics).toStrictEqual([]);
|
|
272
|
-
expect(
|
|
273
|
-
request.mock.calls.reduce((count, [method]) => count + (method === "app/list" ? 1 : 0), 0),
|
|
274
|
-
).toBe(1);
|
|
275
|
-
expect(appListParams).toEqual([
|
|
276
|
-
{
|
|
277
|
-
cursor: undefined,
|
|
278
|
-
limit: 100,
|
|
279
|
-
forceRefetch: true,
|
|
280
|
-
},
|
|
281
|
-
]);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("does not expose plugin apps missing from the app inventory snapshot", async () => {
|
|
285
|
-
const appCache = new CodexAppInventoryCache();
|
|
286
|
-
await appCache.refreshNow({
|
|
287
|
-
key: "runtime",
|
|
288
|
-
nowMs: 0,
|
|
289
|
-
request: async () => ({
|
|
290
|
-
data: [],
|
|
291
|
-
nextCursor: null,
|
|
292
|
-
}),
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
const config = await buildCodexPluginThreadConfig({
|
|
296
|
-
pluginConfig: {
|
|
297
|
-
codexPlugins: {
|
|
298
|
-
enabled: true,
|
|
299
|
-
plugins: {
|
|
300
|
-
"google-calendar": {
|
|
301
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
302
|
-
pluginName: "google-calendar",
|
|
303
|
-
},
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
appCache,
|
|
308
|
-
appCacheKey: "runtime",
|
|
309
|
-
nowMs: 1,
|
|
310
|
-
request: async (method) => {
|
|
311
|
-
if (method === "plugin/list") {
|
|
312
|
-
return pluginList([pluginSummary("google-calendar", { installed: true, enabled: true })]);
|
|
313
|
-
}
|
|
314
|
-
if (method === "plugin/read") {
|
|
315
|
-
return pluginDetail("google-calendar", [appSummary("google-calendar-app")]);
|
|
316
|
-
}
|
|
317
|
-
throw new Error(`unexpected request ${method}`);
|
|
318
|
-
},
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
expect(config.configPatch).toEqual({
|
|
322
|
-
apps: {
|
|
323
|
-
_default: {
|
|
324
|
-
enabled: false,
|
|
325
|
-
destructive_enabled: false,
|
|
326
|
-
open_world_enabled: false,
|
|
327
|
-
},
|
|
328
|
-
},
|
|
329
|
-
});
|
|
330
|
-
expect(config.policyContext.apps).toStrictEqual({});
|
|
331
|
-
expect(config.diagnostics).toStrictEqual([
|
|
332
|
-
{
|
|
333
|
-
code: "app_not_ready",
|
|
334
|
-
plugin: {
|
|
335
|
-
configKey: "google-calendar",
|
|
336
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
337
|
-
pluginName: "google-calendar",
|
|
338
|
-
enabled: true,
|
|
339
|
-
allowDestructiveActions: true,
|
|
340
|
-
},
|
|
341
|
-
message: "google-calendar-app is not accessible or enabled for google-calendar.",
|
|
342
|
-
},
|
|
343
|
-
]);
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
it("force-refreshes app inventory when proven plugin apps are not ready", async () => {
|
|
347
|
-
const appCache = new CodexAppInventoryCache();
|
|
348
|
-
await appCache.refreshNow({
|
|
349
|
-
key: "runtime",
|
|
350
|
-
nowMs: 0,
|
|
351
|
-
request: async () => ({
|
|
352
|
-
data: [],
|
|
353
|
-
nextCursor: null,
|
|
354
|
-
}),
|
|
355
|
-
});
|
|
356
|
-
const appListParams: v2.AppsListParams[] = [];
|
|
357
|
-
const request = vi.fn(async (method: string, params?: unknown) => {
|
|
358
|
-
if (method === "plugin/list") {
|
|
359
|
-
return pluginList([pluginSummary("google-calendar", { installed: true, enabled: true })]);
|
|
360
|
-
}
|
|
361
|
-
if (method === "plugin/read") {
|
|
362
|
-
return pluginDetail("google-calendar", [appSummary("google-calendar-app")]);
|
|
363
|
-
}
|
|
364
|
-
if (method === "app/list") {
|
|
365
|
-
appListParams.push(params as v2.AppsListParams);
|
|
366
|
-
return {
|
|
367
|
-
data: [appInfo("google-calendar-app", true)],
|
|
368
|
-
nextCursor: null,
|
|
369
|
-
} satisfies v2.AppsListResponse;
|
|
370
|
-
}
|
|
371
|
-
throw new Error(`unexpected request ${method}`);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
const config = await buildCodexPluginThreadConfig({
|
|
375
|
-
pluginConfig: {
|
|
376
|
-
codexPlugins: {
|
|
377
|
-
enabled: true,
|
|
378
|
-
plugins: {
|
|
379
|
-
"google-calendar": {
|
|
380
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
381
|
-
pluginName: "google-calendar",
|
|
382
|
-
},
|
|
383
|
-
},
|
|
384
|
-
},
|
|
385
|
-
},
|
|
386
|
-
appCache,
|
|
387
|
-
appCacheKey: "runtime",
|
|
388
|
-
nowMs: 1,
|
|
389
|
-
request,
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
expect(config.configPatch?.apps).toEqual({
|
|
393
|
-
_default: {
|
|
394
|
-
enabled: false,
|
|
395
|
-
destructive_enabled: false,
|
|
396
|
-
open_world_enabled: false,
|
|
397
|
-
},
|
|
398
|
-
"google-calendar-app": {
|
|
399
|
-
enabled: true,
|
|
400
|
-
destructive_enabled: true,
|
|
401
|
-
open_world_enabled: true,
|
|
402
|
-
default_tools_approval_mode: "auto",
|
|
403
|
-
},
|
|
404
|
-
});
|
|
405
|
-
expect(config.policyContext.apps["google-calendar-app"]).toEqual({
|
|
406
|
-
configKey: "google-calendar",
|
|
407
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
408
|
-
pluginName: "google-calendar",
|
|
409
|
-
allowDestructiveActions: true,
|
|
410
|
-
mcpServerNames: [],
|
|
411
|
-
});
|
|
412
|
-
expect(config.diagnostics).toStrictEqual([]);
|
|
413
|
-
expect(appListParams).toEqual([
|
|
414
|
-
{
|
|
415
|
-
cursor: undefined,
|
|
416
|
-
limit: 100,
|
|
417
|
-
forceRefetch: true,
|
|
418
|
-
},
|
|
419
|
-
]);
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
it("re-reads app readiness after re-enabling an installed plugin", async () => {
|
|
423
|
-
const appCache = new CodexAppInventoryCache();
|
|
424
|
-
await appCache.refreshNow({
|
|
425
|
-
key: "runtime",
|
|
426
|
-
nowMs: 0,
|
|
427
|
-
request: async () => ({
|
|
428
|
-
data: [appInfo("google-calendar-app", true, false)],
|
|
429
|
-
nextCursor: null,
|
|
430
|
-
}),
|
|
431
|
-
});
|
|
432
|
-
let enabled = false;
|
|
433
|
-
const appListParams: v2.AppsListParams[] = [];
|
|
434
|
-
const request = vi.fn(async (method: string, params?: unknown) => {
|
|
435
|
-
if (method === "plugin/list") {
|
|
436
|
-
return pluginList([pluginSummary("google-calendar", { installed: true, enabled })]);
|
|
437
|
-
}
|
|
438
|
-
if (method === "plugin/read") {
|
|
439
|
-
return pluginDetail("google-calendar", [appSummary("google-calendar-app")]);
|
|
440
|
-
}
|
|
441
|
-
if (method === "plugin/install") {
|
|
442
|
-
enabled = true;
|
|
443
|
-
return { authPolicy: "ON_USE", appsNeedingAuth: [] } satisfies v2.PluginInstallResponse;
|
|
444
|
-
}
|
|
445
|
-
if (method === "skills/list") {
|
|
446
|
-
return { data: [] } satisfies v2.SkillsListResponse;
|
|
447
|
-
}
|
|
448
|
-
if (method === "hooks/list") {
|
|
449
|
-
return { data: [] } satisfies v2.HooksListResponse;
|
|
450
|
-
}
|
|
451
|
-
if (method === "config/mcpServer/reload") {
|
|
452
|
-
return {};
|
|
453
|
-
}
|
|
454
|
-
if (method === "app/list") {
|
|
455
|
-
appListParams.push(params as v2.AppsListParams);
|
|
456
|
-
return {
|
|
457
|
-
data: [appInfo("google-calendar-app", true, enabled)],
|
|
458
|
-
nextCursor: null,
|
|
459
|
-
} satisfies v2.AppsListResponse;
|
|
460
|
-
}
|
|
461
|
-
throw new Error(`unexpected request ${method}`);
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
const config = await buildCodexPluginThreadConfig({
|
|
465
|
-
pluginConfig: {
|
|
466
|
-
codexPlugins: {
|
|
467
|
-
enabled: true,
|
|
468
|
-
plugins: {
|
|
469
|
-
"google-calendar": {
|
|
470
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
471
|
-
pluginName: "google-calendar",
|
|
472
|
-
},
|
|
473
|
-
},
|
|
474
|
-
},
|
|
475
|
-
},
|
|
476
|
-
appCache,
|
|
477
|
-
appCacheKey: "runtime",
|
|
478
|
-
nowMs: 1,
|
|
479
|
-
request,
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
expect(config.configPatch?.apps).toEqual({
|
|
483
|
-
_default: {
|
|
484
|
-
enabled: false,
|
|
485
|
-
destructive_enabled: false,
|
|
486
|
-
open_world_enabled: false,
|
|
487
|
-
},
|
|
488
|
-
"google-calendar-app": {
|
|
489
|
-
enabled: true,
|
|
490
|
-
destructive_enabled: true,
|
|
491
|
-
open_world_enabled: true,
|
|
492
|
-
default_tools_approval_mode: "auto",
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
expect(config.policyContext.apps["google-calendar-app"]).toEqual({
|
|
496
|
-
configKey: "google-calendar",
|
|
497
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
498
|
-
pluginName: "google-calendar",
|
|
499
|
-
allowDestructiveActions: true,
|
|
500
|
-
mcpServerNames: [],
|
|
501
|
-
});
|
|
502
|
-
expect(config.diagnostics).toStrictEqual([]);
|
|
503
|
-
expect(request.mock.calls.map(([method]) => method)).toEqual([
|
|
504
|
-
"plugin/list",
|
|
505
|
-
"plugin/read",
|
|
506
|
-
"plugin/list",
|
|
507
|
-
"plugin/install",
|
|
508
|
-
"plugin/list",
|
|
509
|
-
"skills/list",
|
|
510
|
-
"hooks/list",
|
|
511
|
-
"config/mcpServer/reload",
|
|
512
|
-
"app/list",
|
|
513
|
-
"app/list",
|
|
514
|
-
"plugin/list",
|
|
515
|
-
"plugin/read",
|
|
516
|
-
]);
|
|
517
|
-
expect(appListParams).toEqual([
|
|
518
|
-
{
|
|
519
|
-
cursor: undefined,
|
|
520
|
-
limit: 100,
|
|
521
|
-
forceRefetch: true,
|
|
522
|
-
},
|
|
523
|
-
{
|
|
524
|
-
cursor: undefined,
|
|
525
|
-
limit: 100,
|
|
526
|
-
forceRefetch: true,
|
|
527
|
-
},
|
|
528
|
-
]);
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
it("surfaces critical post-install refresh failures and keeps plugin apps disabled", async () => {
|
|
532
|
-
const appCache = new CodexAppInventoryCache();
|
|
533
|
-
await appCache.refreshNow({
|
|
534
|
-
key: "runtime",
|
|
535
|
-
nowMs: 0,
|
|
536
|
-
request: async () => ({
|
|
537
|
-
data: [appInfo("google-calendar-app", true)],
|
|
538
|
-
nextCursor: null,
|
|
539
|
-
}),
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
const config = await buildCodexPluginThreadConfig({
|
|
543
|
-
pluginConfig: {
|
|
544
|
-
codexPlugins: {
|
|
545
|
-
enabled: true,
|
|
546
|
-
plugins: {
|
|
547
|
-
"google-calendar": {
|
|
548
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
549
|
-
pluginName: "google-calendar",
|
|
550
|
-
},
|
|
551
|
-
},
|
|
552
|
-
},
|
|
553
|
-
},
|
|
554
|
-
appCache,
|
|
555
|
-
appCacheKey: "runtime",
|
|
556
|
-
nowMs: 1,
|
|
557
|
-
request: async (method) => {
|
|
558
|
-
if (method === "plugin/list") {
|
|
559
|
-
return pluginList([
|
|
560
|
-
pluginSummary("google-calendar", { installed: false, enabled: false }),
|
|
561
|
-
]);
|
|
562
|
-
}
|
|
563
|
-
if (method === "plugin/read") {
|
|
564
|
-
return pluginDetail("google-calendar", [appSummary("google-calendar-app")]);
|
|
565
|
-
}
|
|
566
|
-
if (method === "plugin/install") {
|
|
567
|
-
return { authPolicy: "ON_USE", appsNeedingAuth: [] } satisfies v2.PluginInstallResponse;
|
|
568
|
-
}
|
|
569
|
-
if (method === "skills/list") {
|
|
570
|
-
throw new Error("skills/list unavailable");
|
|
571
|
-
}
|
|
572
|
-
throw new Error(`unexpected request ${method}`);
|
|
573
|
-
},
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
expect(config.configPatch).toEqual({
|
|
577
|
-
apps: {
|
|
578
|
-
_default: {
|
|
579
|
-
enabled: false,
|
|
580
|
-
destructive_enabled: false,
|
|
581
|
-
open_world_enabled: false,
|
|
582
|
-
},
|
|
583
|
-
},
|
|
584
|
-
});
|
|
585
|
-
expect(config.policyContext.apps).toStrictEqual({});
|
|
586
|
-
expect(config.diagnostics).toHaveLength(1);
|
|
587
|
-
expect(config.diagnostics[0]?.code).toBe("plugin_activation_failed");
|
|
588
|
-
expect(config.diagnostics[0]?.message).toBe(
|
|
589
|
-
"Codex plugin runtime refresh failed after install: skills/list unavailable",
|
|
590
|
-
);
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
it("fails closed when the initial app inventory refresh fails", async () => {
|
|
594
|
-
const appCache = new CodexAppInventoryCache();
|
|
595
|
-
const config = await buildCodexPluginThreadConfig({
|
|
596
|
-
pluginConfig: {
|
|
597
|
-
codexPlugins: {
|
|
598
|
-
enabled: true,
|
|
599
|
-
plugins: {
|
|
600
|
-
"google-calendar": {
|
|
601
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
602
|
-
pluginName: "google-calendar",
|
|
603
|
-
},
|
|
604
|
-
},
|
|
605
|
-
},
|
|
606
|
-
},
|
|
607
|
-
appCache,
|
|
608
|
-
appCacheKey: "runtime",
|
|
609
|
-
request: async (method) => {
|
|
610
|
-
if (method === "app/list") {
|
|
611
|
-
throw new Error("app/list unavailable");
|
|
612
|
-
}
|
|
613
|
-
if (method === "plugin/list") {
|
|
614
|
-
return pluginList([pluginSummary("google-calendar", { installed: true, enabled: true })]);
|
|
615
|
-
}
|
|
616
|
-
if (method === "plugin/read") {
|
|
617
|
-
return pluginDetail("google-calendar", [appSummary("google-calendar-app")]);
|
|
618
|
-
}
|
|
619
|
-
throw new Error(`unexpected request ${method}`);
|
|
620
|
-
},
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
expect(config.configPatch).toEqual({
|
|
624
|
-
apps: {
|
|
625
|
-
_default: {
|
|
626
|
-
enabled: false,
|
|
627
|
-
destructive_enabled: false,
|
|
628
|
-
open_world_enabled: false,
|
|
629
|
-
},
|
|
630
|
-
},
|
|
631
|
-
});
|
|
632
|
-
expect(config.policyContext.apps).toStrictEqual({});
|
|
633
|
-
expect(config.policyContext.pluginAppIds).toStrictEqual({
|
|
634
|
-
"google-calendar": ["google-calendar-app"],
|
|
635
|
-
});
|
|
636
|
-
expect(config.diagnostics.map((diagnostic) => diagnostic.code)).toStrictEqual([
|
|
637
|
-
"app_inventory_missing",
|
|
638
|
-
]);
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
it("uses durable policy and app cache key in the cheap input fingerprint", async () => {
|
|
642
|
-
const appCache = new CodexAppInventoryCache();
|
|
643
|
-
const first = buildCodexPluginThreadConfigInputFingerprint({
|
|
644
|
-
pluginConfig: { codexPlugins: { enabled: true } },
|
|
645
|
-
appCacheKey: "runtime-a",
|
|
646
|
-
});
|
|
647
|
-
await appCache.refreshNow({
|
|
648
|
-
key: "runtime-a",
|
|
649
|
-
request: async () => ({ data: [], nextCursor: null }),
|
|
650
|
-
});
|
|
651
|
-
const second = buildCodexPluginThreadConfigInputFingerprint({
|
|
652
|
-
pluginConfig: { codexPlugins: { enabled: true } },
|
|
653
|
-
appCacheKey: "runtime-a",
|
|
654
|
-
});
|
|
655
|
-
const third = buildCodexPluginThreadConfigInputFingerprint({
|
|
656
|
-
pluginConfig: { codexPlugins: { enabled: true } },
|
|
657
|
-
appCacheKey: "runtime-b",
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
expect(second).toBe(first);
|
|
661
|
-
expect(third).not.toBe(second);
|
|
662
|
-
});
|
|
663
|
-
|
|
664
|
-
it("uses app-level destructive policy for plugins without Klaw tool-name knowledge", async () => {
|
|
665
|
-
const appCache = new CodexAppInventoryCache();
|
|
666
|
-
await appCache.refreshNow({
|
|
667
|
-
key: "runtime",
|
|
668
|
-
nowMs: 0,
|
|
669
|
-
request: async () => ({
|
|
670
|
-
data: [appInfo("github-app", true)],
|
|
671
|
-
nextCursor: null,
|
|
672
|
-
}),
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
const config = await buildCodexPluginThreadConfig({
|
|
676
|
-
pluginConfig: {
|
|
677
|
-
codexPlugins: {
|
|
678
|
-
enabled: true,
|
|
679
|
-
allow_destructive_actions: false,
|
|
680
|
-
plugins: {
|
|
681
|
-
github: {
|
|
682
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
683
|
-
pluginName: "github",
|
|
684
|
-
},
|
|
685
|
-
},
|
|
686
|
-
},
|
|
687
|
-
},
|
|
688
|
-
appCache,
|
|
689
|
-
appCacheKey: "runtime",
|
|
690
|
-
nowMs: 1,
|
|
691
|
-
request: async (method) => {
|
|
692
|
-
if (method === "plugin/list") {
|
|
693
|
-
return pluginList([pluginSummary("github", { installed: true, enabled: true })]);
|
|
694
|
-
}
|
|
695
|
-
if (method === "plugin/read") {
|
|
696
|
-
return pluginDetail("github", [appSummary("github-app")], ["github"]);
|
|
697
|
-
}
|
|
698
|
-
throw new Error(`unexpected request ${method}`);
|
|
699
|
-
},
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
const apps = config.configPatch?.apps as Record<string, unknown> | undefined;
|
|
703
|
-
expect(apps?.["github-app"]).toEqual({
|
|
704
|
-
enabled: true,
|
|
705
|
-
destructive_enabled: false,
|
|
706
|
-
open_world_enabled: true,
|
|
707
|
-
default_tools_approval_mode: "auto",
|
|
708
|
-
});
|
|
709
|
-
expect(apps?.["github-app"]).not.toHaveProperty("tools");
|
|
710
|
-
});
|
|
711
|
-
|
|
712
|
-
it("merges app config with native hook config", () => {
|
|
713
|
-
expect(
|
|
714
|
-
mergeCodexThreadConfigs(
|
|
715
|
-
{ "features.hooks": true, hooks: { PreToolUse: [] } },
|
|
716
|
-
{ apps: { _default: { enabled: false } } },
|
|
717
|
-
),
|
|
718
|
-
).toEqual({
|
|
719
|
-
"features.hooks": true,
|
|
720
|
-
hooks: { PreToolUse: [] },
|
|
721
|
-
apps: { _default: { enabled: false } },
|
|
722
|
-
});
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
it("marks missing and changed plugin app bindings stale only when relevant", () => {
|
|
726
|
-
expect(
|
|
727
|
-
isCodexPluginThreadBindingStale({
|
|
728
|
-
codexPluginsEnabled: true,
|
|
729
|
-
currentInputFingerprint: "input-2",
|
|
730
|
-
}),
|
|
731
|
-
).toBe(true);
|
|
732
|
-
expect(
|
|
733
|
-
isCodexPluginThreadBindingStale({
|
|
734
|
-
codexPluginsEnabled: true,
|
|
735
|
-
bindingFingerprint: "config-1",
|
|
736
|
-
bindingInputFingerprint: "input-1",
|
|
737
|
-
currentInputFingerprint: "input-2",
|
|
738
|
-
hasBindingPolicyContext: true,
|
|
739
|
-
}),
|
|
740
|
-
).toBe(true);
|
|
741
|
-
expect(
|
|
742
|
-
isCodexPluginThreadBindingStale({
|
|
743
|
-
codexPluginsEnabled: true,
|
|
744
|
-
bindingFingerprint: "config-1",
|
|
745
|
-
bindingInputFingerprint: "input-1",
|
|
746
|
-
currentInputFingerprint: "input-1",
|
|
747
|
-
hasBindingPolicyContext: true,
|
|
748
|
-
}),
|
|
749
|
-
).toBe(false);
|
|
750
|
-
expect(
|
|
751
|
-
isCodexPluginThreadBindingStale({
|
|
752
|
-
codexPluginsEnabled: false,
|
|
753
|
-
bindingFingerprint: "config-1",
|
|
754
|
-
bindingInputFingerprint: "input-1",
|
|
755
|
-
hasBindingPolicyContext: true,
|
|
756
|
-
}),
|
|
757
|
-
).toBe(true);
|
|
758
|
-
});
|
|
759
|
-
});
|
|
760
|
-
|
|
761
|
-
function pluginList(plugins: v2.PluginSummary[]): v2.PluginListResponse {
|
|
762
|
-
return {
|
|
763
|
-
marketplaces: [
|
|
764
|
-
{
|
|
765
|
-
name: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
766
|
-
path: "/marketplaces/openai-curated",
|
|
767
|
-
interface: null,
|
|
768
|
-
plugins,
|
|
769
|
-
},
|
|
770
|
-
],
|
|
771
|
-
marketplaceLoadErrors: [],
|
|
772
|
-
featuredPluginIds: [],
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
function pluginSummary(id: string, overrides: Partial<v2.PluginSummary> = {}): v2.PluginSummary {
|
|
777
|
-
return {
|
|
778
|
-
id,
|
|
779
|
-
name: id,
|
|
780
|
-
source: { type: "remote" },
|
|
781
|
-
installed: false,
|
|
782
|
-
enabled: false,
|
|
783
|
-
installPolicy: "AVAILABLE",
|
|
784
|
-
authPolicy: "ON_USE",
|
|
785
|
-
availability: "AVAILABLE",
|
|
786
|
-
interface: null,
|
|
787
|
-
...overrides,
|
|
788
|
-
};
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
function pluginDetail(
|
|
792
|
-
pluginName: string,
|
|
793
|
-
apps: v2.AppSummary[],
|
|
794
|
-
mcpServers: string[] = [],
|
|
795
|
-
): v2.PluginReadResponse {
|
|
796
|
-
return {
|
|
797
|
-
plugin: {
|
|
798
|
-
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
799
|
-
marketplacePath: "/marketplaces/openai-curated",
|
|
800
|
-
summary: pluginSummary(pluginName, { installed: true, enabled: true }),
|
|
801
|
-
description: null,
|
|
802
|
-
skills: [],
|
|
803
|
-
apps,
|
|
804
|
-
mcpServers,
|
|
805
|
-
},
|
|
806
|
-
};
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
function appSummary(id: string): v2.AppSummary {
|
|
810
|
-
return {
|
|
811
|
-
id,
|
|
812
|
-
name: id,
|
|
813
|
-
description: null,
|
|
814
|
-
installUrl: null,
|
|
815
|
-
needsAuth: false,
|
|
816
|
-
};
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
function appInfo(id: string, accessible: boolean, enabled = true): v2.AppInfo {
|
|
820
|
-
return {
|
|
821
|
-
id,
|
|
822
|
-
name: id,
|
|
823
|
-
description: null,
|
|
824
|
-
logoUrl: null,
|
|
825
|
-
logoUrlDark: null,
|
|
826
|
-
distributionChannel: null,
|
|
827
|
-
branding: null,
|
|
828
|
-
appMetadata: null,
|
|
829
|
-
labels: null,
|
|
830
|
-
installUrl: null,
|
|
831
|
-
isAccessible: accessible,
|
|
832
|
-
isEnabled: enabled,
|
|
833
|
-
pluginDisplayNames: [],
|
|
834
|
-
};
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
async function buildReadyGoogleCalendarThreadConfig(
|
|
838
|
-
pluginConfig: unknown,
|
|
839
|
-
): Promise<Awaited<ReturnType<typeof buildCodexPluginThreadConfig>>> {
|
|
840
|
-
const appCache = new CodexAppInventoryCache();
|
|
841
|
-
await appCache.refreshNow({
|
|
842
|
-
key: "runtime",
|
|
843
|
-
nowMs: 0,
|
|
844
|
-
request: async () => ({
|
|
845
|
-
data: [appInfo("google-calendar-app", true)],
|
|
846
|
-
nextCursor: null,
|
|
847
|
-
}),
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
return buildCodexPluginThreadConfig({
|
|
851
|
-
pluginConfig,
|
|
852
|
-
appCache,
|
|
853
|
-
appCacheKey: "runtime",
|
|
854
|
-
nowMs: 1,
|
|
855
|
-
request: async (method) => {
|
|
856
|
-
if (method === "plugin/list") {
|
|
857
|
-
return pluginList([pluginSummary("google-calendar", { installed: true, enabled: true })]);
|
|
858
|
-
}
|
|
859
|
-
if (method === "plugin/read") {
|
|
860
|
-
return pluginDetail("google-calendar", [appSummary("google-calendar-app")]);
|
|
861
|
-
}
|
|
862
|
-
throw new Error(`unexpected request ${method}`);
|
|
863
|
-
},
|
|
864
|
-
});
|
|
865
|
-
}
|