shennian 0.2.88 → 0.2.90

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 (143) hide show
  1. package/dist/assets/wechat-channel/macos/manifest.json +22 -0
  2. package/dist/assets/wechat-channel/macos/shennian-wechat-channel-helper +0 -0
  3. package/dist/bin/shennian.js +1 -1
  4. package/dist/publish-build-manifest.json +548 -0
  5. package/dist/scripts/wechat-rpa-confirmation.mjs +5 -97
  6. package/dist/src/agent-env.js +4 -105
  7. package/dist/src/agents/adapter.d.ts +6 -0
  8. package/dist/src/agents/adapter.js +1 -19
  9. package/dist/src/agents/claude.js +8 -305
  10. package/dist/src/agents/codex-control.d.ts +35 -0
  11. package/dist/src/agents/codex-control.js +2 -0
  12. package/dist/src/agents/codex-utils.js +7 -200
  13. package/dist/src/agents/codex.d.ts +8 -0
  14. package/dist/src/agents/codex.js +15 -863
  15. package/dist/src/agents/command-spec.js +2 -413
  16. package/dist/src/agents/config-status.js +1 -226
  17. package/dist/src/agents/cursor.js +1 -249
  18. package/dist/src/agents/custom.js +4 -271
  19. package/dist/src/agents/detect.js +1 -56
  20. package/dist/src/agents/external-channel-instructions.js +10 -94
  21. package/dist/src/agents/gemini.js +1 -173
  22. package/dist/src/agents/manager.js +13 -157
  23. package/dist/src/agents/model-registry/cache.js +1 -37
  24. package/dist/src/agents/model-registry/discovery.js +2 -187
  25. package/dist/src/agents/model-registry/parsers.js +4 -447
  26. package/dist/src/agents/model-registry/runner.js +1 -30
  27. package/dist/src/agents/model-registry/service.js +1 -78
  28. package/dist/src/agents/model-registry/types.js +1 -8
  29. package/dist/src/agents/model-registry.js +1 -18
  30. package/dist/src/agents/openclaw.js +2 -275
  31. package/dist/src/agents/opencode.js +1 -231
  32. package/dist/src/agents/pi-context.js +12 -217
  33. package/dist/src/agents/pi.js +14 -723
  34. package/dist/src/agents/platform-instructions.js +9 -54
  35. package/dist/src/channels/base.d.ts +4 -1
  36. package/dist/src/channels/base.js +1 -3
  37. package/dist/src/channels/registry.js +1 -30
  38. package/dist/src/channels/reply-split.js +10 -89
  39. package/dist/src/channels/runtime.d.ts +1 -0
  40. package/dist/src/channels/runtime.js +5 -533
  41. package/dist/src/channels/secret-registry.d.ts +1 -0
  42. package/dist/src/channels/secret-registry.js +1 -46
  43. package/dist/src/channels/websocket.js +8 -378
  44. package/dist/src/channels/wechat-channel/anchor.d.ts +10 -0
  45. package/dist/src/channels/wechat-channel/anchor.js +1 -0
  46. package/dist/src/channels/wechat-channel/client.d.ts +74 -0
  47. package/dist/src/channels/wechat-channel/client.js +1 -0
  48. package/dist/src/channels/wechat-channel/cooldown.d.ts +15 -0
  49. package/dist/src/channels/wechat-channel/cooldown.js +1 -0
  50. package/dist/src/channels/wechat-channel/fingerprint.d.ts +28 -0
  51. package/dist/src/channels/wechat-channel/fingerprint.js +1 -0
  52. package/dist/src/channels/wechat-channel/helper-assets.d.ts +37 -0
  53. package/dist/src/channels/wechat-channel/helper-assets.js +1 -0
  54. package/dist/src/channels/wechat-channel/helper-client.d.ts +25 -0
  55. package/dist/src/channels/wechat-channel/helper-client.js +3 -0
  56. package/dist/src/channels/wechat-channel/helper-protocol.d.ts +84 -0
  57. package/dist/src/channels/wechat-channel/helper-protocol.js +1 -0
  58. package/dist/src/channels/wechat-channel/index.d.ts +17 -0
  59. package/dist/src/channels/wechat-channel/index.js +1 -0
  60. package/dist/src/channels/wechat-channel/ledger.d.ts +33 -0
  61. package/dist/src/channels/wechat-channel/ledger.js +1 -0
  62. package/dist/src/channels/wechat-channel/media-resolver.d.ts +32 -0
  63. package/dist/src/channels/wechat-channel/media-resolver.js +1 -0
  64. package/dist/src/channels/wechat-channel/message-key.d.ts +19 -0
  65. package/dist/src/channels/wechat-channel/message-key.js +1 -0
  66. package/dist/src/channels/wechat-channel/observer.d.ts +64 -0
  67. package/dist/src/channels/wechat-channel/observer.js +1 -0
  68. package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +69 -0
  69. package/dist/src/channels/wechat-channel/outbound-ledger.js +2 -0
  70. package/dist/src/channels/wechat-channel/outbound-sender.d.ts +26 -0
  71. package/dist/src/channels/wechat-channel/outbound-sender.js +1 -0
  72. package/dist/src/channels/wechat-channel/preflight.d.ts +37 -0
  73. package/dist/src/channels/wechat-channel/preflight.js +1 -0
  74. package/dist/src/channels/wechat-channel/runner.d.ts +34 -0
  75. package/dist/src/channels/wechat-channel/runner.js +1 -0
  76. package/dist/src/channels/wechat-channel/runtime.d.ts +45 -0
  77. package/dist/src/channels/wechat-channel/runtime.js +1 -0
  78. package/dist/src/channels/wechat-channel/scheduler.d.ts +35 -0
  79. package/dist/src/channels/wechat-channel/scheduler.js +1 -0
  80. package/dist/src/channels/wechat-rpa/macos-flow.js +1 -96
  81. package/dist/src/channels/wechat-rpa/macos.js +6 -48
  82. package/dist/src/channels/wechat-rpa/normalizer.js +7 -127
  83. package/dist/src/channels/wechat-rpa.d.ts +21 -0
  84. package/dist/src/channels/wechat-rpa.js +6 -1022
  85. package/dist/src/channels/wecom.js +4 -357
  86. package/dist/src/commands/agent.js +6 -131
  87. package/dist/src/commands/daemon-windows.js +8 -48
  88. package/dist/src/commands/daemon.js +19 -1013
  89. package/dist/src/commands/external-attachments.js +1 -51
  90. package/dist/src/commands/external.js +1 -137
  91. package/dist/src/commands/manager.js +2 -389
  92. package/dist/src/commands/pair-qr.js +1 -6
  93. package/dist/src/commands/pair.js +9 -287
  94. package/dist/src/commands/tools.js +1 -34
  95. package/dist/src/commands/upgrade.js +1 -198
  96. package/dist/src/config/index.js +1 -35
  97. package/dist/src/daemon-log.js +6 -58
  98. package/dist/src/env-path.js +1 -64
  99. package/dist/src/fs/boundary.js +1 -126
  100. package/dist/src/fs/handler.js +1 -130
  101. package/dist/src/fs/security.js +1 -32
  102. package/dist/src/fs/text-decoder.d.ts +10 -0
  103. package/dist/src/fs/text-decoder.js +1 -0
  104. package/dist/src/index.js +2 -404
  105. package/dist/src/log-reporter.js +1 -16
  106. package/dist/src/manager/prompt.js +29 -34
  107. package/dist/src/manager/registry.js +2 -269
  108. package/dist/src/manager/runtime.js +19 -1003
  109. package/dist/src/native-fusion/config.js +1 -5
  110. package/dist/src/native-fusion/opencode-parser.js +3 -123
  111. package/dist/src/native-fusion/parser-common.js +8 -264
  112. package/dist/src/native-fusion/parsers.js +8 -729
  113. package/dist/src/native-fusion/service.d.ts +10 -0
  114. package/dist/src/native-fusion/service.js +2 -198
  115. package/dist/src/native-fusion/state.js +1 -22
  116. package/dist/src/native-fusion/types.js +1 -1
  117. package/dist/src/region.js +1 -88
  118. package/dist/src/relay/client.js +1 -343
  119. package/dist/src/session/archive-zip.js +1 -220
  120. package/dist/src/session/handlers/agent-config.js +1 -150
  121. package/dist/src/session/handlers/agents.js +1 -55
  122. package/dist/src/session/handlers/chat.js +2 -733
  123. package/dist/src/session/handlers/control.js +1 -55
  124. package/dist/src/session/handlers/fs.js +1 -747
  125. package/dist/src/session/handlers/session-refresh.js +1 -35
  126. package/dist/src/session/handlers/skills.js +1 -121
  127. package/dist/src/session/handlers/title.js +1 -60
  128. package/dist/src/session/handlers/tool-detail.d.ts +3 -0
  129. package/dist/src/session/handlers/tool-detail.js +1 -0
  130. package/dist/src/session/manager.d.ts +3 -0
  131. package/dist/src/session/manager.js +1 -261
  132. package/dist/src/session/projection.js +1 -54
  133. package/dist/src/session/queue.js +4 -317
  134. package/dist/src/session/remote-attachments.js +1 -72
  135. package/dist/src/session/store.js +3 -109
  136. package/dist/src/session/types.d.ts +4 -0
  137. package/dist/src/session/types.js +1 -4
  138. package/dist/src/skills/registry.js +15 -148
  139. package/dist/src/skills/setup.js +1 -101
  140. package/dist/src/tools/markdown-to-pdf.js +10 -346
  141. package/dist/src/upgrade/engine.js +3 -347
  142. package/package.json +3 -2
  143. package/dist/scripts/wechat-rpa-download-candidates.mjs +0 -105
