abelworkflow 1.1.0 → 1.1.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.
@@ -1,23 +1,6 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import { createNodeInsecureDispatcher, installProviderTlsFetch } from "./tls-fetch.mjs";
3
-
4
- let nodeInsecureDispatcher: unknown;
5
-
6
- function getNodeInsecureDispatcher() {
7
- if (nodeInsecureDispatcher) return nodeInsecureDispatcher;
8
- nodeInsecureDispatcher = createNodeInsecureDispatcher();
9
- return nodeInsecureDispatcher;
10
- }
11
2
 
12
3
  export default function (pi: ExtensionAPI) {
13
- if (typeof globalThis.fetch === "function") {
14
- const runtime = typeof (globalThis as any).Bun === "undefined" ? "node" : "bun";
15
- installProviderTlsFetch({
16
- runtime,
17
- insecureDispatcher: runtime === "node" ? getNodeInsecureDispatcher : undefined
18
- });
19
- }
20
-
21
4
  pi.on("before_provider_request", (event, ctx) => {
22
5
  const payload = event.payload as any;
23
6
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) return;
@@ -62,23 +62,12 @@ function mergeClaudeSettingsWithDefaults(settings) {
62
62
  };
63
63
  }
64
64
 
65
- function applyClaudeInsecureTlsSetting(env = {}, enabled = false) {
66
- const nextEnv = { ...env };
67
- if (enabled) {
68
- nextEnv.NODE_TLS_REJECT_UNAUTHORIZED = "0";
69
- } else if (nextEnv.NODE_TLS_REJECT_UNAUTHORIZED === "0") {
70
- delete nextEnv.NODE_TLS_REJECT_UNAUTHORIZED;
71
- }
72
- return nextEnv;
73
- }
74
-
75
65
  function getExistingClaudeApiConfig(settings) {
76
66
  const env = mergeClaudeSettingsWithDefaults(settings).env;
77
67
  return {
78
68
  baseUrl: env.ANTHROPIC_BASE_URL || "https://api.anthropic.com",
79
69
  key: env.ANTHROPIC_API_KEY || "",
80
- model: claudeModelEnvKeys.map((field) => env[field]).find(Boolean) || "",
81
- insecureTls: env.NODE_TLS_REJECT_UNAUTHORIZED === "0"
70
+ model: claudeModelEnvKeys.map((field) => env[field]).find(Boolean) || ""
82
71
  };
83
72
  }
84
73
 
@@ -109,14 +98,9 @@ function ensureApprovedClaudeApiKey(config, apiKey) {
109
98
  function buildClaudeApiSettings(settings, {
110
99
  baseUrl,
111
100
  key,
112
- model,
113
- insecureTls = false
101
+ model
114
102
  }) {
115
103
  const nextSettings = mergeClaudeSettingsWithDefaults(settings);
116
- nextSettings.env = applyClaudeInsecureTlsSetting(
117
- nextSettings.env && typeof nextSettings.env === "object" ? nextSettings.env : {},
118
- insecureTls
119
- );
120
104
  nextSettings.env.ANTHROPIC_BASE_URL = baseUrl;
121
105
  nextSettings.env.ANTHROPIC_API_KEY = key;
122
106
  delete nextSettings.env.ANTHROPIC_AUTH_TOKEN;
@@ -134,7 +118,6 @@ async function persistClaudeConfiguration(paths, { settings, metaConfig }) {
134
118
  async function configureClaudeApi(paths = defaultPaths, promptApi) {
135
119
  const {
136
120
  assertNotCancelled,
137
- confirmOrCancel,
138
121
  passwordPromptOptions,
139
122
  required,
140
123
  requiredUnlessExisting,
@@ -158,11 +141,6 @@ async function configureClaudeApi(paths = defaultPaths, promptApi) {
158
141
  assertNotCancelled(key);
159
142
  const finalKey = resolvePasswordValue(key, existing.key);
160
143
 
161
- const insecureTls = await confirmOrCancel({
162
- message: "是否跳过 Claude Code TLS 证书校验?仅证书无法修复时启用(会放宽该进程全部 HTTPS 请求)",
163
- initialValue: existing.insecureTls
164
- });
165
-
166
144
  const model = await p.text({
167
145
  message: "Claude Code 模型",
168
146
  initialValue: existing.model || undefined,
@@ -173,8 +151,7 @@ async function configureClaudeApi(paths = defaultPaths, promptApi) {
173
151
  const apiSettings = buildClaudeApiSettings(settings, {
174
152
  baseUrl,
175
153
  key: finalKey,
176
- model,
177
- insecureTls
154
+ model
178
155
  });
179
156
  const metaConfig = await readJsonFileSafe(paths.claudeMetaConfigPath, {}, { sensitive: true });
180
157
  metaConfig.hasCompletedOnboarding = true;
@@ -188,7 +165,6 @@ async function configureClaudeApi(paths = defaultPaths, promptApi) {
188
165
  }
189
166
 
190
167
  export {
191
- applyClaudeInsecureTlsSetting,
192
168
  buildClaudeApiSettings,
193
169
  buildDefaultClaudeSettings,
194
170
  configureClaudeApi,
@@ -1,7 +1,6 @@
1
1
  import { spawn, spawnSync } from "node:child_process";
2
2
  import { join } from "node:path";
3
3
  import * as p from "@clack/prompts";
4
- import { piInsecureTlsHeader } from "../../extensions/pi-gpt-responses-compat/tls-fetch.mjs";
5
4
  import {
6
5
  readJsonFileSafe,
7
6
  readJsoncFileSafe,
@@ -310,36 +309,17 @@ function buildPiModelConfig(modelId, existingModel = {}) {
310
309
  };
311
310
  }
312
311
 
313
- function hasPiInsecureTlsSetting(modelsConfig = {}, providerId) {
314
- const headers = modelsConfig.providers?.[requirePiProviderId(providerId)]?.headers;
315
- return headers && typeof headers === "object"
316
- ? Object.keys(headers).some((key) => key.toLowerCase() === piInsecureTlsHeader)
317
- : false;
318
- }
319
-
320
312
  function buildPiModelsConfig(modelsConfig = {}, {
321
313
  providerId,
322
314
  baseUrl,
323
315
  api,
324
- modelIds,
325
- insecureTls = false
316
+ modelIds
326
317
  }) {
327
318
  const targetProviderId = requirePiProviderId(providerId);
328
319
  const providers = modelsConfig.providers && typeof modelsConfig.providers === "object" ? modelsConfig.providers : {};
329
320
  const currentProvider = providers[targetProviderId] && typeof providers[targetProviderId] === "object"
330
321
  ? providers[targetProviderId]
331
322
  : {};
332
- const headers = currentProvider.headers && typeof currentProvider.headers === "object"
333
- ? { ...currentProvider.headers }
334
- : {};
335
- for (const key of Object.keys(headers)) {
336
- if (key.toLowerCase() === piInsecureTlsHeader) {
337
- delete headers[key];
338
- }
339
- }
340
- if (insecureTls) {
341
- headers[piInsecureTlsHeader] = new URL(baseUrl).origin;
342
- }
343
323
  const existingModels = new Map(
344
324
  (Array.isArray(currentProvider.models) ? currentProvider.models : [])
345
325
  .filter((model) => model?.id)
@@ -357,11 +337,6 @@ function buildPiModelsConfig(modelsConfig = {}, {
357
337
  models: modelIds.map((modelId) => buildPiModelConfig(modelId, existingModels.get(modelId)))
358
338
  };
359
339
  delete provider.apiKey;
360
- if (Object.keys(headers).length) {
361
- provider.headers = headers;
362
- } else {
363
- delete provider.headers;
364
- }
365
340
 
366
341
  return {
367
342
  ...modelsConfig,
@@ -413,7 +388,6 @@ function buildPiConfiguration({ auth, models, settings }, {
413
388
  baseUrl,
414
389
  api,
415
390
  modelIds,
416
- insecureTls,
417
391
  defaultModel
418
392
  }) {
419
393
  const targetProviderId = requirePiProviderId(providerId);
@@ -425,8 +399,7 @@ function buildPiConfiguration({ auth, models, settings }, {
425
399
  providerId: targetProviderId,
426
400
  baseUrl,
427
401
  api,
428
- modelIds,
429
- insecureTls
402
+ modelIds
430
403
  }),
431
404
  settings: buildPiSettingsConfig(settings, targetProviderId, defaultModel)
432
405
  };
@@ -455,7 +428,6 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
455
428
  }
456
429
  const {
457
430
  assertNotCancelled,
458
- confirmOrCancel,
459
431
  passwordPromptOptions,
460
432
  required,
461
433
  requiredUnlessExisting,
@@ -495,11 +467,6 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
495
467
  const inferredApi = inferPiApiFromBaseUrl(baseUrlInput);
496
468
  const baseUrl = normalizeOpenAiBaseUrl(baseUrlInput);
497
469
 
498
- const insecureTls = await confirmOrCancel({
499
- message: `是否仅为 ${providerLabel} 中转请求跳过 TLS 证书校验?仅证书无法修复时启用`,
500
- initialValue: hasPiInsecureTlsSetting(modelsConfig, providerId)
501
- });
502
-
503
470
  const piApiOptions = getPiApiPromptOptions();
504
471
  const initialApi = piApiOptions.some((option) => option.value === existing.api)
505
472
  ? existing.api
@@ -542,7 +509,6 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
542
509
  baseUrl,
543
510
  api,
544
511
  modelIds,
545
- insecureTls,
546
512
  defaultModel: finalDefaultModel
547
513
  });
548
514
  await ensurePiResourcesLinked(paths);
@@ -564,7 +530,6 @@ export {
564
530
  configurePiApi,
565
531
  detectPiEffectiveModel,
566
532
  getPiApiPromptOptions,
567
- hasPiInsecureTlsSetting,
568
533
  inferPiApiFromBaseUrl,
569
534
  normalizeOpenAiBaseUrl,
570
535
  parsePiRpcEffectiveModel,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abelworkflow",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Install AbelWorkflow into ~/.agents and create Claude/Codex symlinks.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,188 +0,0 @@
1
- export const piInsecureTlsHeader = "x-abelworkflow-insecure-tls";
2
-
3
- const installedFetchMarker = Symbol.for("abelworkflow.pi-provider-tls-fetch");
4
- const undiciGlobalDispatchers = [
5
- Symbol.for("undici.globalDispatcher.2"),
6
- Symbol.for("undici.globalDispatcher.1")
7
- ];
8
- const redirectStatuses = new Set([301, 302, 303, 307, 308]);
9
- const maxRedirects = 5;
10
-
11
- function getMarkedHeaders(input, init) {
12
- const source = init?.headers !== undefined
13
- ? init.headers
14
- : typeof Request !== "undefined" && input instanceof Request
15
- ? input.headers
16
- : undefined;
17
- if (source === undefined) return null;
18
-
19
- const headers = new Headers(source);
20
- if (!headers.has(piInsecureTlsHeader)) return null;
21
- const allowedOrigin = headers.get(piInsecureTlsHeader);
22
- headers.delete(piInsecureTlsHeader);
23
- return { allowedOrigin, headers };
24
- }
25
-
26
- function getRequestUrl(input) {
27
- return typeof Request !== "undefined" && input instanceof Request
28
- ? input.url
29
- : input instanceof URL
30
- ? input.href
31
- : input;
32
- }
33
-
34
- function getRequestOrigin(input) {
35
- try {
36
- return new URL(getRequestUrl(input)).origin;
37
- } catch {
38
- return null;
39
- }
40
- }
41
-
42
- function redirectRequestInit(input, init, status) {
43
- const method = String(init.method ?? (
44
- typeof Request !== "undefined" && input instanceof Request ? input.method : "GET"
45
- )).toUpperCase();
46
- const switchToGet = status === 303 && method !== "HEAD"
47
- || (status === 301 || status === 302) && method === "POST";
48
- if (!switchToGet) {
49
- if (typeof Request !== "undefined" && input instanceof Request && method !== "GET" && method !== "HEAD") {
50
- throw new Error("Pi insecure TLS cannot safely replay a redirected Request body");
51
- }
52
- return init;
53
- }
54
-
55
- const headers = new Headers(init.headers);
56
- for (const name of ["content-encoding", "content-language", "content-length", "content-location", "content-type"]) {
57
- headers.delete(name);
58
- }
59
- const nextInit = { ...init, method: "GET", headers };
60
- delete nextInit.body;
61
- return nextInit;
62
- }
63
-
64
- async function fetchWithSameOriginRedirects({ fetchOnce, input, init, allowedOrigin }) {
65
- let nextInput = input;
66
- let nextInit = init;
67
-
68
- for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount += 1) {
69
- const response = await fetchOnce(nextInput, nextInit);
70
- const location = redirectStatuses.has(response?.status) ? response.headers?.get?.("location") : null;
71
- if (!location) return response;
72
- if (redirectCount === maxRedirects) {
73
- await response.body?.cancel?.();
74
- throw new Error(`Pi insecure TLS exceeded ${maxRedirects} same-origin redirects`);
75
- }
76
-
77
- const target = new URL(location, getRequestUrl(nextInput));
78
- if (target.origin !== allowedOrigin) {
79
- await response.body?.cancel?.();
80
- throw new Error(`Pi insecure TLS blocked cross-origin redirect to ${target.origin}`);
81
- }
82
- await response.body?.cancel?.();
83
- nextInit = redirectRequestInit(nextInput, nextInit, response.status);
84
- nextInput = target.href;
85
- }
86
- }
87
-
88
- function applyNodeDispatcher(fetchImpl, input, init, dispatcherSource) {
89
- let dispatcher;
90
- try {
91
- dispatcher = typeof dispatcherSource === "function" ? dispatcherSource() : dispatcherSource;
92
- } catch (error) {
93
- return Promise.reject(error);
94
- }
95
-
96
- if (dispatcher && typeof dispatcher.then === "function") {
97
- return dispatcher.then((resolved) => applyNodeDispatcher(fetchImpl, input, init, resolved));
98
- }
99
- if (!dispatcher || typeof dispatcher.dispatch !== "function") {
100
- return Promise.reject(new Error("Pi insecure TLS requires an injected Undici dispatcher"));
101
- }
102
- return fetchImpl(input, { ...init, dispatcher });
103
- }
104
-
105
- function getUndiciDispatcherConstructor(target) {
106
- return undiciGlobalDispatchers
107
- .map((symbol) => target[symbol]?.constructor)
108
- .find((constructor) => typeof constructor === "function");
109
- }
110
-
111
- function initializeUndiciGlobalDispatcher(target) {
112
- if (typeof target.fetch !== "function") return;
113
- try {
114
- void Promise.resolve(target.fetch("data:,")).catch(() => {});
115
- } catch {
116
- }
117
- }
118
-
119
- export function createNodeInsecureDispatcher(target = globalThis) {
120
- let Dispatcher = getUndiciDispatcherConstructor(target);
121
- if (typeof Dispatcher !== "function") {
122
- initializeUndiciGlobalDispatcher(target);
123
- Dispatcher = getUndiciDispatcherConstructor(target);
124
- }
125
- if (typeof Dispatcher !== "function") {
126
- throw new Error("Pi insecure TLS requires the active Undici dispatcher");
127
- }
128
- return new Dispatcher({
129
- allowH2: false,
130
- connect: { rejectUnauthorized: false },
131
- requestTls: { rejectUnauthorized: false }
132
- });
133
- }
134
-
135
- export function createProviderTlsFetch({
136
- fetchImpl = globalThis.fetch,
137
- runtime = typeof globalThis.Bun === "undefined" ? "node" : "bun",
138
- insecureDispatcher
139
- } = {}) {
140
- if (typeof fetchImpl !== "function") {
141
- throw new TypeError("A fetch implementation is required");
142
- }
143
-
144
- return function providerTlsFetch(input, init) {
145
- const marked = getMarkedHeaders(input, init);
146
- if (!marked) return fetchImpl(input, init);
147
-
148
- const nextInit = { ...(init ?? {}), headers: marked.headers };
149
- if (!marked.allowedOrigin || getRequestOrigin(input) !== marked.allowedOrigin) {
150
- return fetchImpl(input, nextInit);
151
- }
152
-
153
- nextInit.redirect = "manual";
154
- const fetchOnce = runtime === "bun"
155
- ? (nextInput, redirectInit) => {
156
- const tls = redirectInit.tls && typeof redirectInit.tls === "object" ? redirectInit.tls : {};
157
- return fetchImpl(nextInput, {
158
- ...redirectInit,
159
- tls: { ...tls, rejectUnauthorized: false }
160
- });
161
- }
162
- : (nextInput, redirectInit) => applyNodeDispatcher(
163
- fetchImpl,
164
- nextInput,
165
- redirectInit,
166
- insecureDispatcher
167
- );
168
-
169
- return fetchWithSameOriginRedirects({
170
- fetchOnce,
171
- input,
172
- init: nextInit,
173
- allowedOrigin: marked.allowedOrigin
174
- });
175
- };
176
- }
177
-
178
- export function installProviderTlsFetch({ target = globalThis, ...options } = {}) {
179
- if (target.fetch?.[installedFetchMarker]) return target.fetch;
180
-
181
- const wrapped = createProviderTlsFetch({
182
- ...options,
183
- fetchImpl: target.fetch.bind(target)
184
- });
185
- Object.defineProperty(wrapped, installedFetchMarker, { value: true });
186
- target.fetch = wrapped;
187
- return wrapped;
188
- }