@openclaw/copilot 2026.5.28

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.
@@ -0,0 +1,30 @@
1
+ //#region extensions/copilot/doctor-contract-api.ts
2
+ const legacyConfigRules = [];
3
+ function normalizeCompatibilityConfig({ cfg }) {
4
+ return {
5
+ config: cfg,
6
+ changes: []
7
+ };
8
+ }
9
+ /**
10
+ * Session-state ownership claim for the copilot agent runtime.
11
+ *
12
+ * - id / label: Identify the extension in doctor output.
13
+ * - providerIds: The subscription Copilot providers (kept in sync
14
+ * with `SUPPORTED_PROVIDERS` in attempt.ts).
15
+ * - runtimeIds: Our harness id (matches harness.ts `id` field).
16
+ * - cliSessionKeys: Session keys this harness writes; doctor uses
17
+ * this when pruning stale CLI session state.
18
+ * - authProfilePrefixes: Conventional prefix for any auth profile
19
+ * created/consumed by this extension.
20
+ */
21
+ const sessionRouteStateOwners = [{
22
+ id: "copilot",
23
+ label: "GitHub Copilot agent runtime",
24
+ providerIds: ["github-copilot"],
25
+ runtimeIds: ["copilot"],
26
+ cliSessionKeys: ["copilot"],
27
+ authProfilePrefixes: ["github-copilot:"]
28
+ }];
29
+ //#endregion
30
+ export { legacyConfigRules, normalizeCompatibilityConfig, sessionRouteStateOwners };
@@ -0,0 +1,473 @@
1
+ import { createHash } from "node:crypto";
2
+ import { homedir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+ import { mkdir, writeFile } from "node:fs/promises";
5
+ //#region extensions/copilot/src/auth-bridge.ts
6
+ /**
7
+ * Pure functional auth resolver for the copilot agent runtime.
8
+ *
9
+ * Scope:
10
+ *
11
+ * - Consumes the resolved auth signals that core's harness contract
12
+ * already carries on `EmbeddedRunAttemptParams` (=
13
+ * `AgentHarnessAttemptParams`): `resolvedApiKey`, `authProfileId`,
14
+ * `authProfileIdSource`. Core resolves these from the agent's
15
+ * `AuthProfileStore` via `provider-usage.auth.ts:resolveProviderAuths`
16
+ * before invoking the harness, so the harness does not re-perform
17
+ * the lookup (and could not, due to the package boundary in
18
+ * `tsconfig.package-boundary.base.json`).
19
+ * - Reads optional explicit overrides from the harness attempt params
20
+ * (`auth.useLoggedInUser`, `auth.gitHubToken`) for direct CLI / test
21
+ * use cases.
22
+ * - Falls back to OPENCLAW_GITHUB_TOKEN, COPILOT_GITHUB_TOKEN,
23
+ * GH_TOKEN, or GITHUB_TOKEN env vars (in that precedence) when
24
+ * no contract-resolved token is given; synthesises a stable,
25
+ * non-reversible pool fingerprint so token rotation busts the
26
+ * client pool cleanly.
27
+ * - Computes a per-agent `copilotHome` default
28
+ * (`<openClawHome>/.openclaw/agents/<agentId>/copilot`, or
29
+ * `<agentDir>/copilot` when an agent directory is supplied) that
30
+ * respects `OPENCLAW_HOME` for the home directory root.
31
+ * - Defaults to `useLoggedInUser` when no token signal is available.
32
+ *
33
+ * Precedence (highest to lowest):
34
+ * 1. `auth.useLoggedInUser === true` (explicit user opt-in)
35
+ * 2. `auth.gitHubToken` (explicit override; requires
36
+ * `profileId` + `profileVersion`)
37
+ * 3. `resolvedApiKey` + `authProfileId` from the contract (core's
38
+ * AuthProfileStore-resolved token — the production main path for
39
+ * a configured `github-copilot` auth profile)
40
+ * 4. OPENCLAW_GITHUB_TOKEN, then COPILOT_GITHUB_TOKEN, then
41
+ * GH_TOKEN, then GITHUB_TOKEN env vars (mirrors the
42
+ * shipped `github-copilot` provider precedence so headless
43
+ * users who already follow the documented
44
+ * COPILOT_GITHUB_TOKEN / GH_TOKEN setup get the token they
45
+ * configured rather than silently falling through to the
46
+ * logged-in CLI user.)
47
+ * 5. `useLoggedInUser` (default)
48
+ */
49
+ const COPILOT_TOKEN_PROFILE_ERROR = "[copilot-attempt] gitHubToken auth requires profileId+profileVersion (pool keying safety; per Q5/Q1 decisions)";
50
+ const COPILOT_DEFAULT_AGENT_ID = "copilot";
51
+ /**
52
+ * Resolve copilot auth + copilotHome.
53
+ *
54
+ * Synchronous because we intentionally do not perform any I/O or
55
+ * cross-package credential lookups here (see file header for rationale).
56
+ *
57
+ * Throws if `gitHubToken` is supplied via `params.auth.gitHubToken`
58
+ * WITHOUT both `profileId` and `profileVersion` (the existing invariant
59
+ * from attempt.ts; preserves pool-key safety per Q5/Q1).
60
+ */
61
+ function resolveCopilotAuth(input) {
62
+ const env = input.env ?? process.env;
63
+ const homeDir = input.homeDir ?? homedir;
64
+ const agentId = sanitizeAgentId(input.agentId);
65
+ const copilotHome = resolveCopilotHome({
66
+ explicit: readString(input.copilotHome),
67
+ agentDir: readString(input.agentDir),
68
+ workspaceDir: readString(input.workspaceDir),
69
+ agentId,
70
+ env,
71
+ homeDir
72
+ });
73
+ const explicitToken = readString(input.auth?.gitHubToken);
74
+ const explicitProfileId = readString(input.auth?.profileId) ?? readString(input.authProfileId);
75
+ const explicitProfileVersion = readString(input.auth?.profileVersion) ?? readString(input.profileVersion);
76
+ if (input.auth?.useLoggedInUser === true) return {
77
+ authMode: "useLoggedInUser",
78
+ copilotHome,
79
+ agentId
80
+ };
81
+ if (explicitToken) {
82
+ if (!explicitProfileId || !explicitProfileVersion) throw new Error(COPILOT_TOKEN_PROFILE_ERROR);
83
+ return {
84
+ authMode: "gitHubToken",
85
+ gitHubToken: explicitToken,
86
+ authProfileId: explicitProfileId,
87
+ authProfileVersion: explicitProfileVersion,
88
+ copilotHome,
89
+ agentId
90
+ };
91
+ }
92
+ const contractToken = readString(input.resolvedApiKey);
93
+ if (contractToken) return {
94
+ authMode: "gitHubToken",
95
+ gitHubToken: contractToken,
96
+ authProfileId: readString(input.authProfileId) ?? "pi:resolved",
97
+ authProfileVersion: tokenFingerprint(contractToken),
98
+ copilotHome,
99
+ agentId
100
+ };
101
+ const envFallback = readEnvTokenFallback(env);
102
+ if (envFallback) return {
103
+ authMode: "gitHubToken",
104
+ gitHubToken: envFallback.token,
105
+ authProfileId: envFallback.profileId,
106
+ authProfileVersion: envFallback.profileVersion,
107
+ copilotHome,
108
+ agentId
109
+ };
110
+ return {
111
+ authMode: "useLoggedInUser",
112
+ copilotHome,
113
+ agentId
114
+ };
115
+ }
116
+ /**
117
+ * Validate + sanitise an agent id for use in filesystem paths and pool
118
+ * keys.
119
+ *
120
+ * Mirrors the shape constraints documented by core's `normalizeAgentId`
121
+ * / `isValidAgentId` in `src/routing/session-key.ts` (alnum + `-_`,
122
+ * starts with alnum, lowercase, <=64 chars). We re-implement here
123
+ * because the package boundary prevents importing from `src/`. Any
124
+ * caller that passes an invalid id falls back to the shared default
125
+ * (`COPILOT_DEFAULT_AGENT_ID`) rather than throwing - the harness's
126
+ * job is to keep running with a safe default, not to validate config.
127
+ */
128
+ function sanitizeAgentId(value) {
129
+ const trimmed = (value ?? "").trim().toLowerCase();
130
+ if (!trimmed) return COPILOT_DEFAULT_AGENT_ID;
131
+ if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(trimmed)) return COPILOT_DEFAULT_AGENT_ID;
132
+ return trimmed;
133
+ }
134
+ function resolveCopilotHome(args) {
135
+ if (args.explicit) return resolve(args.explicit);
136
+ if (args.agentDir) return resolve(join(args.agentDir, "copilot"));
137
+ const openClawHome = readString(args.env.OPENCLAW_HOME);
138
+ return resolve(join(openClawHome ? resolve(openClawHome) : safeHomeDir(args.homeDir), ".openclaw", "agents", args.agentId, "copilot"));
139
+ }
140
+ function safeHomeDir(homeDir) {
141
+ try {
142
+ const value = homeDir();
143
+ if (typeof value === "string" && value.length > 0) return value;
144
+ } catch {}
145
+ return process.cwd();
146
+ }
147
+ function readEnvTokenFallback(env) {
148
+ const candidates = [
149
+ {
150
+ name: "OPENCLAW_GITHUB_TOKEN",
151
+ value: readString(env.OPENCLAW_GITHUB_TOKEN)
152
+ },
153
+ {
154
+ name: "COPILOT_GITHUB_TOKEN",
155
+ value: readString(env.COPILOT_GITHUB_TOKEN)
156
+ },
157
+ {
158
+ name: "GH_TOKEN",
159
+ value: readString(env.GH_TOKEN)
160
+ },
161
+ {
162
+ name: "GITHUB_TOKEN",
163
+ value: readString(env.GITHUB_TOKEN)
164
+ }
165
+ ];
166
+ for (const { name, value } of candidates) if (value) return {
167
+ token: value,
168
+ profileId: `env:${name}`,
169
+ profileVersion: tokenFingerprint(value)
170
+ };
171
+ }
172
+ /**
173
+ * Non-reversible 12-hex-char fingerprint of a token, prefixed with
174
+ * `sha256:` for forward-compat. Used as the pool-key profileVersion when
175
+ * a token comes from env: rotation -> different fingerprint -> pool
176
+ * entry invalidated cleanly. 48 bits of entropy is sufficient
177
+ * collision resistance for a per-agent client pool; never log the
178
+ * fingerprint alongside an account id.
179
+ */
180
+ function tokenFingerprint(token) {
181
+ return `sha256:${createHash("sha256").update(token).digest("hex").slice(0, 12)}`;
182
+ }
183
+ function readString(value) {
184
+ return typeof value === "string" && value.length > 0 ? value : void 0;
185
+ }
186
+ //#endregion
187
+ //#region extensions/copilot/src/compaction-bridge.ts
188
+ /**
189
+ * Shape an `InfiniteSessionConfig` for `SessionConfig.infiniteSessions`.
190
+ * Returns `undefined` when no fields were supplied so callers can
191
+ * spread conditionally and let the SDK apply its own defaults
192
+ * (`enabled: true`, background 0.80, buffer 0.95). Any explicitly-set
193
+ * value (including `enabled: false` to disable infinite sessions) is
194
+ * preserved.
195
+ */
196
+ function createInfiniteSessionConfig(options) {
197
+ if (!options) return;
198
+ const result = {};
199
+ if (options.enabled !== void 0) result.enabled = options.enabled;
200
+ if (options.backgroundCompactionThreshold !== void 0) result.backgroundCompactionThreshold = options.backgroundCompactionThreshold;
201
+ if (options.bufferExhaustionThreshold !== void 0) result.bufferExhaustionThreshold = options.bufferExhaustionThreshold;
202
+ return Object.keys(result).length > 0 ? result : void 0;
203
+ }
204
+ function compactJsonValue(input) {
205
+ const out = {};
206
+ for (const [key, value] of Object.entries(input)) if (value !== void 0) out[key] = value;
207
+ return out;
208
+ }
209
+ /**
210
+ * Write an OpenClaw-shaped compaction marker JSON file under
211
+ * `<workspaceDir>/<subdir>/openclaw-compaction-<sessionId>-<ts>.json`.
212
+ *
213
+ * Returns the resolved file path and the marker payload that was
214
+ * written. Throws if the workspaceDir or sessionId is missing/empty
215
+ * (the caller should not invoke this without those — the harness
216
+ * `compact()` must validate first).
217
+ */
218
+ async function writeOpenClawCompactionMarker(input, options = {}) {
219
+ if (!input.workspaceDir || typeof input.workspaceDir !== "string") throw new Error("[copilot:compaction-bridge] workspaceDir is required to write a marker");
220
+ if (!input.sessionId || typeof input.sessionId !== "string") throw new Error("[copilot:compaction-bridge] sessionId is required to write a marker");
221
+ const now = options.now ?? Date.now;
222
+ const fs = options.fs ?? {
223
+ mkdir,
224
+ writeFile
225
+ };
226
+ const subdir = options.subdir ?? "files";
227
+ const ts = now();
228
+ const filename = `openclaw-compaction-${ts}-${input.sessionId.replace(/[^a-zA-Z0-9._-]/g, "_")}.json`;
229
+ const dirPath = join(input.workspaceDir, subdir);
230
+ const filePath = join(dirPath, filename);
231
+ const marker = compactJsonValue({
232
+ version: 1,
233
+ source: "copilot-harness",
234
+ sessionId: input.sessionId,
235
+ ts,
236
+ compacted: false,
237
+ trigger: input.trigger,
238
+ force: input.force,
239
+ sdkSessionId: input.sdkSessionId,
240
+ currentTokenCount: input.currentTokenCount,
241
+ reason: input.reason
242
+ });
243
+ await fs.mkdir(dirPath, { recursive: true });
244
+ await fs.writeFile(filePath, `${JSON.stringify(marker, null, 2)}\n`, "utf8");
245
+ return {
246
+ path: filePath,
247
+ marker
248
+ };
249
+ }
250
+ //#endregion
251
+ //#region extensions/copilot/harness.ts
252
+ const COPILOT_PROVIDER_IDS = new Set(["github-copilot"]);
253
+ function normalizeBinding(value) {
254
+ if (!value || value.schemaVersion !== 1 || typeof value.sdkSessionId !== "string" || value.sdkSessionId.trim() === "" || typeof value.compatKey !== "string" || value.compatKey.trim() === "" || typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt)) return;
255
+ return {
256
+ schemaVersion: 1,
257
+ sdkSessionId: value.sdkSessionId.trim(),
258
+ compatKey: value.compatKey,
259
+ updatedAt: value.updatedAt
260
+ };
261
+ }
262
+ function lookupStoredBinding(store, key) {
263
+ try {
264
+ return normalizeBinding(store?.lookup(key));
265
+ } catch {
266
+ try {
267
+ store?.delete(key);
268
+ } catch {}
269
+ return;
270
+ }
271
+ }
272
+ function registerStoredBinding(store, key, binding) {
273
+ try {
274
+ store?.register(key, binding);
275
+ return true;
276
+ } catch {
277
+ try {
278
+ store?.delete(key);
279
+ } catch {}
280
+ return false;
281
+ }
282
+ }
283
+ function deleteStoredBinding(store, key) {
284
+ try {
285
+ store?.delete(key);
286
+ return true;
287
+ } catch {
288
+ return false;
289
+ }
290
+ }
291
+ function computeSessionCompatKey(params) {
292
+ const p = params;
293
+ const modelObj = p.model && typeof p.model === "object" ? p.model : { id: typeof p.model === "string" ? p.model : void 0 };
294
+ let authParts;
295
+ let resolvedAgentId = "";
296
+ let resolvedCopilotHome = "";
297
+ try {
298
+ const resolved = resolveCopilotAuth({
299
+ agentId: typeof p.agentId === "string" ? p.agentId : void 0,
300
+ agentDir: typeof p.agentDir === "string" ? p.agentDir : void 0,
301
+ workspaceDir: typeof p.workspaceDir === "string" ? p.workspaceDir : void 0,
302
+ copilotHome: typeof p.copilotHome === "string" ? p.copilotHome : void 0,
303
+ auth: p.auth,
304
+ resolvedApiKey: typeof p.resolvedApiKey === "string" ? p.resolvedApiKey : void 0,
305
+ authProfileId: typeof p.authProfileId === "string" ? p.authProfileId : void 0,
306
+ profileVersion: typeof p.profileVersion === "string" ? p.profileVersion : void 0
307
+ });
308
+ resolvedAgentId = resolved.agentId;
309
+ resolvedCopilotHome = resolved.copilotHome;
310
+ authParts = [
311
+ `auth.mode=${resolved.authMode}`,
312
+ `auth.profileId=${resolved.authProfileId ?? ""}`,
313
+ `auth.profileVersion=${resolved.authProfileVersion ?? ""}`
314
+ ];
315
+ } catch {
316
+ authParts = ["auth=unresolvable"];
317
+ }
318
+ return [
319
+ `provider=${modelObj.provider ?? ""}`,
320
+ `model=${modelObj.id ?? ""}`,
321
+ `api=${modelObj.api ?? ""}`,
322
+ `cwd=${p.cwd ?? p.workspaceDir ?? ""}`,
323
+ `agentId=${resolvedAgentId}`,
324
+ `agentDir=${p.agentDir ?? ""}`,
325
+ `copilotHome=${p.copilotHome ?? ""}`,
326
+ `resolvedCopilotHome=${resolvedCopilotHome}`,
327
+ ...authParts
328
+ ].join("|");
329
+ }
330
+ function createCopilotAgentHarness(options) {
331
+ let poolPromise;
332
+ let createdPool;
333
+ let disposed = false;
334
+ let disposePromise;
335
+ const inFlight = /* @__PURE__ */ new Set();
336
+ const trackedSessions = /* @__PURE__ */ new Map();
337
+ const resetBlockedStoredSessions = /* @__PURE__ */ new Set();
338
+ async function getPool() {
339
+ if (options?.pool) return options.pool;
340
+ if (!poolPromise) poolPromise = (async () => {
341
+ const { createCopilotClientPool } = await import("./runtime-C2rPhifm.js");
342
+ createdPool = createCopilotClientPool(options?.poolOptions);
343
+ return createdPool;
344
+ })();
345
+ return poolPromise;
346
+ }
347
+ return {
348
+ id: options?.id ?? "copilot",
349
+ label: options?.label ?? "GitHub Copilot agent runtime",
350
+ supports(ctx) {
351
+ if (String(ctx.requestedRuntime ?? "").trim().toLowerCase() !== "copilot") return {
352
+ supported: false,
353
+ reason: "copilot is opt-in only"
354
+ };
355
+ const provider = ctx.provider.trim().toLowerCase();
356
+ if (!COPILOT_PROVIDER_IDS.has(provider)) return {
357
+ supported: false,
358
+ reason: `provider is not one of: ${[...COPILOT_PROVIDER_IDS].toSorted().join(", ")}`
359
+ };
360
+ return {
361
+ supported: true,
362
+ priority: 100
363
+ };
364
+ },
365
+ async runAttempt(params) {
366
+ const attemptPromise = (async () => {
367
+ if (disposed) throw new Error("[copilot] harness has been disposed; cannot start new attempts");
368
+ const { runCopilotAttempt } = await import("./attempt-DMegR4ua.js");
369
+ if (disposed) throw new Error("[copilot] harness was disposed while starting an attempt");
370
+ const pool = await getPool();
371
+ if (disposed) throw new Error("[copilot] harness was disposed while starting an attempt");
372
+ const openclawSessionId = typeof params.sessionId === "string" ? params.sessionId : void 0;
373
+ const currentCompatKey = computeSessionCompatKey(params);
374
+ const tracked = openclawSessionId ? trackedSessions.get(openclawSessionId) : void 0;
375
+ const stored = openclawSessionId ? resetBlockedStoredSessions.has(openclawSessionId) ? void 0 : lookupStoredBinding(options?.sessionStore, openclawSessionId) : void 0;
376
+ const resumableSessionId = tracked && tracked.compatKey === currentCompatKey ? tracked.sdkSessionId : !tracked && stored && stored.compatKey === currentCompatKey ? stored.sdkSessionId : void 0;
377
+ return runCopilotAttempt(resumableSessionId ? {
378
+ ...params,
379
+ initialReplayState: {
380
+ ...params.initialReplayState,
381
+ sdkSessionId: resumableSessionId
382
+ }
383
+ } : params, {
384
+ pool,
385
+ onSessionEstablished: openclawSessionId ? ({ sdkSessionId, pooledClient }) => {
386
+ trackedSessions.set(openclawSessionId, {
387
+ sdkSessionId,
388
+ client: pooledClient.client,
389
+ compatKey: currentCompatKey
390
+ });
391
+ if (registerStoredBinding(options?.sessionStore, openclawSessionId, {
392
+ schemaVersion: 1,
393
+ sdkSessionId,
394
+ compatKey: currentCompatKey,
395
+ updatedAt: Date.now()
396
+ })) resetBlockedStoredSessions.delete(openclawSessionId);
397
+ } : void 0
398
+ });
399
+ })();
400
+ inFlight.add(attemptPromise);
401
+ try {
402
+ return await attemptPromise;
403
+ } finally {
404
+ inFlight.delete(attemptPromise);
405
+ }
406
+ },
407
+ async reset(params) {
408
+ const openclawSessionId = typeof params.sessionId === "string" ? params.sessionId : void 0;
409
+ if (!openclawSessionId) return;
410
+ const tracked = trackedSessions.get(openclawSessionId);
411
+ if (deleteStoredBinding(options?.sessionStore, openclawSessionId)) resetBlockedStoredSessions.delete(openclawSessionId);
412
+ else resetBlockedStoredSessions.add(openclawSessionId);
413
+ if (!tracked) return;
414
+ trackedSessions.delete(openclawSessionId);
415
+ try {
416
+ await tracked.client.deleteSession(tracked.sdkSessionId);
417
+ } catch {}
418
+ },
419
+ async compact(params) {
420
+ const openclawSessionId = typeof params.sessionId === "string" ? params.sessionId : void 0;
421
+ const workspaceDir = typeof params.workspaceDir === "string" ? params.workspaceDir : void 0;
422
+ if (!openclawSessionId || !workspaceDir) return {
423
+ ok: false,
424
+ compacted: false,
425
+ reason: "missing-required-params"
426
+ };
427
+ const tracked = trackedSessions.get(openclawSessionId);
428
+ const reason = params.force ? "force-requested-but-sdk-has-no-synchronous-compact-api" : "deferred-to-sdk-infinite-sessions";
429
+ try {
430
+ await writeOpenClawCompactionMarker({
431
+ sessionId: openclawSessionId,
432
+ workspaceDir,
433
+ trigger: params.trigger,
434
+ currentTokenCount: params.currentTokenCount,
435
+ sdkSessionId: tracked?.sdkSessionId,
436
+ force: params.force,
437
+ reason
438
+ });
439
+ } catch (err) {
440
+ return {
441
+ ok: false,
442
+ compacted: false,
443
+ reason: "marker-write-failed",
444
+ failure: {
445
+ reason: "marker-write-failed",
446
+ rawError: err instanceof Error ? err.message : String(err)
447
+ }
448
+ };
449
+ }
450
+ return {
451
+ ok: true,
452
+ compacted: false,
453
+ reason
454
+ };
455
+ },
456
+ async dispose() {
457
+ if (disposePromise) return disposePromise;
458
+ disposed = true;
459
+ disposePromise = (async () => {
460
+ if (inFlight.size > 0) await Promise.allSettled(inFlight);
461
+ trackedSessions.clear();
462
+ resetBlockedStoredSessions.clear();
463
+ if (createdPool) {
464
+ const errors = await createdPool.dispose();
465
+ if (errors.length > 0) throw new AggregateError(errors, "[copilot] pool disposal errors");
466
+ }
467
+ })();
468
+ return disposePromise;
469
+ }
470
+ };
471
+ }
472
+ //#endregion
473
+ export { createInfiniteSessionConfig as n, resolveCopilotAuth as r, createCopilotAgentHarness as t };
@@ -0,0 +1,2 @@
1
+ import { t as createCopilotAgentHarness } from "./harness-Blgz_qk3.js";
2
+ export { createCopilotAgentHarness };
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ import { t as createCopilotAgentHarness } from "./harness-Blgz_qk3.js";
2
+ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
3
+ //#region extensions/copilot/index.ts
4
+ function isRecord(value) {
5
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6
+ }
7
+ function readPoolOptions(pluginConfig) {
8
+ if (!isRecord(pluginConfig)) return;
9
+ const pool = pluginConfig.pool;
10
+ if (!isRecord(pool)) return;
11
+ const idleTtlMs = pool.idleTtlMs;
12
+ if (typeof idleTtlMs !== "number" || !Number.isFinite(idleTtlMs) || idleTtlMs < 1) return;
13
+ return { idleTtlMs };
14
+ }
15
+ var copilot_default = definePluginEntry({
16
+ id: "copilot",
17
+ name: "GitHub Copilot agent runtime",
18
+ description: "Registers the GitHub Copilot agent runtime.",
19
+ register(api) {
20
+ const poolOptions = readPoolOptions(api.pluginConfig);
21
+ const sessionStore = api.runtime.state.openSyncKeyedStore({
22
+ namespace: "sdk-sessions",
23
+ maxEntries: 5e3,
24
+ defaultTtlMs: 2160 * 60 * 60 * 1e3
25
+ });
26
+ api.registerAgentHarness(createCopilotAgentHarness({
27
+ ...poolOptions ? { poolOptions } : {},
28
+ sessionStore
29
+ }));
30
+ }
31
+ });
32
+ //#endregion
33
+ export { copilot_default as default };