@@ -1,413 +1,2 @@
1
- // @arch docs/architecture/cli/windows-agent-launch.md
2
- // @test src/__tests__/command-spec.test.ts
3
- import { spawn, spawnSync } from 'node:child_process';
4
- import fs from 'node:fs';
5
- import os from 'node:os';
6
- import path from 'node:path';
7
- const BUILTIN_COMMANDS = {
8
- claude: [
9
- { command: 'claude', args: [], display: 'claude' },
10
- ],
11
- codex: [
12
- { command: 'codex', args: [], display: 'codex' },
13
- ],
14
- gemini: [
15
- { command: 'gemini', args: [], display: 'gemini' },
16
- ],
17
- cursor: [
18
- { command: 'agent', args: [], display: 'agent' },
19
- { command: 'cursor', args: ['agent'], display: 'cursor agent' },
20
- ],
21
- // OpenClaw support is intentionally disabled.
22
- openclaw: [],
23
- opencode: [
24
- { command: 'opencode', args: [], display: 'opencode' },
25
- ],
26
- pi: [
27
- { command: 'shennian', args: [], display: 'shennian' },
28
- ],
29
- manager: [
30
- { command: 'shennian', args: ['manager'], display: 'shennian manager' },
31
- ],
32
- };
33
- const availabilityCache = new Map();
34
- const resolvedCache = new Map();
35
- const pathLookupCache = new Map();
36
- const wslAvailabilityCache = new Map();
37
- export function resetCommandSpecCache() {
38
- availabilityCache.clear();
39
- resolvedCache.clear();
40
- pathLookupCache.clear();
41
- wslAvailabilityCache.clear();
42
- }
43
- export function getProcessPlatform() {
44
- return process.platform;
45
- }
46
- function splitLines(text) {
47
- return text
48
- .split(/\r?\n/)
49
- .map((line) => line.trim())
50
- .filter(Boolean);
51
- }
52
- function getFallbackCommandCandidates(command) {
53
- if (path.basename(command) !== command)
54
- return [command];
55
- const home = os.homedir();
56
- if (getProcessPlatform() === 'win32') {
57
- const winPath = path.win32;
58
- const names = path.extname(command)
59
- ? [command]
60
- : [command, `${command}.cmd`, `${command}.exe`, `${command}.bat`];
61
- const appData = process.env.APPDATA || winPath.join(home, 'AppData', 'Roaming');
62
- const localAppData = process.env.LOCALAPPDATA || winPath.join(home, 'AppData', 'Local');
63
- const dirs = [
64
- winPath.join(home, '.shennian', 'node'),
65
- winPath.join('C:\\', 'nvm4w', 'nodejs'),
66
- winPath.join(localAppData, 'npm-global'),
67
- winPath.join(appData, 'npm'),
68
- winPath.join(localAppData, 'pnpm'),
69
- winPath.join(home, 'scoop', 'shims'),
70
- winPath.join('C:\\', 'Program Files', 'nodejs'),
71
- ];
72
- return dirs.flatMap((dir) => names.map((name) => winPath.join(dir, name)));
73
- }
74
- const dirs = [
75
- path.join(home, '.npm-global', 'bin'),
76
- path.join(home, '.local', 'bin'),
77
- path.join(home, '.bun', 'bin'),
78
- '/opt/homebrew/bin',
79
- '/usr/local/bin',
80
- '/usr/bin',
81
- '/bin',
82
- ];
83
- return dirs.map((dir) => path.join(dir, command));
84
- }
85
- function buildFallbackPathEnv(currentPath, command) {
86
- const parts = currentPath?.split(path.delimiter).filter(Boolean) ?? [];
87
- if (getProcessPlatform() === 'win32') {
88
- if (command && path.basename(command) !== command) {
89
- const commandDir = path.win32.dirname(command);
90
- if (!parts.includes(commandDir))
91
- parts.unshift(commandDir);
92
- }
93
- for (const candidate of getFallbackCommandCandidates('shennian')) {
94
- const dir = path.win32.dirname(candidate);
95
- if (!parts.includes(dir))
96
- parts.push(dir);
97
- }
98
- return parts.join(path.delimiter);
99
- }
100
- if (command && path.basename(command) !== command) {
101
- const commandDir = path.dirname(command);
102
- if (!parts.includes(commandDir))
103
- parts.unshift(commandDir);
104
- }
105
- for (const candidate of getFallbackCommandCandidates('shennian')) {
106
- const dir = path.dirname(candidate);
107
- if (!parts.includes(dir))
108
- parts.push(dir);
109
- }
110
- return parts.join(path.delimiter);
111
- }
112
- function lookupCommandPaths(command) {
113
- if (pathLookupCache.has(command)) {
114
- return pathLookupCache.get(command) ?? [];
115
- }
116
- const isWindows = getProcessPlatform() === 'win32';
117
- const lookup = isWindows ? 'where' : 'which';
118
- const result = spawnSync(lookup, [command], {
119
- encoding: 'utf-8',
120
- stdio: ['ignore', 'pipe', 'pipe'],
121
- timeout: 3000,
122
- windowsHide: true,
123
- env: {
124
- ...process.env,
125
- PATH: isWindows ? process.env.PATH : buildFallbackPathEnv(process.env.PATH, command),
126
- },
127
- });
128
- const paths = result.status === 0 ? splitLines(result.stdout ?? '') : [];
129
- const withFallbacks = [...paths];
130
- for (const candidate of getFallbackCommandCandidates(command)) {
131
- if (fs.existsSync(candidate) && !withFallbacks.includes(candidate))
132
- withFallbacks.push(candidate);
133
- }
134
- pathLookupCache.set(command, withFallbacks);
135
- return withFallbacks;
136
- }
137
- function getWindowsShellPath() {
138
- return process.env.ComSpec || 'cmd.exe';
139
- }
140
- function isWindowsNativeBinary(filePath) {
141
- const ext = path.extname(filePath).toLowerCase();
142
- return ext === '.exe' || ext === '.com';
143
- }
144
- function isWindowsCmdShim(filePath) {
145
- const ext = path.extname(filePath).toLowerCase();
146
- return ext === '.cmd' || ext === '.bat';
147
- }
148
- function isWindowsNodeScript(filePath) {
149
- const ext = path.extname(filePath).toLowerCase();
150
- return ext === '.js' || ext === '.mjs' || ext === '.cjs';
151
- }
152
- function resolveWindowsNodeCommand() {
153
- return lookupCommandPaths('node.exe')[0] ?? lookupCommandPaths('node')[0] ?? 'node';
154
- }
155
- function quoteCmdArg(text) {
156
- return `"${text.replace(/"/g, '""')}"`;
157
- }
158
- function quotePosixArg(text) {
159
- return `'${text.replace(/'/g, `'\\''`)}'`;
160
- }
161
- export function windowsPathToWsl(input) {
162
- if (!input)
163
- return undefined;
164
- const normalized = input.replace(/\//g, '\\');
165
- const driveMatch = normalized.match(/^([A-Za-z]):\\(.*)$/);
166
- if (driveMatch) {
167
- const [, drive, rest] = driveMatch;
168
- const suffix = rest.replace(/\\/g, '/');
169
- return `/mnt/${drive.toLowerCase()}/${suffix}`;
170
- }
171
- if (normalized.startsWith('\\\\wsl$\\')) {
172
- const remainder = normalized.replace(/^\\\\wsl\$\\[^\\]+\\?/, '');
173
- return `/${remainder.replace(/\\/g, '/')}`;
174
- }
175
- if (input.startsWith('/'))
176
- return input;
177
- return undefined;
178
- }
179
- function resolveArbitraryWindowsCommand(command) {
180
- const normalized = command.trim();
181
- if (!normalized) {
182
- throw new Error('Command string is empty');
183
- }
184
- const hasExplicitPath = /[\\/]/.test(normalized) || /^[A-Za-z]:/.test(normalized);
185
- if (hasExplicitPath) {
186
- if (isWindowsCmdShim(normalized))
187
- return { kind: 'cmd-shim', path: normalized };
188
- return { kind: 'direct', path: normalized };
189
- }
190
- const paths = lookupCommandPaths(normalized);
191
- const native = paths.find(isWindowsNativeBinary);
192
- if (native)
193
- return { kind: 'direct', path: native };
194
- const shim = paths.find(isWindowsCmdShim);
195
- if (shim)
196
- return { kind: 'cmd-shim', path: shim };
197
- return { kind: 'direct', path: normalized };
198
- }
199
- function canUseWslBridge(command) {
200
- if (wslAvailabilityCache.has(command)) {
201
- return wslAvailabilityCache.get(command) ?? false;
202
- }
203
- const wslPath = lookupCommandPaths('wsl.exe')[0] ?? lookupCommandPaths('wsl')[0];
204
- if (!wslPath) {
205
- wslAvailabilityCache.set(command, false);
206
- return false;
207
- }
208
- const result = spawnSync(wslPath, ['-e', 'sh', '-lc', `command -v ${quotePosixArg(command)} >/dev/null 2>&1`], {
209
- stdio: 'ignore',
210
- timeout: 5000,
211
- windowsHide: true,
212
- });
213
- const ok = result.status === 0;
214
- wslAvailabilityCache.set(command, ok);
215
- return ok;
216
- }
217
- export function commandExists(command) {
218
- if (availabilityCache.has(command)) {
219
- return availabilityCache.get(command) ?? false;
220
- }
221
- const exists = lookupCommandPaths(command).length > 0 || (getProcessPlatform() === 'win32' && canUseWslBridge(command));
222
- availabilityCache.set(command, exists);
223
- return exists;
224
- }
225
- function resolveWindowsBuiltinCommand(candidate) {
226
- const paths = lookupCommandPaths(candidate.command);
227
- const native = paths.find(isWindowsNativeBinary);
228
- if (native) {
229
- return { ...candidate, kind: 'native', path: native };
230
- }
231
- const shim = paths.find(isWindowsCmdShim);
232
- if (shim) {
233
- return { ...candidate, kind: 'cmd-shim', path: shim };
234
- }
235
- if (canUseWslBridge(candidate.command)) {
236
- const wslPath = lookupCommandPaths('wsl.exe')[0] ?? lookupCommandPaths('wsl')[0];
237
- if (wslPath) {
238
- return { ...candidate, kind: 'wsl-bridge', path: wslPath };
239
- }
240
- }
241
- return null;
242
- }
243
- export function resolveBuiltinCommand(type) {
244
- if (resolvedCache.has(type)) {
245
- return resolvedCache.get(type) ?? null;
246
- }
247
- const resolved = BUILTIN_COMMANDS[type]
248
- .map((candidate) => {
249
- if (getProcessPlatform() === 'win32') {
250
- return resolveWindowsBuiltinCommand(candidate);
251
- }
252
- const commandPath = lookupCommandPaths(candidate.command)[0];
253
- return commandPath ? { ...candidate, kind: 'native', path: commandPath } : null;
254
- })
255
- .find(Boolean) ?? null;
256
- resolvedCache.set(type, resolved);
257
- return resolved;
258
- }
259
- export function buildLaunchSpec(spec, runtimeArgs, cwd) {
260
- if (spec.kind === 'native') {
261
- if (getProcessPlatform() === 'win32' && isWindowsNodeScript(spec.path)) {
262
- return {
263
- command: resolveWindowsNodeCommand(),
264
- args: [spec.path, ...spec.args, ...runtimeArgs],
265
- cwd,
266
- };
267
- }
268
- return {
269
- command: spec.path,
270
- args: [...spec.args, ...runtimeArgs],
271
- cwd,
272
- };
273
- }
274
- if (spec.kind === 'cmd-shim') {
275
- const commandLine = [spec.path, ...spec.args, ...runtimeArgs].map(quoteCmdArg).join(' ');
276
- return {
277
- command: getWindowsShellPath(),
278
- args: ['/d', '/s', '/c', `"${commandLine}"`],
279
- cwd,
280
- };
281
- }
282
- const wslCwd = cwd ? windowsPathToWsl(cwd) : undefined;
283
- if (cwd && !wslCwd) {
284
- throw new Error(`Cannot map Windows path to WSL workDir: ${cwd}`);
285
- }
286
- const shellCommand = [
287
- wslCwd ? `cd ${quotePosixArg(wslCwd)}` : '',
288
- `exec ${[spec.command, ...spec.args, ...runtimeArgs].map(quotePosixArg).join(' ')}`,
289
- ].filter(Boolean).join(' && ');
290
- return {
291
- command: spec.path,
292
- args: ['-e', 'sh', '-lc', shellCommand],
293
- cwd: undefined,
294
- };
295
- }
296
- export function spawnResolvedCommand(spec, runtimeArgs, options = {}) {
297
- const launch = buildLaunchSpec(spec, runtimeArgs, options.cwd);
298
- return spawn(launch.command, launch.args, {
299
- ...options,
300
- cwd: launch.cwd,
301
- windowsHide: options.windowsHide ?? true,
302
- ...(getProcessPlatform() === 'win32' && spec.kind === 'cmd-shim'
303
- ? { windowsVerbatimArguments: true }
304
- : {}),
305
- });
306
- }
307
- export function spawnAgentCommand(spec, runtimeArgs, options = {}) {
308
- return spawnResolvedCommand(spec, runtimeArgs, options);
309
- }
310
- export function spawnResolvedCommandSync(spec, runtimeArgs, options = {}) {
311
- const launch = buildLaunchSpec(spec, runtimeArgs, options.cwd);
312
- return spawnSync(launch.command, launch.args, {
313
- ...options,
314
- cwd: launch.cwd,
315
- windowsHide: options.windowsHide ?? true,
316
- ...(getProcessPlatform() === 'win32' && spec.kind === 'cmd-shim'
317
- ? { windowsVerbatimArguments: true }
318
- : {}),
319
- });
320
- }
321
- export function parseCommandString(command) {
322
- const args = [];
323
- let current = '';
324
- let inSingle = false;
325
- let inDouble = false;
326
- for (const ch of command) {
327
- if (ch === "'" && !inDouble) {
328
- inSingle = !inSingle;
329
- continue;
330
- }
331
- if (ch === '"' && !inSingle) {
332
- inDouble = !inDouble;
333
- continue;
334
- }
335
- if (ch === ' ' && !inSingle && !inDouble) {
336
- if (current) {
337
- args.push(current);
338
- current = '';
339
- }
340
- continue;
341
- }
342
- current += ch;
343
- }
344
- if (current)
345
- args.push(current);
346
- return args;
347
- }
348
- export function buildCommandStringLaunchSpec(commandString, runtimeArgs, cwd) {
349
- const parts = parseCommandString(commandString);
350
- const bin = parts[0];
351
- if (!bin) {
352
- throw new Error('Command string is empty');
353
- }
354
- const baseArgs = parts.slice(1);
355
- if (getProcessPlatform() !== 'win32') {
356
- return {
357
- command: bin,
358
- args: [...baseArgs, ...runtimeArgs],
359
- cwd,
360
- };
361
- }
362
- const invocation = resolveArbitraryWindowsCommand(bin);
363
- if (invocation.kind === 'cmd-shim') {
364
- return {
365
- command: getWindowsShellPath(),
366
- args: ['/d', '/s', '/c', `"${[invocation.path, ...baseArgs, ...runtimeArgs].map(quoteCmdArg).join(' ')}"`],
367
- cwd,
368
- };
369
- }
370
- if (isWindowsNodeScript(invocation.path)) {
371
- return {
372
- command: resolveWindowsNodeCommand(),
373
- args: [invocation.path, ...baseArgs, ...runtimeArgs],
374
- cwd,
375
- };
376
- }
377
- return {
378
- command: invocation.path,
379
- args: [...baseArgs, ...runtimeArgs],
380
- cwd,
381
- };
382
- }
383
- export function spawnCommandString(commandString, runtimeArgs, options = {}) {
384
- const launch = buildCommandStringLaunchSpec(commandString, runtimeArgs, options.cwd);
385
- const parts = parseCommandString(commandString);
386
- const invocation = getProcessPlatform() === 'win32' && parts[0]
387
- ? resolveArbitraryWindowsCommand(parts[0])
388
- : null;
389
- return spawn(launch.command, launch.args, {
390
- ...options,
391
- cwd: launch.cwd,
392
- windowsHide: options.windowsHide ?? true,
393
- env: {
394
- ...options.env,
395
- PATH: buildFallbackPathEnv(options.env?.PATH ?? process.env.PATH, parts[0]),
396
- },
397
- ...(getProcessPlatform() === 'win32' && invocation?.kind === 'cmd-shim'
398
- ? { windowsVerbatimArguments: true }
399
- : {}),
400
- });
401
- }
402
- export function getCommandVersion(spec, flag = '--version') {
403
- const result = spawnResolvedCommandSync(spec, [flag], {
404
- encoding: 'utf-8',
405
- stdio: ['ignore', 'pipe', 'pipe'],
406
- timeout: 5000,
407
- });
408
- if (result.status !== 0)
409
- return undefined;
410
- const text = `${result.stdout ?? ''}\n${result.stderr ?? ''}`.trim();
411
- const match = text.match(/\d+\.\d+[\w.-]*/);
412
- return match?.[0];
413
- }
1
+ import{spawn as x,spawnSync as p}from"node:child_process";import W from"node:fs";import D from"node:os";import s from"node:path";const T={claude:[{command:"claude",args:[],display:"claude"}],codex:[{command:"codex",args:[],display:"codex"}],gemini:[{command:"gemini",args:[],display:"gemini"}],cursor:[{command:"agent",args:[],display:"agent"},{command:"cursor",args:["agent"],display:"cursor agent"}],openclaw:[],opencode:[{command:"opencode",args:[],display:"opencode"}],pi:[{command:"shennian",args:[],display:"shennian"}],manager:[{command:"shennian",args:["manager"],display:"shennian manager"}]},l=new Map,m=new Map,f=new Map,u=new Map;function U(){l.clear(),m.clear(),f.clear(),u.clear()}function c(){return process.platform}function B(n){return n.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)}function h(n){if(s.basename(n)!==n)return[n];const e=D.homedir();if(c()==="win32"){const t=s.win32,r=s.extname(n)?[n]:[n,`${n}.cmd`,`${n}.exe`,`${n}.bat`],o=process.env.APPDATA||t.join(e,"AppData","Roaming"),a=process.env.LOCALAPPDATA||t.join(e,"AppData","Local");return[t.join(e,".shennian","node"),t.join("C:\\","nvm4w","nodejs"),t.join(a,"npm-global"),t.join(o,"npm"),t.join(a,"pnpm"),t.join(e,"scoop","shims"),t.join("C:\\","Program Files","nodejs")].flatMap(H=>r.map(L=>t.join(H,L)))}return[s.join(e,".npm-global","bin"),s.join(e,".local","bin"),s.join(e,".bun","bin"),"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"].map(t=>s.join(t,n))}function v(n,e){const i=n?.split(s.delimiter).filter(Boolean)??[];if(c()==="win32"){if(e&&s.basename(e)!==e){const t=s.win32.dirname(e);i.includes(t)||i.unshift(t)}for(const t of h("shennian")){const r=s.win32.dirname(t);i.includes(r)||i.push(r)}return i.join(s.delimiter)}if(e&&s.basename(e)!==e){const t=s.dirname(e);i.includes(t)||i.unshift(t)}for(const t of h("shennian")){const r=s.dirname(t);i.includes(r)||i.push(r)}return i.join(s.delimiter)}function d(n){if(f.has(n))return f.get(n)??[];const e=c()==="win32",t=p(e?"where":"which",[n],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,windowsHide:!0,env:{...process.env,PATH:e?process.env.PATH:v(process.env.PATH,n)}}),o=[...t.status===0?B(t.stdout??""):[]];for(const a of h(n))W.existsSync(a)&&!o.includes(a)&&o.push(a);return f.set(n,o),o}function C(){return process.env.ComSpec||"cmd.exe"}function b(n){const e=s.extname(n).toLowerCase();return e===".exe"||e===".com"}function w(n){const e=s.extname(n).toLowerCase();return e===".cmd"||e===".bat"}function j(n){const e=s.extname(n).toLowerCase();return e===".js"||e===".mjs"||e===".cjs"}function k(){return d("node.exe")[0]??d("node")[0]??"node"}function P(n){return`"${n.replace(/"/g,'""')}"`}function g(n){return`'${n.replace(/'/g,"'\\''")}'`}function M(n){if(!n)return;const e=n.replace(/\//g,"\\"),i=e.match(/^([A-Za-z]):\\(.*)$/);if(i){const[,t,r]=i,o=r.replace(/\\/g,"/");return`/mnt/${t.toLowerCase()}/${o}`}if(e.startsWith("\\\\wsl$\\"))return`/${e.replace(/^\\\\wsl\$\\[^\\]+\\?/,"").replace(/\\/g,"/")}`;if(n.startsWith("/"))return n}function A(n){const e=n.trim();if(!e)throw new Error("Command string is empty");if(/[\\/]/.test(e)||/^[A-Za-z]:/.test(e))return w(e)?{kind:"cmd-shim",path:e}:{kind:"direct",path:e};const t=d(e),r=t.find(b);if(r)return{kind:"direct",path:r};const o=t.find(w);return o?{kind:"cmd-shim",path:o}:{kind:"direct",path:e}}function $(n){if(u.has(n))return u.get(n)??!1;const e=d("wsl.exe")[0]??d("wsl")[0];if(!e)return u.set(n,!1),!1;const t=p(e,["-e","sh","-lc",`command -v ${g(n)} >/dev/null 2>&1`],{stdio:"ignore",timeout:5e3,windowsHide:!0}).status===0;return u.set(n,t),t}function Z(n){if(l.has(n))return l.get(n)??!1;const e=d(n).length>0||c()==="win32"&&$(n);return l.set(n,e),e}function E(n){const e=d(n.command),i=e.find(b);if(i)return{...n,kind:"native",path:i};const t=e.find(w);if(t)return{...n,kind:"cmd-shim",path:t};if($(n.command)){const r=d("wsl.exe")[0]??d("wsl")[0];if(r)return{...n,kind:"wsl-bridge",path:r}}return null}function _(n){if(m.has(n))return m.get(n)??null;const e=T[n].map(i=>{if(c()==="win32")return E(i);const t=d(i.command)[0];return t?{...i,kind:"native",path:t}:null}).find(Boolean)??null;return m.set(n,e),e}function S(n,e,i){if(n.kind==="native")return c()==="win32"&&j(n.path)?{command:k(),args:[n.path,...n.args,...e],cwd:i}:{command:n.path,args:[...n.args,...e],cwd:i};if(n.kind==="cmd-shim"){const o=[n.path,...n.args,...e].map(P).join(" ");return{command:C(),args:["/d","/s","/c",`"${o}"`],cwd:i}}const t=i?M(i):void 0;if(i&&!t)throw new Error(`Cannot map Windows path to WSL workDir: ${i}`);const r=[t?`cd ${g(t)}`:"",`exec ${[n.command,...n.args,...e].map(g).join(" ")}`].filter(Boolean).join(" && ");return{command:n.path,args:["-e","sh","-lc",r],cwd:void 0}}function N(n,e,i={}){const t=S(n,e,i.cwd);return x(t.command,t.args,{...i,cwd:t.cwd,windowsHide:i.windowsHide??!0,...c()==="win32"&&n.kind==="cmd-shim"?{windowsVerbatimArguments:!0}:{}})}function G(n,e,i={}){return N(n,e,i)}function z(n,e,i={}){const t=S(n,e,i.cwd);return p(t.command,t.args,{...i,cwd:t.cwd,windowsHide:i.windowsHide??!0,...c()==="win32"&&n.kind==="cmd-shim"?{windowsVerbatimArguments:!0}:{}})}function y(n){const e=[];let i="",t=!1,r=!1;for(const o of n){if(o==="'"&&!r){t=!t;continue}if(o==='"'&&!t){r=!r;continue}if(o===" "&&!t&&!r){i&&(e.push(i),i="");continue}i+=o}return i&&e.push(i),e}function F(n,e,i){const t=y(n),r=t[0];if(!r)throw new Error("Command string is empty");const o=t.slice(1);if(c()!=="win32")return{command:r,args:[...o,...e],cwd:i};const a=A(r);return a.kind==="cmd-shim"?{command:C(),args:["/d","/s","/c",`"${[a.path,...o,...e].map(P).join(" ")}"`],cwd:i}:j(a.path)?{command:k(),args:[a.path,...o,...e],cwd:i}:{command:a.path,args:[...o,...e],cwd:i}}function J(n,e,i={}){const t=F(n,e,i.cwd),r=y(n),o=c()==="win32"&&r[0]?A(r[0]):null;return x(t.command,t.args,{...i,cwd:t.cwd,windowsHide:i.windowsHide??!0,env:{...i.env,PATH:v(i.env?.PATH??process.env.PATH,r[0])},...c()==="win32"&&o?.kind==="cmd-shim"?{windowsVerbatimArguments:!0}:{}})}function K(n,e="--version"){const i=z(n,[e],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:5e3});return i.status!==0?void 0:`${i.stdout??""}
2
+ ${i.stderr??""}`.trim().match(/\d+\.\d+[\w.-]*/)?.[0]}export{F as buildCommandStringLaunchSpec,S as buildLaunchSpec,Z as commandExists,K as getCommandVersion,c as getProcessPlatform,y as parseCommandString,U as resetCommandSpecCache,_ as resolveBuiltinCommand,G as spawnAgentCommand,J as spawnCommandString,N as spawnResolvedCommand,z as spawnResolvedCommandSync,M as windowsPathToWsl};
@@ -1,226 +1 @@
1
- // @arch docs/features/agent-provider-config.md
2
- // @test src/__tests__/agent-config-status.test.ts
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { readLatestUserEnv } from '../agent-env.js';
7
- import { loadConfig, resolveShennianPath } from '../config/index.js';
8
- const MANAGED_CONFIG_PATH = resolveShennianPath('agent-provider-config.json');
9
- const TOKEN_SUFFIX_LENGTH = 4;
10
- function isConfigurableAgent(agent) {
11
- return agent === 'codex' || agent === 'claude' || agent === 'pi';
12
- }
13
- const AGENT_ENV_KEYS = {
14
- codex: {
15
- baseUrl: ['OPENAI_BASE_URL', 'OPENAI_API_BASE', 'OPENAI_API_URL'],
16
- token: ['OPENAI_API_KEY', 'OPENAI_TOKEN'],
17
- },
18
- claude: {
19
- baseUrl: ['ANTHROPIC_BASE_URL', 'ANTHROPIC_API_URL'],
20
- token: ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN'],
21
- },
22
- pi: {
23
- baseUrl: ['DASHSCOPE_BASE_URL', 'DASHSCOPE_API_BASE', 'DASHSCOPE_API_URL'],
24
- token: ['DASHSCOPE_API_KEY', 'DASHSCOPE_TOKEN'],
25
- },
26
- };
27
- export function getManagedAgentProviderConfig(agent) {
28
- return loadManagedConfig().configs[agent];
29
- }
30
- export function upsertManagedAgentProviderConfig(input) {
31
- const file = loadManagedConfig();
32
- const existing = file.configs[input.agent];
33
- const record = {
34
- agent: input.agent,
35
- baseUrl: input.baseUrl?.trim() || existing?.baseUrl,
36
- token: input.token?.trim() || existing?.token,
37
- updatedAt: new Date().toISOString(),
38
- };
39
- file.configs[input.agent] = record;
40
- saveManagedConfig(file);
41
- return record;
42
- }
43
- export function deleteManagedAgentProviderConfig(agent) {
44
- const file = loadManagedConfig();
45
- delete file.configs[agent];
46
- saveManagedConfig(file);
47
- }
48
- export function buildManagedAgentEnv(agent) {
49
- if (!isConfigurableAgent(agent))
50
- return {};
51
- const config = getManagedAgentProviderConfig(agent);
52
- if (!config)
53
- return {};
54
- if (agent === 'codex') {
55
- return compactEnv({
56
- OPENAI_BASE_URL: config.baseUrl,
57
- OPENAI_API_KEY: config.token,
58
- });
59
- }
60
- if (agent === 'claude') {
61
- return compactEnv({
62
- ANTHROPIC_BASE_URL: config.baseUrl,
63
- ANTHROPIC_API_KEY: config.token,
64
- });
65
- }
66
- return compactEnv({
67
- DASHSCOPE_BASE_URL: config.baseUrl,
68
- DASHSCOPE_API_KEY: config.token,
69
- });
70
- }
71
- export function getAgentConfigSummary(agent, env = readLatestUserEnv()) {
72
- if (!isConfigurableAgent(agent))
73
- return undefined;
74
- const managed = getManagedAgentProviderConfig(agent);
75
- if (managed?.token || managed?.baseUrl) {
76
- return toSummary({
77
- agent,
78
- source: 'shennian',
79
- status: managed.token ? 'managed' : 'missing',
80
- baseUrl: managed.baseUrl,
81
- token: managed.token,
82
- tokenPresent: !!managed.token,
83
- });
84
- }
85
- const envConfig = detectFromEnv(agent, env);
86
- if (envConfig.tokenPresent || envConfig.baseUrl) {
87
- return toSummary({
88
- agent,
89
- source: 'env',
90
- status: envConfig.tokenPresent ? 'detected' : 'missing',
91
- baseUrl: envConfig.baseUrl,
92
- token: envConfig.token,
93
- tokenPresent: envConfig.tokenPresent,
94
- });
95
- }
96
- const fileConfig = detectFromKnownConfigFiles(agent);
97
- if (fileConfig.tokenPresent || fileConfig.baseUrl) {
98
- return toSummary({
99
- agent,
100
- source: 'config-file',
101
- status: fileConfig.tokenPresent ? 'detected' : 'missing',
102
- baseUrl: fileConfig.baseUrl,
103
- token: fileConfig.token,
104
- tokenPresent: fileConfig.tokenPresent,
105
- });
106
- }
107
- return toSummary({
108
- agent,
109
- source: 'unknown',
110
- status: 'missing',
111
- tokenPresent: false,
112
- });
113
- }
114
- function loadManagedConfig() {
115
- try {
116
- const parsed = JSON.parse(fs.readFileSync(MANAGED_CONFIG_PATH, 'utf-8'));
117
- return { configs: parsed.configs ?? {} };
118
- }
119
- catch {
120
- return { configs: {} };
121
- }
122
- }
123
- function saveManagedConfig(file) {
124
- fs.mkdirSync(path.dirname(MANAGED_CONFIG_PATH), { recursive: true });
125
- fs.writeFileSync(MANAGED_CONFIG_PATH, JSON.stringify(file, null, 2), { mode: 0o600 });
126
- try {
127
- fs.chmodSync(MANAGED_CONFIG_PATH, 0o600);
128
- }
129
- catch {
130
- // Best effort on filesystems without POSIX modes.
131
- }
132
- }
133
- function compactEnv(env) {
134
- const compacted = {};
135
- for (const [key, value] of Object.entries(env)) {
136
- if (value)
137
- compacted[key] = value;
138
- }
139
- return compacted;
140
- }
141
- function detectFromEnv(agent, env) {
142
- const keys = AGENT_ENV_KEYS[agent];
143
- const baseUrl = firstEnv(env, keys.baseUrl);
144
- const token = firstEnv(env, keys.token);
145
- return { baseUrl, token, tokenPresent: !!token };
146
- }
147
- function firstEnv(env, keys) {
148
- for (const key of keys) {
149
- const value = env[key]?.trim();
150
- if (value)
151
- return value;
152
- }
153
- return undefined;
154
- }
155
- function detectFromKnownConfigFiles(agent) {
156
- const home = os.homedir();
157
- if (agent === 'pi') {
158
- const config = loadConfig();
159
- const token = config.apiKeys?.dashscope?.trim();
160
- if (token)
161
- return { token, tokenPresent: true };
162
- }
163
- const candidates = agent === 'codex'
164
- ? [path.join(home, '.codex', 'config.toml'), path.join(home, '.codex', 'auth.json')]
165
- : agent === 'claude'
166
- ? [path.join(home, '.claude', 'settings.json'), path.join(home, '.claude.json')]
167
- : [path.join(home, '.dashscope', 'config.json')];
168
- for (const file of candidates) {
169
- const text = readSmallTextFile(file);
170
- if (!text)
171
- continue;
172
- const token = extractTokenLikeValue(text, agent);
173
- const baseUrl = extractBaseUrl(text);
174
- if (token || baseUrl)
175
- return { token, baseUrl, tokenPresent: !!token };
176
- }
177
- return { tokenPresent: false };
178
- }
179
- function readSmallTextFile(file) {
180
- try {
181
- const stat = fs.statSync(file);
182
- if (!stat.isFile() || stat.size > 1024 * 1024)
183
- return null;
184
- return fs.readFileSync(file, 'utf-8');
185
- }
186
- catch {
187
- return null;
188
- }
189
- }
190
- function extractBaseUrl(text) {
191
- const match = text.match(/(?:base_url|baseURL|api_url|apiUrl|ANTHROPIC_BASE_URL|OPENAI_BASE_URL|DASHSCOPE_BASE_URL)["'\s:=]+([^"'\s,}]+)/i);
192
- return match?.[1]?.trim();
193
- }
194
- function extractTokenLikeValue(text, agent) {
195
- const prefix = agent === 'claude' ? 'sk-ant-' : agent === 'pi' ? 'sk-' : 'sk-';
196
- const direct = text.match(new RegExp(`${prefix.replace(/-/g, '\\-')}[A-Za-z0-9_\\-]{8,}`));
197
- if (direct?.[0])
198
- return direct[0];
199
- const keyMatch = text.match(/(?:api[_-]?key|auth[_-]?token|token|dashscope)["'\s:=]+([A-Za-z0-9_\-.]{12,})/i);
200
- return keyMatch?.[1]?.trim();
201
- }
202
- function toSummary(input) {
203
- return {
204
- status: input.status,
205
- source: input.source,
206
- tokenPresent: input.tokenPresent,
207
- ...(input.baseUrl ? { baseUrlHost: formatBaseUrlHost(input.baseUrl) } : {}),
208
- ...(input.token ? { tokenHint: maskToken(input.token) } : {}),
209
- updatedAt: new Date().toISOString(),
210
- };
211
- }
212
- export function maskToken(token) {
213
- const trimmed = token.trim();
214
- if (!trimmed)
215
- return '';
216
- const suffix = trimmed.slice(-TOKEN_SUFFIX_LENGTH);
217
- return `••••${suffix}`;
218
- }
219
- function formatBaseUrlHost(baseUrl) {
220
- try {
221
- return new URL(baseUrl).host || baseUrl;
222
- }
223
- catch {
224
- return baseUrl.replace(/^https?:\/\//i, '').replace(/\/.*$/, '') || baseUrl;
225
- }
226
- }
1
+ import s from"node:fs";import m from"node:os";import i from"node:path";import{readLatestUserEnv as E}from"../agent-env.js";import{loadConfig as S,resolveShennianPath as g}from"../config/index.js";const c=g("agent-provider-config.json"),U=4;function A(e){return e==="codex"||e==="claude"||e==="pi"}const O={codex:{baseUrl:["OPENAI_BASE_URL","OPENAI_API_BASE","OPENAI_API_URL"],token:["OPENAI_API_KEY","OPENAI_TOKEN"]},claude:{baseUrl:["ANTHROPIC_BASE_URL","ANTHROPIC_API_URL"],token:["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN"]},pi:{baseUrl:["DASHSCOPE_BASE_URL","DASHSCOPE_API_BASE","DASHSCOPE_API_URL"],token:["DASHSCOPE_API_KEY","DASHSCOPE_TOKEN"]}};function k(e){return u().configs[e]}function v(e){const n=u(),o=n.configs[e.agent],t={agent:e.agent,baseUrl:e.baseUrl?.trim()||o?.baseUrl,token:e.token?.trim()||o?.token,updatedAt:new Date().toISOString()};return n.configs[e.agent]=t,_(n),t}function B(e){const n=u();delete n.configs[e],_(n)}function K(e){if(!A(e))return{};const n=k(e);return n?l(e==="codex"?{OPENAI_BASE_URL:n.baseUrl,OPENAI_API_KEY:n.token}:e==="claude"?{ANTHROPIC_BASE_URL:n.baseUrl,ANTHROPIC_API_KEY:n.token}:{DASHSCOPE_BASE_URL:n.baseUrl,DASHSCOPE_API_KEY:n.token}):{}}function j(e,n=E()){if(!A(e))return;const o=k(e);if(o?.token||o?.baseUrl)return a({agent:e,source:"shennian",status:o.token?"managed":"missing",baseUrl:o.baseUrl,token:o.token,tokenPresent:!!o.token});const t=I(e,n);if(t.tokenPresent||t.baseUrl)return a({agent:e,source:"env",status:t.tokenPresent?"detected":"missing",baseUrl:t.baseUrl,token:t.token,tokenPresent:t.tokenPresent});const r=p(e);return r.tokenPresent||r.baseUrl?a({agent:e,source:"config-file",status:r.tokenPresent?"detected":"missing",baseUrl:r.baseUrl,token:r.token,tokenPresent:r.tokenPresent}):a({agent:e,source:"unknown",status:"missing",tokenPresent:!1})}function u(){try{return{configs:JSON.parse(s.readFileSync(c,"utf-8")).configs??{}}}catch{return{configs:{}}}}function _(e){s.mkdirSync(i.dirname(c),{recursive:!0}),s.writeFileSync(c,JSON.stringify(e,null,2),{mode:384});try{s.chmodSync(c,384)}catch{}}function l(e){const n={};for(const[o,t]of Object.entries(e))t&&(n[o]=t);return n}function I(e,n){const o=O[e],t=P(n,o.baseUrl),r=P(n,o.token);return{baseUrl:t,token:r,tokenPresent:!!r}}function P(e,n){for(const o of n){const t=e[o]?.trim();if(t)return t}}function p(e){const n=m.homedir();if(e==="pi"){const r=S().apiKeys?.dashscope?.trim();if(r)return{token:r,tokenPresent:!0}}const o=e==="codex"?[i.join(n,".codex","config.toml"),i.join(n,".codex","auth.json")]:e==="claude"?[i.join(n,".claude","settings.json"),i.join(n,".claude.json")]:[i.join(n,".dashscope","config.json")];for(const t of o){const r=C(t);if(!r)continue;const f=N(r,e),d=b(r);if(f||d)return{token:f,baseUrl:d,tokenPresent:!!f}}return{tokenPresent:!1}}function C(e){try{const n=s.statSync(e);return!n.isFile()||n.size>1024*1024?null:s.readFileSync(e,"utf-8")}catch{return null}}function b(e){return e.match(/(?:base_url|baseURL|api_url|apiUrl|ANTHROPIC_BASE_URL|OPENAI_BASE_URL|DASHSCOPE_BASE_URL)["'\s:=]+([^"'\s,}]+)/i)?.[1]?.trim()}function N(e,n){const o=n==="claude"?"sk-ant-":"sk-",t=e.match(new RegExp(`${o.replace(/-/g,"\\-")}[A-Za-z0-9_\\-]{8,}`));return t?.[0]?t[0]:e.match(/(?:api[_-]?key|auth[_-]?token|token|dashscope)["'\s:=]+([A-Za-z0-9_\-.]{12,})/i)?.[1]?.trim()}function a(e){return{status:e.status,source:e.source,tokenPresent:e.tokenPresent,...e.baseUrl?{baseUrlHost:R(e.baseUrl)}:{},...e.token?{tokenHint:h(e.token)}:{},updatedAt:new Date().toISOString()}}function h(e){const n=e.trim();return n?`\u2022\u2022\u2022\u2022${n.slice(-U)}`:""}function R(e){try{return new URL(e).host||e}catch{return e.replace(/^https?:\/\//i,"").replace(/\/.*$/,"")||e}}export{K as buildManagedAgentEnv,B as deleteManagedAgentProviderConfig,j as getAgentConfigSummary,k as getManagedAgentProviderConfig,h as maskToken,v as upsertManagedAgentProviderConfig};