codex-copilot-dx 0.6.7 → 0.6.9

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.
@@ -16,6 +16,11 @@ import {
16
16
  pmStudioPatchManifestPath,
17
17
  } from "./pm-studio-setup.mjs";
18
18
  import { readAdapterStatus } from "./cli-status.mjs";
19
+ import {
20
+ PM_STUDIO_RELAY_MARKER_HEADER,
21
+ PM_STUDIO_RELAY_MARKER_VALUE,
22
+ PM_STUDIO_RELAY_PREFIX,
23
+ } from "./pm-studio-relay.mjs";
19
24
  import { checkRunningAdapter } from "./running-adapter.mjs";
20
25
  import { status } from "./status.mjs";
21
26
  import {
@@ -27,12 +32,11 @@ import {
27
32
 
28
33
  const PM_RELAY_HOST = "127.0.0.1";
29
34
  const PM_RELAY_PORT = 2026;
30
- const PM_RELAY_CAPABILITY = "pm_studio_relay_v1";
35
+ const PM_RELAY_PROBE_TIMEOUT_MS = 500;
36
+ const PM_RELAY_CAPABILITY = "pm_studio_split_origin_v1";
31
37
  const PM_RELAY_ROUTE_NAMES = Object.freeze([
32
38
  "pm_models",
33
39
  "pm_chat_completions",
34
- "pm_responses",
35
- "pm_embeddings",
36
40
  ]);
37
41
 
38
42
  function selectRecipe(metadata, recipes) {
@@ -45,6 +49,31 @@ function safeMessage(error) {
45
49
  return String(error?.message || "inspection failed").replace(/\s+/g, " ").trim();
46
50
  }
47
51
 
52
+ export async function probePmStudioRelay({
53
+ baseUrl,
54
+ fetchImpl = fetch,
55
+ timeoutMs = PM_RELAY_PROBE_TIMEOUT_MS,
56
+ } = {}) {
57
+ const controller = new AbortController();
58
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
59
+ try {
60
+ const response = await fetchImpl(new URL(`${PM_STUDIO_RELAY_PREFIX}/models`, baseUrl).href, {
61
+ method: "GET",
62
+ headers: { Accept: "application/json" },
63
+ redirect: "error",
64
+ signal: controller.signal,
65
+ });
66
+ const result = {
67
+ status: response.status,
68
+ marker: response.headers.get(PM_STUDIO_RELAY_MARKER_HEADER) || "",
69
+ };
70
+ await response.body?.cancel().catch(() => {});
71
+ return result;
72
+ } finally {
73
+ clearTimeout(timer);
74
+ }
75
+ }
76
+
48
77
  function inspectClaudeProfile(home, readCredentials) {
49
78
  try {
50
79
  const credentials = readCredentials(AUTH_PROFILE_CLAUDE, { home });
@@ -73,7 +102,7 @@ function inspectAdapterRuntime(adapter, runtimeStatus) {
73
102
  issues.push("health and runtime status do not describe the same adapter instance");
74
103
  }
75
104
  const capabilities = new Set(Array.isArray(data.capabilities) ? data.capabilities : []);
76
- if (!capabilities.has(PM_RELAY_CAPABILITY)) issues.push("PM Studio relay capability is missing");
105
+ if (!capabilities.has(PM_RELAY_CAPABILITY)) issues.push("PM Studio split-origin relay capability is missing");
77
106
  if (data.profiles?.claude?.mode !== "isolated") issues.push("Claude profile mode is not isolated");
78
107
  if (data.profiles?.claude?.profile_current !== true) {
79
108
  issues.push("running Claude credentials do not match the current isolated profile");
@@ -93,6 +122,21 @@ function inspectAdapterRuntime(adapter, runtimeStatus) {
93
122
  };
94
123
  }
95
124
 
125
+ function inspectRelayProbe(runtime, probe) {
126
+ const relayProbe = {
127
+ status: probe?.status,
128
+ marker: String(probe?.marker || ""),
129
+ };
130
+ const issues = [...runtime.issues];
131
+ if (relayProbe.status !== 401) {
132
+ issues.push(`PM Studio relay probe returned HTTP ${relayProbe.status ?? "unknown"}; expected 401`);
133
+ }
134
+ if (relayProbe.marker !== PM_STUDIO_RELAY_MARKER_VALUE) {
135
+ issues.push("PM Studio relay compatibility marker is missing or incompatible");
136
+ }
137
+ return { ...runtime, relayProbe, ok: issues.length === 0, issues };
138
+ }
139
+
96
140
  export async function inspectPmStudioStatus({
97
141
  appPath = DEFAULT_PM_STUDIO_APP_PATH,
98
142
  home = os.homedir(),
@@ -105,6 +149,7 @@ export async function inspectPmStudioStatus({
105
149
  readClaudeCredentials = readAuthProfileCredentials,
106
150
  checkRunningAdapterFn = checkRunningAdapter,
107
151
  readAdapterStatusFn = readAdapterStatus,
152
+ probePmStudioRelayFn = probePmStudioRelay,
108
153
  } = {}) {
109
154
  const operations = createPmStudioSetupOperations(operationOverrides);
110
155
  let app;
@@ -163,6 +208,18 @@ export async function inspectPmStudioStatus({
163
208
  } catch (error) {
164
209
  runtime = { ok: false, baseUrl: adapter.baseUrl, data: null, issues: [safeMessage(error)] };
165
210
  }
211
+ if (runtime.data) {
212
+ try {
213
+ runtime = inspectRelayProbe(runtime, await probePmStudioRelayFn({ baseUrl: adapter.baseUrl }));
214
+ } catch (error) {
215
+ runtime = {
216
+ ...runtime,
217
+ ok: false,
218
+ relayProbe: null,
219
+ issues: [...runtime.issues, `PM Studio relay probe failed: ${safeMessage(error)}`],
220
+ };
221
+ }
222
+ }
166
223
  }
167
224
  const operational = app.state === "patched"
168
225
  && app.patchRecord?.valid === true
@@ -182,6 +239,9 @@ function appStatusItem(result, commandName) {
182
239
  const reason = app.patchRecord?.reason || "installed patch record is missing";
183
240
  return { kind: "err", component: "App patch", detail: `${version}; patch record not verified`, message: `PM Studio ${version} matches the patch recipe, but its installed patch record is not verified: ${reason}` };
184
241
  }
242
+ if (app.state === "legacy") {
243
+ return { kind: "err", component: "App patch", detail: `${version}; legacy global-origin patch`, message: `PM Studio ${version} has a legacy global-origin patch; run ${commandName} pms setup to migrate` };
244
+ }
185
245
  if (app.state === "clean") return { kind: "warn", component: "App patch", detail: `${version}; supported, not patched`, message: `PM Studio ${version} is supported but not patched; run ${commandName} pms setup` };
186
246
  if (app.state === "unsupported") return { kind: "err", component: "App patch", detail: `${version}; unsupported version`, message: `PM Studio ${version} has no exact patch recipe; no files will be changed` };
187
247
  if (app.state === "drift" && app.patchRecipeMatched) {
@@ -203,7 +263,7 @@ function pmStudioStatusItems(result, commandName) {
203
263
  items.push({ kind: "err", component: "Claude profile", detail: "not ready", message: `Isolated Claude profile is not ready${reason}; run ${PM_STUDIO_CLAUDE_AUTH_COMMAND}` });
204
264
  }
205
265
  if (result.adapter?.ok && result.runtime?.ok) {
206
- items.push({ kind: "ok", component: "PM relay", detail: `verified at ${result.adapter.baseUrl}`, message: `PM relay and isolated Claude routing are verified at ${result.adapter.baseUrl}` });
266
+ items.push({ kind: "ok", component: "PM relay", detail: `verified at ${result.adapter.baseUrl}`, message: `PM model discovery and isolated Claude routing are verified at ${result.adapter.baseUrl}` });
207
267
  } else if (result.adapter?.ok) {
208
268
  const reason = result.runtime?.issues?.join("; ") || "runtime status is unavailable";
209
269
  items.push({ kind: "err", component: "PM relay", detail: "running but routing not ready", message: `The adapter is running at ${result.adapter.baseUrl}, but PM relay routing is not ready: ${reason}; stop it and run ${commandName} start` });
@@ -213,9 +273,9 @@ function pmStudioStatusItems(result, commandName) {
213
273
  items.push({ kind: "warn", component: "PM relay", detail: `not running at ${PM_RELAY_HOST}:${PM_RELAY_PORT}`, message: `PM relay is not running at http://${PM_RELAY_HOST}:${PM_RELAY_PORT}; run ${commandName} start` });
214
274
  }
215
275
  if (result.runtime?.ok) {
216
- items.push({ kind: "info", component: "Routing", detail: "GPT -> PM bearer; Claude -> isolated profile", message: "Routing: PM GPT uses the PM Studio bearer; eligible Claude chat uses the isolated Claude profile" });
276
+ items.push({ kind: "info", component: "Routing", detail: "GPT -> native official; models/Claude -> local", message: "Routing: PM GPT uses its native official GitHub Copilot path; model discovery and eligible Claude chat use the local CCDX relay" });
217
277
  } else {
218
- items.push({ kind: "info", component: "Routing", detail: "expected: GPT -> PM bearer; Claude -> isolated profile", message: "Expected routing: PM GPT uses the PM Studio bearer; eligible Claude chat uses the isolated Claude profile" });
278
+ items.push({ kind: "info", component: "Routing", detail: "expected: GPT -> native official; models/Claude -> local", message: "Expected routing: PM GPT uses its native official GitHub Copilot path; model discovery and eligible Claude chat use the local CCDX relay" });
219
279
  }
220
280
  return items;
221
281
  }
@@ -65,9 +65,21 @@ function replayableResponsesOutputItems(output) {
65
65
  return output.filter((item) => item && typeof item === "object");
66
66
  }
67
67
 
68
+ function isEncryptedContentPart(value) {
69
+ return value && typeof value === "object" && value.type === "encrypted_content";
70
+ }
71
+
68
72
  function stripEncryptedReasoningValue(value, state) {
69
73
  if (Array.isArray(value)) {
70
- return value.map((item) => stripEncryptedReasoningValue(item, state));
74
+ const out = [];
75
+ for (const item of value) {
76
+ if (isEncryptedContentPart(item)) {
77
+ state.changed = true;
78
+ continue;
79
+ }
80
+ out.push(stripEncryptedReasoningValue(item, state));
81
+ }
82
+ return out;
71
83
  }
72
84
 
73
85
  if (value && typeof value === "object") {
@@ -87,7 +99,9 @@ function stripEncryptedReasoningValue(value, state) {
87
99
 
88
100
  function isEncryptedReasoningInputItem(item) {
89
101
  return item && typeof item === "object"
90
- && (item.type === "reasoning" || Object.prototype.hasOwnProperty.call(item, "encrypted_content"));
102
+ && (item.type === "reasoning"
103
+ || item.type === "encrypted_content"
104
+ || Object.prototype.hasOwnProperty.call(item, "encrypted_content"));
91
105
  }
92
106
 
93
107
  export function sanitizeEncryptedReasoningRequest(reqContext) {
@@ -5,7 +5,9 @@ export const ADAPTER_HEALTH_PATH = "/_ccdx/health";
5
5
  export const ADAPTER_STATUS_PATH = "/_ccdx/status";
6
6
  export const ADAPTER_PROTOCOL_VERSION = 2;
7
7
  export const ADAPTER_VERSION = localPackageVersion();
8
- export const ADAPTER_CAPABILITIES = Object.freeze(["pm_studio_relay_v1"]);
8
+ export const ADAPTER_CAPABILITIES = Object.freeze([
9
+ "pm_studio_split_origin_v1",
10
+ ]);
9
11
  const ADAPTER_INSTANCE_ID = randomUUID();
10
12
 
11
13
  export function adapterHealthPayload() {