gitnexus 1.6.8-rc.43 → 1.6.8-rc.44

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 (33) hide show
  1. package/dist/server/api.d.ts +17 -0
  2. package/dist/server/api.js +61 -5
  3. package/dist/server/git-clone.d.ts +41 -1
  4. package/dist/server/git-clone.js +197 -11
  5. package/package.json +1 -1
  6. package/web/assets/{agent-lSrfPH05.js → agent-BZFcfmVS.js} +1 -1
  7. package/web/assets/{architectureDiagram-UL44E2DR-CgHRMZJ8.js → architectureDiagram-UL44E2DR-CC6YeZjE.js} +1 -1
  8. package/web/assets/{chunk-LCXTWHL2-03IqIAdZ.js → chunk-LCXTWHL2-ehYBXKwO.js} +1 -1
  9. package/web/assets/{chunk-RG4AUYOV-DLFjj1rt.js → chunk-RG4AUYOV-2GU6ShCB.js} +1 -1
  10. package/web/assets/{classDiagram-KGZ6W3CR-BTr7xsR8.js → classDiagram-KGZ6W3CR-Du-aRyou.js} +1 -1
  11. package/web/assets/{classDiagram-v2-72OJOZXJ-CakV709X.js → classDiagram-v2-72OJOZXJ-OTZof5RN.js} +1 -1
  12. package/web/assets/{diagram-3NCE3AQN-BW6iSZhw.js → diagram-3NCE3AQN-C_FW_H06.js} +1 -1
  13. package/web/assets/{diagram-GF46GFSD-5IsY7kfK.js → diagram-GF46GFSD-CPue67d6.js} +1 -1
  14. package/web/assets/{diagram-QXG6HAR7-Cia81gsm.js → diagram-QXG6HAR7-C15do1g5.js} +1 -1
  15. package/web/assets/{diagram-WEQXMOUZ-CLfT1sdo.js → diagram-WEQXMOUZ-4OqFacRe.js} +1 -1
  16. package/web/assets/{erDiagram-L5TCEMPS-DqEAcwC_.js → erDiagram-L5TCEMPS-BNwZauWu.js} +1 -1
  17. package/web/assets/{flowDiagram-H6V6AXG4-BUEpeW9m.js → flowDiagram-H6V6AXG4-kyetTRlI.js} +1 -1
  18. package/web/assets/{index-64YMDMOE.js → index-B_ksxgRo.js} +84 -84
  19. package/web/assets/{index-DeuHlyzm.css → index-_lgn7hs5.css} +1 -1
  20. package/web/assets/{infoDiagram-3YFTVSEB-hHbd_QCD.js → infoDiagram-3YFTVSEB-CpzasHwn.js} +1 -1
  21. package/web/assets/{ishikawaDiagram-BNXS4ZKH-XxO6eDu4.js → ishikawaDiagram-BNXS4ZKH-ag_Rd7pn.js} +1 -1
  22. package/web/assets/{kanban-definition-75IXJCU3-DeSVq5eO.js → kanban-definition-75IXJCU3-C6XM-FIC.js} +1 -1
  23. package/web/assets/{mindmap-definition-2TDM6QVE-CgEl9e61.js → mindmap-definition-2TDM6QVE-FiwxZu84.js} +1 -1
  24. package/web/assets/{pieDiagram-CU6KROY3-E3RA4hXq.js → pieDiagram-CU6KROY3-BnAQSSDK.js} +1 -1
  25. package/web/assets/{requirementDiagram-JXO7QTGE-B70bTqxy.js → requirementDiagram-JXO7QTGE-DazbQFgq.js} +1 -1
  26. package/web/assets/{sequenceDiagram-VS2MUI6T-CLt7nidU.js → sequenceDiagram-VS2MUI6T-COXrxbBh.js} +1 -1
  27. package/web/assets/{stateDiagram-7D4R322I-DfdeOa9A.js → stateDiagram-7D4R322I-DdTDJnHs.js} +1 -1
  28. package/web/assets/{stateDiagram-v2-36443NZ5-C-c52-8M.js → stateDiagram-v2-36443NZ5-BNyEew0I.js} +1 -1
  29. package/web/assets/{timeline-definition-O6YCAMPW-8DBKNdJr.js → timeline-definition-O6YCAMPW-DGlWC8rx.js} +1 -1
  30. package/web/assets/{vennDiagram-MWXL3ELB-DhqnfFx6.js → vennDiagram-MWXL3ELB-XCUXE6XL.js} +1 -1
  31. package/web/assets/{wardleyDiagram-CUQ6CDDI-DcliVPWw.js → wardleyDiagram-CUQ6CDDI-GsPjEa48.js} +1 -1
  32. package/web/assets/{xychartDiagram-N2JHSOCM-CYmW296g.js → xychartDiagram-N2JHSOCM-Bc8P_Tyo.js} +1 -1
  33. package/web/index.html +2 -2
@@ -72,5 +72,22 @@ export declare const handleFileRequest: (req: {
72
72
  export declare const handleQueryRequest: (req: express.Request, res: express.Response, resolveRepo: (repoName?: string) => Promise<{
73
73
  storagePath: string;
74
74
  } | undefined>) => Promise<void>;
75
+ /**
76
+ * Validate the optional `token` field of POST /api/analyze. Returns an
77
+ * { status, error } to send, or null when the token is absent or valid.
78
+ *
79
+ * The token is a GitHub PAT: charset-restricted (blocks CRLF header
80
+ * smuggling), length-bounded (1–256), and bound to github.com using the SAME
81
+ * GITHUB_TOKEN_HOSTS allowlist + hostname parse as resolveGitCredential, so a
82
+ * token the API accepts is exactly the one buildGitEnv will inject — and one
83
+ * it rejects is never sent off github.com.
84
+ *
85
+ * Exported for unit tests (the route validation is otherwise only reachable
86
+ * by booting the server).
87
+ */
88
+ export declare function validateAnalyzeToken(repoToken: unknown, repoUrl: unknown): {
89
+ status: number;
90
+ error: string;
91
+ } | null;
75
92
  export declare const createServer: (port: number, host?: string) => Promise<void>;
76
93
  export {};
@@ -23,7 +23,7 @@ import { mountMCPEndpoints } from './mcp-http.js';
23
23
  import { fileURLToPath } from 'url';
24
24
  import { JobManager } from './analyze-job.js';
25
25
  import { assertString, escapeRegExp, BadRequestError, createRouteLimiter } from './validation.js';
26
- import { extractRepoName, getCloneDir, cloneOrPull } from './git-clone.js';
26
+ import { extractRepoName, getCloneDir, cloneOrPull, warnIfInsecureAzureConfig, GITHUB_TOKEN_HOSTS, } from './git-clone.js';
27
27
  import { createAnalyzeUploadHandler } from './analyze-upload.js';
28
28
  import { createLocalhostOriginGuard, normalizeBoundHost } from './middleware.js';
29
29
  import { createLaunchAnalysisWorker } from './analyze-launch.js';
@@ -580,7 +580,45 @@ export const handleQueryRequest = async (req, res, resolveRepo) => {
580
580
  res.status(500).json({ error: err.message || 'Query failed' });
581
581
  }
582
582
  };
583
+ /**
584
+ * Validate the optional `token` field of POST /api/analyze. Returns an
585
+ * { status, error } to send, or null when the token is absent or valid.
586
+ *
587
+ * The token is a GitHub PAT: charset-restricted (blocks CRLF header
588
+ * smuggling), length-bounded (1–256), and bound to github.com using the SAME
589
+ * GITHUB_TOKEN_HOSTS allowlist + hostname parse as resolveGitCredential, so a
590
+ * token the API accepts is exactly the one buildGitEnv will inject — and one
591
+ * it rejects is never sent off github.com.
592
+ *
593
+ * Exported for unit tests (the route validation is otherwise only reachable
594
+ * by booting the server).
595
+ */
596
+ export function validateAnalyzeToken(repoToken, repoUrl) {
597
+ if (repoToken === undefined)
598
+ return null;
599
+ if (typeof repoToken !== 'string')
600
+ return { status: 400, error: '"token" must be a string' };
601
+ if (repoToken.length === 0 || repoToken.length > 256)
602
+ return { status: 400, error: '"token" length must be between 1 and 256' };
603
+ if (!/^[A-Za-z0-9._~+/=-]+$/.test(repoToken))
604
+ return { status: 400, error: '"token" contains invalid characters' };
605
+ if (!repoUrl || typeof repoUrl !== 'string')
606
+ return { status: 400, error: '"token" requires "url"' };
607
+ let tokenHost;
608
+ try {
609
+ tokenHost = new URL(repoUrl).hostname.toLowerCase();
610
+ }
611
+ catch {
612
+ return { status: 400, error: '"url" must be a valid URL when "token" is provided' };
613
+ }
614
+ if (!GITHUB_TOKEN_HOSTS.has(tokenHost))
615
+ return { status: 400, error: '"token" is only supported for github.com URLs' };
616
+ return null;
617
+ }
583
618
  export const createServer = async (port, host = '127.0.0.1') => {
619
+ // Surface a cleartext Azure DevOps PAT config at boot (operators rarely
620
+ // read per-request logs). Warn-only — http:// self-hosted stays supported.
621
+ warnIfInsecureAzureConfig();
584
622
  const app = express();
585
623
  app.disable('x-powered-by');
586
624
  // Trust X-Forwarded-* headers only when the connection comes from the
@@ -1272,7 +1310,7 @@ export const createServer = async (port, host = '127.0.0.1') => {
1272
1310
  // POST /api/analyze — start a new analysis job
1273
1311
  app.post('/api/analyze', createRouteLimiter({ limit: 10 }), requireLocalhostOrigin, async (req, res) => {
1274
1312
  try {
1275
- const { url: repoUrl, path: repoLocalPath, force, embeddings, dropEmbeddings } = req.body;
1313
+ const { url: repoUrl, path: repoLocalPath, force, embeddings, dropEmbeddings, token: repoToken, } = req.body;
1276
1314
  // Input type validation
1277
1315
  if (repoUrl !== undefined && typeof repoUrl !== 'string') {
1278
1316
  res.status(400).json({ error: '"url" must be a string' });
@@ -1286,6 +1324,13 @@ export const createServer = async (port, host = '127.0.0.1') => {
1286
1324
  res.status(400).json({ error: 'Provide "url" (git URL) or "path" (local path)' });
1287
1325
  return;
1288
1326
  }
1327
+ // Token: optional, restricted charset to prevent header smuggling
1328
+ // (CRLF), bound length, and bound to github.com (see validateAnalyzeToken).
1329
+ const tokenError = validateAnalyzeToken(repoToken, repoUrl);
1330
+ if (tokenError) {
1331
+ res.status(tokenError.status).json({ error: tokenError.error });
1332
+ return;
1333
+ }
1289
1334
  // Path validation. The previous `normalize !== resolve` guard was inert
1290
1335
  // (both collapse `..` identically) and only false-rejected trailing
1291
1336
  // slashes, so it is dropped. Analyzing a local path the operator names
@@ -1302,9 +1347,20 @@ export const createServer = async (port, host = '127.0.0.1') => {
1302
1347
  return;
1303
1348
  }
1304
1349
  const job = jobManager.createJob({ repoUrl, repoPath: repoLocalPath });
1305
- // If job was already running (dedup), just return its id
1350
+ // If job was already running (dedup), just return its id. The token is
1351
+ // not part of the dedup identity and is never stored on the job, so a
1352
+ // token on THIS request had no effect — the existing job already
1353
+ // cloned (or is cloning) with whatever credentials its originating
1354
+ // request supplied. Surface `tokenIgnored` so an authenticated caller
1355
+ // isn't misled into thinking their PAT took effect on a reused job.
1306
1356
  if (job.status !== 'queued') {
1307
- res.status(202).json({ jobId: job.id, status: job.status });
1357
+ const body = {
1358
+ jobId: job.id,
1359
+ status: job.status,
1360
+ };
1361
+ if (repoToken !== undefined)
1362
+ body.tokenIgnored = true;
1363
+ res.status(202).json(body);
1308
1364
  return;
1309
1365
  }
1310
1366
  // Mark as active synchronously to prevent race with concurrent requests
@@ -1326,7 +1382,7 @@ export const createServer = async (port, host = '127.0.0.1') => {
1326
1382
  jobManager.updateJob(job.id, {
1327
1383
  progress: { phase: progress.phase, percent: 5, message: progress.message },
1328
1384
  });
1329
- });
1385
+ }, repoToken ? { token: repoToken } : undefined);
1330
1386
  }
1331
1387
  if (!targetPath) {
1332
1388
  throw new Error('No target path resolved');
@@ -35,6 +35,25 @@ export interface CloneProgress {
35
35
  *
36
36
  * Exported so the separator placement is testable without mocking spawn.
37
37
  */
38
+ /**
39
+ * Detect Azure DevOps URLs — both self-hosted (via AZURE_DEVOPS_URL env)
40
+ * and cloud (dev.azure.com / *.visualstudio.com).
41
+ *
42
+ * Self-hosted Azure DevOps Server instances use arbitrary hostnames
43
+ * (e.g. `http://tfs.corp.example/Collection/Project/_git/Repo`), so the
44
+ * function checks `AZURE_DEVOPS_URL` first. Cloud addresses are a
45
+ * hardcoded fallback so PAT injection works out-of-the-box for
46
+ * dev.azure.com without extra configuration.
47
+ */
48
+ export declare function isAzureDevOpsUrl(url: string): boolean;
49
+ /**
50
+ * One-time startup warning when AZURE_DEVOPS_URL is configured over cleartext
51
+ * http:// — the Azure DevOps PAT would then be sent unencrypted on every
52
+ * clone. Self-hosted instances that only serve http are still supported (we
53
+ * do not refuse), but operators rarely read request-time logs, so surface it
54
+ * at boot too. Call once from server startup.
55
+ */
56
+ export declare function warnIfInsecureAzureConfig(): void;
38
57
  export declare function buildCloneArgs(url: string, targetDir: string): string[];
39
58
  /**
40
59
  * Normalize a git URL into a comparable form.
@@ -97,4 +116,25 @@ export declare function assertRemoteMatchesRequestedUrl(targetDir: string, reque
97
116
  * `--` (e.g. `--upload-pack=evil`) cannot be interpreted as a git option
98
117
  * (CodeQL js/second-order-command-line-injection).
99
118
  */
100
- export declare function cloneOrPull(url: string, targetDir: string, onProgress?: (progress: CloneProgress) => void): Promise<string>;
119
+ export declare function cloneOrPull(url: string, targetDir: string, onProgress?: (progress: CloneProgress) => void, options?: {
120
+ token?: string;
121
+ }): Promise<string>;
122
+ /**
123
+ * Hosts the per-request GitHub PAT may be sent to. Exported so the
124
+ * /api/analyze boundary check and this injection-site check share one
125
+ * allowlist (they must agree, or a token accepted by the API could be
126
+ * silently dropped — or worse — at injection).
127
+ */
128
+ export declare const GITHUB_TOKEN_HOSTS: ReadonlySet<string>;
129
+ /**
130
+ * Build the spawn env for `git`. Suppresses credential prompts and, when a
131
+ * credential resolves (see resolveGitCredential), injects a single
132
+ * host-scoped Authorization header via the `GIT_CONFIG_*` env protocol
133
+ * (git ≥2.31) so credentials never appear in argv or the URL. Appends after
134
+ * any existing `GIT_CONFIG_COUNT` rather than overwriting it. Exported for
135
+ * unit tests.
136
+ */
137
+ export declare function buildGitEnv(baseEnv: NodeJS.ProcessEnv, options?: {
138
+ token?: string;
139
+ url?: string;
140
+ }): NodeJS.ProcessEnv;
@@ -197,6 +197,60 @@ function assertNotPrivateIPv4(ip) {
197
197
  *
198
198
  * Exported so the separator placement is testable without mocking spawn.
199
199
  */
200
+ /**
201
+ * Detect Azure DevOps URLs — both self-hosted (via AZURE_DEVOPS_URL env)
202
+ * and cloud (dev.azure.com / *.visualstudio.com).
203
+ *
204
+ * Self-hosted Azure DevOps Server instances use arbitrary hostnames
205
+ * (e.g. `http://tfs.corp.example/Collection/Project/_git/Repo`), so the
206
+ * function checks `AZURE_DEVOPS_URL` first. Cloud addresses are a
207
+ * hardcoded fallback so PAT injection works out-of-the-box for
208
+ * dev.azure.com without extra configuration.
209
+ */
210
+ export function isAzureDevOpsUrl(url) {
211
+ try {
212
+ // Strip a single trailing dot: `dev.azure.com.` is a valid absolute FQDN
213
+ // that resolves to the same host, so it must match too.
214
+ const host = new URL(url).hostname.toLowerCase().replace(/\.$/, '');
215
+ // Self-hosted: match against the configured base URL.
216
+ const configuredBase = process.env.AZURE_DEVOPS_URL;
217
+ if (configuredBase) {
218
+ try {
219
+ const baseHost = new URL(configuredBase).hostname.toLowerCase().replace(/\.$/, '');
220
+ if (host === baseHost)
221
+ return true;
222
+ }
223
+ catch {
224
+ /* invalid AZURE_DEVOPS_URL — fall through to cloud check */
225
+ }
226
+ }
227
+ // Cloud fallback.
228
+ return host === 'dev.azure.com' || host.endsWith('.visualstudio.com');
229
+ }
230
+ catch {
231
+ return false;
232
+ }
233
+ }
234
+ /**
235
+ * One-time startup warning when AZURE_DEVOPS_URL is configured over cleartext
236
+ * http:// — the Azure DevOps PAT would then be sent unencrypted on every
237
+ * clone. Self-hosted instances that only serve http are still supported (we
238
+ * do not refuse), but operators rarely read request-time logs, so surface it
239
+ * at boot too. Call once from server startup.
240
+ */
241
+ export function warnIfInsecureAzureConfig() {
242
+ const base = process.env.AZURE_DEVOPS_URL;
243
+ if (!base)
244
+ return;
245
+ try {
246
+ if (new URL(base).protocol === 'http:') {
247
+ logger.warn('AZURE_DEVOPS_URL is configured over cleartext http:// — the Azure DevOps PAT will be sent unencrypted. Prefer https:// where your instance supports it.');
248
+ }
249
+ }
250
+ catch {
251
+ /* invalid AZURE_DEVOPS_URL — isAzureDevOpsUrl already tolerates this */
252
+ }
253
+ }
200
254
  export function buildCloneArgs(url, targetDir) {
201
255
  return ['clone', '--depth', '1', '--', url, targetDir];
202
256
  }
@@ -327,7 +381,7 @@ export async function assertRemoteMatchesRequestedUrl(targetDir, requestedUrl) {
327
381
  * `--` (e.g. `--upload-pack=evil`) cannot be interpreted as a git option
328
382
  * (CodeQL js/second-order-command-line-injection).
329
383
  */
330
- export async function cloneOrPull(url, targetDir, onProgress) {
384
+ export async function cloneOrPull(url, targetDir, onProgress, options) {
331
385
  // Containment barrier — inline with the canonical path.relative idiom so
332
386
  // CodeQL recognizes the sanitizer at every following filesystem and
333
387
  // subprocess sink. The same `safeTarget` is used for every downstream
@@ -355,28 +409,160 @@ export async function cloneOrPull(url, targetDir, onProgress) {
355
409
  // whatever remote the dir was originally cloned from.
356
410
  await assertRemoteMatchesRequestedUrl(safeTarget, url);
357
411
  onProgress?.({ phase: 'pulling', message: 'Pulling latest changes...' });
358
- await runGit(['pull', '--ff-only'], safeTarget);
412
+ await runGit(['pull', '--ff-only'], safeTarget, { token: options?.token, url });
359
413
  }
360
414
  else {
361
415
  await fs.mkdir(path.dirname(safeTarget), { recursive: true });
362
416
  onProgress?.({ phase: 'cloning', message: `Cloning ${url}...` });
363
- await runGit(buildCloneArgs(url, safeTarget));
417
+ await runGit(buildCloneArgs(url, safeTarget), undefined, { token: options?.token, url });
364
418
  }
365
419
  return safeTarget;
366
420
  }
367
- function runGit(args, cwd) {
421
+ /**
422
+ * Hosts the per-request GitHub PAT may be sent to. Exported so the
423
+ * /api/analyze boundary check and this injection-site check share one
424
+ * allowlist (they must agree, or a token accepted by the API could be
425
+ * silently dropped — or worse — at injection).
426
+ */
427
+ export const GITHUB_TOKEN_HOSTS = new Set(['github.com', 'www.github.com']);
428
+ /**
429
+ * Resolve at most ONE git credential for a clone/pull, by server-side policy
430
+ * keyed on the clone host against a fixed allowlist (never a free-form user
431
+ * toggle):
432
+ * 1. a per-request GitHub PAT — only for hosts in GITHUB_TOKEN_HOSTS;
433
+ * 2. else the server's AZURE_DEVOPS_PAT — only for Azure DevOps hosts;
434
+ * 3. else none.
435
+ * The two host sets are disjoint, so at most one credential ever applies; the
436
+ * GitHub token taking precedence is deterministic for the pathological case
437
+ * where AZURE_DEVOPS_URL is itself configured to a github.com host. Returns
438
+ * the base64 of the Basic-auth `user:secret` pair, or undefined.
439
+ *
440
+ * Security note (re CodeQL js/user-controlled-bypass): the clone URL is
441
+ * user-controlled and selects WHICH credential applies, but it cannot
442
+ * redirect a credential to an arbitrary host — the host is matched against
443
+ * fixed server-side allowlists (GITHUB_TOKEN_HOSTS, isAzureDevOpsUrl's
444
+ * dev.azure.com/*.visualstudio.com/configured AZURE_DEVOPS_URL), and the
445
+ * emitted header is host-scoped (buildExtraHeaderKey). A URL outside the
446
+ * allowlists yields no credential. The selection is therefore server-policy,
447
+ * not a bypass the user can steer.
448
+ */
449
+ function resolveGitCredential(options) {
450
+ const url = options?.url;
451
+ if (!url)
452
+ return undefined;
453
+ let host;
454
+ try {
455
+ host = new URL(url).hostname.toLowerCase();
456
+ }
457
+ catch {
458
+ return undefined;
459
+ }
460
+ // 1. Per-request GitHub PAT — github.com only (mirrors the /api/analyze
461
+ // host-bind so the user's token is never sent off github.com).
462
+ if (options.token && GITHUB_TOKEN_HOSTS.has(host)) {
463
+ return Buffer.from(`x-access-token:${options.token}`).toString('base64');
464
+ }
465
+ // 2. Server-configured Azure DevOps PAT — Azure hosts only.
466
+ const azurePat = process.env.AZURE_DEVOPS_PAT;
467
+ if (azurePat && isAzureDevOpsUrl(url)) {
468
+ return Buffer.from(`:${azurePat}`).toString('base64');
469
+ }
470
+ return undefined;
471
+ }
472
+ /**
473
+ * Build the host-scoped git config key `http.<origin+path>.extraHeader` from
474
+ * the raw clone URL, so the Authorization header is attached only to the
475
+ * intended origin (and its clone sub-requests like /info/refs), never a
476
+ * redirect target. Derived from the SAME raw URL git clones from — not the
477
+ * normalize-for-compare form, which strips `.git` and would desync the key
478
+ * from the wire URL and silently disable the header. Userinfo/query/fragment
479
+ * are dropped (not part of git's URL match) and control characters stripped
480
+ * (git rejects a newline in a config key outright).
481
+ */
482
+ function buildExtraHeaderKey(url) {
483
+ let scoped;
484
+ try {
485
+ const u = new URL(url);
486
+ u.username = '';
487
+ u.password = '';
488
+ u.search = '';
489
+ u.hash = '';
490
+ scoped = `${u.protocol}//${u.host}${u.pathname}`;
491
+ }
492
+ catch {
493
+ return undefined;
494
+ }
495
+ scoped = scoped.replace(/[\r\n\0]/g, '');
496
+ return `http.${scoped}.extraHeader`;
497
+ }
498
+ /**
499
+ * Warn (do not block) when a credential is about to be sent over cleartext
500
+ * http://. Base64 is encoding, not encryption, so an on-path observer can
501
+ * read the PAT. We keep http:// working for self-hosted Azure DevOps Server.
502
+ */
503
+ function warnIfCleartextCredential(url) {
504
+ if (!url)
505
+ return;
506
+ try {
507
+ const u = new URL(url);
508
+ if (u.protocol === 'http:') {
509
+ logger.warn(`Sending a git credential over cleartext http:// (${u.host}) — base64 is not encryption. Prefer https:// where the host supports it.`);
510
+ }
511
+ }
512
+ catch {
513
+ /* resolver already validated the URL */
514
+ }
515
+ }
516
+ /**
517
+ * Build the spawn env for `git`. Suppresses credential prompts and, when a
518
+ * credential resolves (see resolveGitCredential), injects a single
519
+ * host-scoped Authorization header via the `GIT_CONFIG_*` env protocol
520
+ * (git ≥2.31) so credentials never appear in argv or the URL. Appends after
521
+ * any existing `GIT_CONFIG_COUNT` rather than overwriting it. Exported for
522
+ * unit tests.
523
+ */
524
+ export function buildGitEnv(baseEnv, options) {
525
+ const env = {
526
+ ...baseEnv,
527
+ // Prevent git from prompting for credentials (hangs the process)
528
+ GIT_TERMINAL_PROMPT: '0',
529
+ // Ensure no credential helper tries to open a GUI prompt
530
+ GIT_ASKPASS: process.platform === 'win32' ? 'echo' : '/bin/true',
531
+ // Scrub git's HTTP/transport trace vars: if inherited from the parent
532
+ // process they dump every request header — including the injected
533
+ // Authorization header — to stderr, which runGit captures and logs.
534
+ // `undefined` makes child_process omit the key from the child env.
535
+ GIT_TRACE: undefined,
536
+ GIT_TRACE_CURL: undefined,
537
+ GIT_TRACE_PACKET: undefined,
538
+ GIT_CURL_VERBOSE: undefined,
539
+ };
540
+ const credential = resolveGitCredential(options);
541
+ const key = options?.url ? buildExtraHeaderKey(options.url) : undefined;
542
+ if (credential && key) {
543
+ // Append after any GIT_CONFIG_* the operator already set, so we never
544
+ // clobber their git config (e.g. an enforced http.sslVerify).
545
+ const existing = Number.parseInt(env.GIT_CONFIG_COUNT ?? '', 10);
546
+ const base = Number.isInteger(existing) && existing > 0 ? existing : 0;
547
+ env.GIT_CONFIG_COUNT = String(base + 1);
548
+ env[`GIT_CONFIG_KEY_${base}`] = key;
549
+ env[`GIT_CONFIG_VALUE_${base}`] = `Authorization: Basic ${credential}`;
550
+ warnIfCleartextCredential(options?.url);
551
+ }
552
+ return env;
553
+ }
554
+ // `options` carries the inputs the credential resolver needs: a per-request
555
+ // GitHub `token` and the clone `url`. buildGitEnv injects at most ONE
556
+ // host-scoped Authorization header (GitHub PAT for github.com, else the
557
+ // server's AZURE_DEVOPS_PAT for Azure hosts) via the GIT_CONFIG_* protocol —
558
+ // never in argv. See resolveGitCredential / buildExtraHeaderKey.
559
+ function runGit(args, cwd, options) {
368
560
  return new Promise((resolve, reject) => {
369
561
  const proc = spawn('git', args, {
370
562
  cwd,
371
563
  stdio: ['ignore', 'pipe', 'pipe'],
372
564
  windowsHide: true,
373
- env: {
374
- ...process.env,
375
- // Prevent git from prompting for credentials (hangs the process)
376
- GIT_TERMINAL_PROMPT: '0',
377
- // Ensure no credential helper tries to open a GUI prompt
378
- GIT_ASKPASS: process.platform === 'win32' ? 'echo' : '/bin/true',
379
- },
565
+ env: buildGitEnv(process.env, options),
380
566
  });
381
567
  let stderr = '';
382
568
  proc.stderr.on('data', (chunk) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.8-rc.43",
3
+ "version": "1.6.8-rc.44",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",
@@ -1,4 +1,4 @@
1
- import{r as e,t}from"./chunk-CilyBKbf.js";import{o as n,s as r}from"./index-64YMDMOE.js";import{CHAT_ONLY_PROMPT_NOTE as i,buildDynamicSystemPrompt as a}from"./context-builder-C6wAZwss.js";var o=Object.defineProperty,s=(e,t)=>{let n={};for(var r in e)o(n,r,{get:e[r],enumerable:!0});return t||o(n,Symbol.toStringTag,{value:`Module`}),n};function c(e){let t=Symbol.for(e);return{brand(n,r){let i=r?Symbol.for(`${e}.${r}`):t;class a extends n{[i]=!0;constructor(...e){super(...e)}static isInstance(e){return typeof e==`object`&&!!e&&i in e&&e[i]===!0}}return Object.defineProperty(a,`name`,{value:n.name}),a},sub(t){return c(`${e}.${t}`)},isInstance(e){return typeof e==`object`&&!!e&&t in e&&e[t]===!0}}}var l=c(`langchain`),u=s({ContextOverflowError:()=>h,LangChainError:()=>p,ModelAbortError:()=>m,addLangChainErrorFields:()=>d,ns:()=>f});function d(e,t){return e.lc_error_code=t,e.message=`${e.message}\n\nTroubleshooting URL: https://docs.langchain.com/oss/javascript/langchain/errors/${t}/\n`,e}var f=l.sub(`error`),p=class extends f.brand(Error){name=`LangChainError`;constructor(e){super(e),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},m=class extends f.brand(p,`model-abort`){name=`ModelAbortError`;partialOutput;constructor(e,t){super(e),this.partialOutput=t}},h=class e extends f.brand(p,`context-overflow`){name=`ContextOverflowError`;cause;constructor(e){super(e??`Input exceeded the model's context window.`)}static fromError(t){let n=new e(t.message);return n.cause=t,n}};function g(e){return!!(e&&typeof e==`object`&&`type`in e&&e.type===`tool_call`)}function _(e){return!!(e&&typeof e==`object`&&`toolCall`in e&&e.toolCall!=null&&typeof e.toolCall==`object`&&`id`in e.toolCall&&typeof e.toolCall.id==`string`)}var v=class extends Error{output;constructor(e,t){super(e),this.output=t}};function y(e,t=b){e=e.trim();let n=e.indexOf("```");if(n===-1)return t(e);let r=e.substring(n+3);r.startsWith(`json
1
+ import{r as e,t}from"./chunk-CilyBKbf.js";import{o as n,s as r}from"./index-B_ksxgRo.js";import{CHAT_ONLY_PROMPT_NOTE as i,buildDynamicSystemPrompt as a}from"./context-builder-C6wAZwss.js";var o=Object.defineProperty,s=(e,t)=>{let n={};for(var r in e)o(n,r,{get:e[r],enumerable:!0});return t||o(n,Symbol.toStringTag,{value:`Module`}),n};function c(e){let t=Symbol.for(e);return{brand(n,r){let i=r?Symbol.for(`${e}.${r}`):t;class a extends n{[i]=!0;constructor(...e){super(...e)}static isInstance(e){return typeof e==`object`&&!!e&&i in e&&e[i]===!0}}return Object.defineProperty(a,`name`,{value:n.name}),a},sub(t){return c(`${e}.${t}`)},isInstance(e){return typeof e==`object`&&!!e&&t in e&&e[t]===!0}}}var l=c(`langchain`),u=s({ContextOverflowError:()=>h,LangChainError:()=>p,ModelAbortError:()=>m,addLangChainErrorFields:()=>d,ns:()=>f});function d(e,t){return e.lc_error_code=t,e.message=`${e.message}\n\nTroubleshooting URL: https://docs.langchain.com/oss/javascript/langchain/errors/${t}/\n`,e}var f=l.sub(`error`),p=class extends f.brand(Error){name=`LangChainError`;constructor(e){super(e),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},m=class extends f.brand(p,`model-abort`){name=`ModelAbortError`;partialOutput;constructor(e,t){super(e),this.partialOutput=t}},h=class e extends f.brand(p,`context-overflow`){name=`ContextOverflowError`;cause;constructor(e){super(e??`Input exceeded the model's context window.`)}static fromError(t){let n=new e(t.message);return n.cause=t,n}};function g(e){return!!(e&&typeof e==`object`&&`type`in e&&e.type===`tool_call`)}function _(e){return!!(e&&typeof e==`object`&&`toolCall`in e&&e.toolCall!=null&&typeof e.toolCall==`object`&&`id`in e.toolCall&&typeof e.toolCall.id==`string`)}var v=class extends Error{output;constructor(e,t){super(e),this.output=t}};function y(e,t=b){e=e.trim();let n=e.indexOf("```");if(n===-1)return t(e);let r=e.substring(n+3);r.startsWith(`json
2
2
  `)?r=r.substring(5):r.startsWith(`json`)?r=r.substring(4):r.startsWith(`
3
3
  `)&&(r=r.substring(1));let i=r.indexOf("```"),a=r;return i!==-1&&(a=r.substring(0,i)),t(a.trim())}function ee(e){try{return JSON.parse(e)}catch{}let t=e.trim();if(t.length===0)throw Error(`Unexpected end of JSON input`);let n=0;function r(){for(;n<t.length&&/\s/.test(t[n]);)n+=1}function i(){if(t[n]!==`"`)throw Error(`Expected '"' at position ${n}, got '${t[n]}'`);n+=1;let e=``,r=!1;for(;n<t.length;){let i=t[n];if(r){if(i===`n`)e+=`
4
4
  `;else if(i===`t`)e+=` `;else if(i===`r`)e+=`\r`;else if(i===`\\`)e+=`\\`;else if(i===`"`)e+=`"`;else if(i===`b`)e+=`\b`;else if(i===`f`)e+=`\f`;else if(i===`/`)e+=`/`;else if(i===`u`){let r=t.substring(n+1,n+5);if(/^[0-9A-Fa-f]{0,4}$/.test(r))r.length===4?e+=String.fromCharCode(Number.parseInt(r,16)):e+=`u${r}`,n+=r.length;else throw Error(`Invalid unicode escape sequence '\\u${r}' at position ${n}`)}else throw Error(`Invalid escape sequence '\\${i}' at position ${n}`);r=!1}else if(i===`\\`)r=!0;else if(i===`"`)return n+=1,e;else e+=i;n+=1}return r&&(e+=`\\`),e}function a(){let e=n,r=``;if(t[n]===`-`&&(r+=`-`,n+=1),n<t.length&&t[n]===`0`&&(r+=`0`,n+=1,t[n]>=`0`&&t[n]<=`9`))throw Error(`Invalid number at position ${e}`);if(n<t.length&&t[n]>=`1`&&t[n]<=`9`)for(;n<t.length&&t[n]>=`0`&&t[n]<=`9`;)r+=t[n],n+=1;if(n<t.length&&t[n]===`.`)for(r+=`.`,n+=1;n<t.length&&t[n]>=`0`&&t[n]<=`9`;)r+=t[n],n+=1;if(n<t.length&&(t[n]===`e`||t[n]===`E`))for(r+=t[n],n+=1,n<t.length&&(t[n]===`+`||t[n]===`-`)&&(r+=t[n],n+=1);n<t.length&&t[n]>=`0`&&t[n]<=`9`;)r+=t[n],n+=1;if(r===`-`)return-0;let i=Number.parseFloat(r);if(Number.isNaN(i))throw n=e,Error(`Invalid number '${r}' at position ${e}`);return i}function o(){if(r(),n>=t.length)throw Error(`Unexpected end of input at position ${n}`);let e=t[n];if(e===`{`)return c();if(e===`[`)return s();if(e===`"`)return i();if(`null`.startsWith(t.substring(n,n+4)))return n+=Math.min(4,t.length-n),null;if(`true`.startsWith(t.substring(n,n+4)))return n+=Math.min(4,t.length-n),!0;if(`false`.startsWith(t.substring(n,n+5)))return n+=Math.min(5,t.length-n),!1;if(e===`-`||e>=`0`&&e<=`9`)return a();throw Error(`Unexpected character '${e}' at position ${n}`)}function s(){if(t[n]!==`[`)throw Error(`Expected '[' at position ${n}, got '${t[n]}'`);let e=[];if(n+=1,r(),n>=t.length)return e;if(t[n]===`]`)return n+=1,e;for(;n<t.length;){if(r(),n>=t.length||(e.push(o()),r(),n>=t.length))return e;if(t[n]===`]`)return n+=1,e;if(t[n]===`,`){n+=1;continue}throw Error(`Expected ',' or ']' at position ${n}, got '${t[n]}'`)}return e}function c(){if(t[n]!==`{`)throw Error(`Expected '{' at position ${n}, got '${t[n]}'`);let e={};if(n+=1,r(),n>=t.length)return e;if(t[n]===`}`)return n+=1,e;for(;n<t.length;){if(r(),n>=t.length)return e;let a=i();if(r(),n>=t.length)return e;if(t[n]!==`:`)throw Error(`Expected ':' at position ${n}, got '${t[n]}'`);if(n+=1,r(),n>=t.length||(e[a]=o(),r(),n>=t.length))return e;if(t[n]===`}`)return n+=1,e;if(t[n]===`,`){n+=1;continue}throw Error(`Expected ',' or '}' at position ${n}, got '${t[n]}'`)}return e}let l=o();if(r(),n<t.length)throw Error(`Unexpected character '${t[n]}' at position ${n}`);return l}function b(e){try{return e===void 0?null:ee(e)}catch{return null}}var te=/([A-Z]+)([A-Z][a-z0-9]+)/g,ne=/([a-z0-9])([A-Z])/g,x=/[-_\s]+/g;function re(e){return e.replace(te,`$1_$2`).replace(ne,`$1_$2`).replace(x,`_`).toLowerCase()}function ie(e){let t=e.trim();return/[-_\s]/.test(t)?t.replace(x,`_`).toLowerCase().replace(/_+([a-z0-9])/g,(e,t)=>t.toUpperCase()):t}function ae(e,t){return t?.[e]||re(e)}function oe(e,t){return t?.[e]||ie(e)}function se(e,t,n){let r={};for(let i in e)Object.hasOwn(e,i)&&(r[t(i,n)]=e[i]);return r}var ce=`__lc_escaped__`;function le(e){return`lc`in e||Object.keys(e).length===1&&`__lc_escaped__`in e}function S(e){return{[ce]:e}}function ue(e){return Object.keys(e).length===1&&`__lc_escaped__`in e}function de(e){return typeof e==`object`&&!!e&&`lc_serializable`in e&&typeof e.toJSON==`function`}function fe(e){let t;return t=typeof e==`object`&&e?`lc_id`in e&&Array.isArray(e.lc_id)?e.lc_id:[e.constructor?.name??`Object`]:[typeof e],{lc:1,type:`not_implemented`,id:t}}function pe(e,t=new WeakSet){if(typeof e==`object`&&e&&!Array.isArray(e)){if(t.has(e))return fe(e);if(de(e))return e;t.add(e);let n=e;if(le(n))return t.delete(e),S(n);let r={};for(let[e,i]of Object.entries(n))r[e]=pe(i,t);return t.delete(e),r}return Array.isArray(e)?e.map(e=>pe(e,t)):e}function me(e){if(typeof e==`object`&&e&&!Array.isArray(e)){let t=e;if(ue(t))return t[ce];let n={};for(let[e,r]of Object.entries(t))n[e]=me(r);return n}return Array.isArray(e)?e.map(e=>me(e)):e}var he=s({Serializable:()=>ye,get_lc_unique_name:()=>ve});function ge(e){return Array.isArray(e)?[...e]:{...e}}function _e(e,t){let n=ge(e);for(let[e,r]of Object.entries(t)){let[t,...i]=e.split(`.`).reverse(),a=n;for(let e of i.reverse()){if(a[e]===void 0)break;a[e]=ge(a[e]),a=a[e]}a[t]!==void 0&&(a[t]={lc:1,type:`secret`,id:[r]})}return n}function ve(e){let t=Object.getPrototypeOf(e);return typeof e.lc_name==`function`&&(typeof t.lc_name!=`function`||e.lc_name()!==t.lc_name())?e.lc_name():e.name}var ye=class e{lc_serializable=!1;lc_kwargs;static lc_name(){return this.name}get lc_id(){return[...this.lc_namespace,ve(this.constructor)]}get lc_secrets(){}get lc_attributes(){}get lc_aliases(){}get lc_serializable_keys(){}constructor(e,...t){this.lc_serializable_keys===void 0?this.lc_kwargs=e??{}:this.lc_kwargs=Object.fromEntries(Object.entries(e||{}).filter(([e])=>this.lc_serializable_keys?.includes(e)))}toJSON(){if(!this.lc_serializable||this.lc_kwargs instanceof e||typeof this.lc_kwargs!=`object`||Array.isArray(this.lc_kwargs))return this.toJSONNotImplemented();let t={},n={},r=Object.keys(this.lc_kwargs).reduce((e,t)=>(e[t]=t in this?this[t]:this.lc_kwargs[t],e),{});for(let e=Object.getPrototypeOf(this);e;e=Object.getPrototypeOf(e))Object.assign(t,Reflect.get(e,`lc_aliases`,this)),Object.assign(n,Reflect.get(e,`lc_secrets`,this)),Object.assign(r,Reflect.get(e,`lc_attributes`,this));Object.keys(n).forEach(e=>{let t=this,n=r,[i,...a]=e.split(`.`).reverse();for(let e of a.reverse()){if(!(e in t)||t[e]===void 0)return;(!(e in n)||n[e]===void 0)&&(typeof t[e]==`object`&&t[e]!=null?n[e]={}:Array.isArray(t[e])&&(n[e]=[])),t=t[e],n=n[e]}i in t&&t[i]!==void 0&&(n[i]=n[i]||t[i])});let i={},a=new WeakSet;a.add(this);for(let[e,t]of Object.entries(r))i[e]=pe(t,a);let o=se(Object.keys(n).length?_e(i,n):i,ae,t);return{lc:1,type:`constructor`,id:this.lc_id,kwargs:o}}toJSONNotImplemented(){return{lc:1,type:`not_implemented`,id:this.lc_id}}};function be(e){return typeof e==`object`&&!!e&&`type`in e&&typeof e.type==`string`&&`source_type`in e&&(e.source_type===`url`||e.source_type===`base64`||e.source_type===`text`||e.source_type===`id`)}function xe(e){return be(e)&&e.source_type===`url`&&`url`in e&&typeof e.url==`string`}function Se(e){return be(e)&&e.source_type===`base64`&&`data`in e&&typeof e.data==`string`}function Ce(e){return be(e)&&e.source_type===`text`&&`text`in e&&typeof e.text==`string`}function we(e){return be(e)&&e.source_type===`id`&&`id`in e&&typeof e.id==`string`}function Te(e){if(be(e)){if(e.source_type===`url`)return{type:`image_url`,image_url:{url:e.url}};if(e.source_type===`base64`){if(!e.mime_type)throw Error(`mime_type key is required for base64 data.`);return{type:`image_url`,image_url:{url:`data:${e.mime_type};base64,${e.data}`}}}}throw Error(`Unsupported source type. Only 'url' and 'base64' are supported.`)}function Ee(e){let t=e.split(`;`)[0].split(`/`);if(t.length!==2)throw Error(`Invalid mime type: "${e}" - does not match type/subtype format.`);let n=t[0].trim(),r=t[1].trim();if(n===``||r===``)throw Error(`Invalid mime type: "${e}" - type or subtype is empty.`);let i={};for(let t of e.split(`;`).slice(1)){let n=t.split(`=`);if(n.length!==2)throw Error(`Invalid parameter syntax in mime type: "${e}".`);let r=n[0].trim(),a=n[1].trim();if(r===``)throw Error(`Invalid parameter syntax in mime type: "${e}".`);i[r]=a}return{type:n,subtype:r,parameters:i}}function De({dataUrl:e,asTypedArray:t=!1}){let n=e.match(/^data:(\w+\/\w+);base64,([A-Za-z0-9+/]+=*)$/),r;if(n){r=n[1].toLowerCase();let e=t?Uint8Array.from(atob(n[2]),e=>e.charCodeAt(0)):n[2];return{mime_type:r,data:e}}}function Oe(e,t){if(e.type===`text`){if(!t.fromStandardTextBlock)throw Error(`Converter for ${t.providerName} does not implement \`fromStandardTextBlock\` method.`);return t.fromStandardTextBlock(e)}if(e.type===`image`){if(!t.fromStandardImageBlock)throw Error(`Converter for ${t.providerName} does not implement \`fromStandardImageBlock\` method.`);return t.fromStandardImageBlock(e)}if(e.type===`audio`){if(!t.fromStandardAudioBlock)throw Error(`Converter for ${t.providerName} does not implement \`fromStandardAudioBlock\` method.`);return t.fromStandardAudioBlock(e)}if(e.type===`file`){if(!t.fromStandardFileBlock)throw Error(`Converter for ${t.providerName} does not implement \`fromStandardFileBlock\` method.`);return t.fromStandardFileBlock(e)}throw Error(`Unable to convert content block type '${e.type}' to provider-specific format: not recognized.`)}function C(e,t){return w(e)&&e.type===t}function w(e){return typeof e==`object`&&!!e}function ke(e){return Array.isArray(e)}function T(e){return typeof e==`string`}function E(e){return typeof e==`number`}function Ae(e){return e instanceof Uint8Array}function je(e){try{return JSON.parse(e)}catch{return}}var Me=e=>e();function Ne(e){if(e.type===`char_location`&&T(e.document_title)&&E(e.start_char_index)&&E(e.end_char_index)&&T(e.cited_text)){let{document_title:t,start_char_index:n,end_char_index:r,cited_text:i,...a}=e;return{...a,type:`citation`,source:`char`,title:t??void 0,startIndex:n,endIndex:r,citedText:i}}if(e.type===`page_location`&&T(e.document_title)&&E(e.start_page_number)&&E(e.end_page_number)&&T(e.cited_text)){let{document_title:t,start_page_number:n,end_page_number:r,cited_text:i,...a}=e;return{...a,type:`citation`,source:`page`,title:t??void 0,startIndex:n,endIndex:r,citedText:i}}if(e.type===`content_block_location`&&T(e.document_title)&&E(e.start_block_index)&&E(e.end_block_index)&&T(e.cited_text)){let{document_title:t,start_block_index:n,end_block_index:r,cited_text:i,...a}=e;return{...a,type:`citation`,source:`block`,title:t??void 0,startIndex:n,endIndex:r,citedText:i}}if(e.type===`web_search_result_location`&&T(e.url)&&T(e.title)&&T(e.encrypted_index)&&T(e.cited_text)){let{url:t,title:n,encrypted_index:r,cited_text:i,...a}=e;return{...a,type:`citation`,source:`url`,url:t,title:n,startIndex:Number(r),endIndex:Number(r),citedText:i}}if(e.type===`search_result_location`&&T(e.source)&&T(e.title)&&E(e.start_block_index)&&E(e.end_block_index)&&T(e.cited_text)){let{source:t,title:n,start_block_index:r,end_block_index:i,cited_text:a,...o}=e;return{...o,type:`citation`,source:`search`,url:t,title:n??void 0,startIndex:r,endIndex:i,citedText:a}}}function Pe(e){if(C(e,`document`)&&w(e.source)&&`type`in e.source){if(e.source.type===`base64`&&T(e.source.media_type)&&T(e.source.data))return{type:`file`,mimeType:e.source.media_type,data:e.source.data};if(e.source.type===`url`&&T(e.source.url))return{type:`file`,url:e.source.url};if(e.source.type===`file`&&T(e.source.file_id))return{type:`file`,fileId:e.source.file_id};if(e.source.type===`text`&&T(e.source.data))return{type:`file`,mimeType:String(e.source.media_type??`text/plain`),data:e.source.data}}else if(C(e,`image`)&&w(e.source)&&`type`in e.source){if(e.source.type===`base64`&&T(e.source.media_type)&&T(e.source.data))return{type:`image`,mimeType:e.source.media_type,data:e.source.data};if(e.source.type===`url`&&T(e.source.url))return{type:`image`,url:e.source.url};if(e.source.type===`file`&&T(e.source.file_id))return{type:`image`,fileId:e.source.file_id}}}function Fe(e){function*t(){for(let t of e){let e=Pe(t);e?yield e:yield t}}return Array.from(t())}function Ie(e){function*t(){let t=typeof e.content==`string`?[{type:`text`,text:e.content}]:e.content;for(let n of t){if(C(n,`text`)&&T(n.text)){let{text:e,citations:t,...r}=n;if(ke(t)&&t.length){let n=t.reduce((e,t)=>{let n=Ne(t);return n?[...e,n]:e},[]);yield{...r,type:`text`,text:e,annotations:n};continue}else{yield{...r,type:`text`,text:e};continue}}else if(C(n,`thinking`)&&T(n.thinking)){let{thinking:e,signature:t,...r}=n;yield{...r,type:`reasoning`,reasoning:e,signature:t};continue}else if(C(n,`redacted_thinking`)){yield{type:`non_standard`,value:n};continue}else if(C(n,`tool_use`)&&T(n.name)&&T(n.id)){yield{type:`tool_call`,id:n.id,name:n.name,args:n.input};continue}else if(C(n,`input_json_delta`)){if(Re(e)&&e.tool_call_chunks?.length){let t=e.tool_call_chunks[0];yield{type:`tool_call_chunk`,id:t.id,name:t.name,args:t.args,index:t.index};continue}}else if(C(n,`server_tool_use`)&&T(n.name)&&T(n.id)){let{name:e,id:t}=n;if(e===`web_search`){yield{id:t,type:`server_tool_call`,name:`web_search`,args:{query:Me(()=>{if(typeof n.input==`string`)return n.input;if(w(n.input)&&T(n.input.query))return n.input.query;if(T(n.partial_json)){let e=je(n.partial_json);if(e?.query)return e.query}return``})}};continue}else if(n.name===`code_execution`){yield{id:t,type:`server_tool_call`,name:`code_execution`,args:{code:Me(()=>{if(typeof n.input==`string`)return n.input;if(w(n.input)&&T(n.input.code))return n.input.code;if(T(n.partial_json)){let e=je(n.partial_json);if(e?.code)return e.code}return``})}};continue}}else if(C(n,`web_search_tool_result`)&&T(n.tool_use_id)&&ke(n.content)){let{content:e,tool_use_id:t}=n;yield{type:`server_tool_call_result`,name:`web_search`,toolCallId:t,status:`success`,output:{urls:e.reduce((e,t)=>C(t,`web_search_result`)?[...e,t.url]:e,[])}};continue}else if(C(n,`code_execution_tool_result`)&&T(n.tool_use_id)&&w(n.content)){yield{type:`server_tool_call_result`,name:`code_execution`,toolCallId:n.tool_use_id,status:`success`,output:n.content};continue}else if(C(n,`mcp_tool_use`)){yield{id:n.id,type:`server_tool_call`,name:`mcp_tool_use`,args:n.input};continue}else if(C(n,`mcp_tool_result`)&&T(n.tool_use_id)&&w(n.content)){yield{type:`server_tool_call_result`,name:`mcp_tool_use`,toolCallId:n.tool_use_id,status:`success`,output:n.content};continue}else if(C(n,`container_upload`)){yield{type:`server_tool_call`,name:`container_upload`,args:n.input};continue}else if(C(n,`search_result`)){yield{id:n.id,type:`non_standard`,value:n};continue}else if(C(n,`tool_result`)){yield{id:n.id,type:`non_standard`,value:n};continue}else{let e=Pe(n);if(e){yield e;continue}}yield{type:`non_standard`,value:n}}}return Array.from(t())}var Le={translateContent:Ie,translateContentChunk:Ie};function Re(e){return typeof e?._getType==`function`&&typeof e.concat==`function`&&e._getType()===`ai`}function ze(e){return xe(e)?{type:e.type,mimeType:e.mime_type,url:e.url,metadata:e.metadata}:Se(e)?{type:e.type,mimeType:e.mime_type??`application/octet-stream`,data:e.data,metadata:e.metadata}:we(e)?{type:e.type,mimeType:e.mime_type,fileId:e.id,metadata:e.metadata}:e}function Be(e){return e.map(ze)}function Ve(e){return!!(C(e,`image_url`)&&w(e.image_url)||C(e,`input_audio`)&&w(e.input_audio)||C(e,`file`)&&w(e.file))}function He(e){if(C(e,`image_url`)&&w(e.image_url)&&T(e.image_url.url)){let t=De({dataUrl:e.image_url.url});return t?{type:`image`,mimeType:t.mime_type,data:t.data}:{type:`image`,url:e.image_url.url}}else if(C(e,`input_audio`)&&w(e.input_audio)&&T(e.input_audio.data)&&T(e.input_audio.format))return{type:`audio`,data:e.input_audio.data,mimeType:`audio/${e.input_audio.format}`};else if(C(e,`file`)&&w(e.file)&&T(e.file.data)){let t=De({dataUrl:e.file.data});if(t)return{type:`file`,data:t.data,mimeType:t.mime_type};if(T(e.file.file_id))return{type:`file`,fileId:e.file.file_id}}return e}function Ue(e){let t=[];typeof e.content==`string`?e.content.length>0&&t.push({type:`text`,text:e.content}):t.push(...Ge(e.content));for(let n of e.tool_calls??[])t.push({type:`tool_call`,id:n.id,name:n.name,args:n.args});return t}function We(e){let t=[];typeof e.content==`string`?e.content.length>0&&t.push({type:`text`,text:e.content}):t.push(...Ge(e.content));for(let n of e.tool_calls??[])t.push({type:`tool_call`,id:n.id,name:n.name,args:n.args});return t}function Ge(e){let t=[];for(let n of e)Ve(n)?t.push(He(n)):t.push(n);return t}function Ke(e){if(e.type===`url_citation`){let{url:t,title:n,start_index:r,end_index:i}=e;return{type:`citation`,url:t,title:n,startIndex:r,endIndex:i}}if(e.type===`file_citation`){let{file_id:t,filename:n,index:r}=e;return{type:`citation`,title:n,startIndex:r,endIndex:r,fileId:t}}return e}function qe(e){function*t(){w(e.additional_kwargs?.reasoning)&&ke(e.additional_kwargs.reasoning.summary)&&(yield{type:`reasoning`,reasoning:e.additional_kwargs.reasoning.summary.reduce((e,t)=>w(t)&&T(t.text)?`${e}${t.text}`:e,``)});let t=typeof e.content==`string`?[{type:`text`,text:e.content}]:e.content;for(let e of t)if(C(e,`text`)){let{text:t,annotations:n,phase:r,extras:i,...a}=e,o=w(i)?{...i}:{};T(r)&&(o.phase=r);let s=Object.keys(o).length>0?{extras:o}:{};Array.isArray(n)?yield{...a,...s,type:`text`,text:String(t),annotations:n.map(Ke)}:yield{...a,...s,type:`text`,text:String(t)}}for(let t of e.tool_calls??[])yield{type:`tool_call`,id:t.id,name:t.name,args:t.args};if(w(e.additional_kwargs)&&ke(e.additional_kwargs.tool_outputs))for(let t of e.additional_kwargs.tool_outputs){if(C(t,`web_search_call`)){let e={};if(w(t.action)&&T(t.action.query)&&(e.query=t.action.query),yield{id:t.id,type:`server_tool_call`,name:`web_search`,args:e},t.status===`completed`||t.status===`failed`){let e={};w(t.action)&&(e.action=t.action),yield{type:`server_tool_call_result`,toolCallId:T(t.id)?t.id:``,status:t.status===`completed`?`success`:`error`,output:e}}continue}else if(C(t,`file_search_call`)){yield{id:t.id,type:`server_tool_call`,name:`file_search`,args:{queries:ke(t.queries)?t.queries:[]}},(t.status===`completed`||t.status===`failed`)&&(yield{type:`server_tool_call_result`,toolCallId:T(t.id)?t.id:``,status:t.status===`completed`?`success`:`error`,output:ke(t.results)?{results:t.results}:{}});continue}else if(C(t,`computer_call`)){yield{type:`non_standard`,value:t};continue}else if(C(t,`code_interpreter_call`)){if(T(t.code)&&(yield{id:t.id,type:`server_tool_call`,name:`code_interpreter`,args:{code:t.code}}),ke(t.outputs)){let e=Me(()=>{if(t.status!==`in_progress`){if(t.status===`completed`)return 0;if(t.status===`incomplete`)return 127;if(t.status!==`interpreting`&&t.status===`failed`)return 1}});for(let n of t.outputs)if(C(n,`logs`)){yield{type:`server_tool_call_result`,toolCallId:t.id??``,status:`success`,output:{type:`code_interpreter_output`,returnCode:e??0,stderr:[0,void 0].includes(e)?void 0:String(n.logs),stdout:[0,void 0].includes(e)?String(n.logs):void 0}};continue}}continue}else if(C(t,`mcp_call`)){yield{id:t.id,type:`server_tool_call`,name:`mcp_call`,args:t.input};continue}else if(C(t,`mcp_list_tools`)){yield{id:t.id,type:`server_tool_call`,name:`mcp_list_tools`,args:t.input};continue}else if(C(t,`mcp_approval_request`)){yield{type:`non_standard`,value:t};continue}else if(C(t,`tool_search_call`)){let e={};w(t.arguments)&&Object.assign(e,t.arguments);let n={};T(t.execution)&&(n.execution=t.execution),T(t.status)&&(n.status=t.status),T(t.call_id)&&(n.call_id=t.call_id),yield{id:T(t.id)?t.id:``,type:`server_tool_call`,name:`tool_search`,args:e,...Object.keys(n).length>0?{extras:n}:{}};continue}else if(C(t,`tool_search_output`)){let e={name:`tool_search`};T(t.execution)&&(e.execution=t.execution),yield{type:`server_tool_call_result`,toolCallId:T(t.id)?t.id:``,status:t.status===`completed`?`success`:t.status===`failed`?`error`:`success`,output:{tools:ke(t.tools)?t.tools:[]},extras:e};continue}else if(C(t,`image_generation_call`)){T(t.result)&&(yield{type:`image`,mimeType:`image/png`,data:t.result,id:T(t.id)?t.id:void 0,metadata:{status:T(t.status)?t.status:void 0}}),yield{type:`non_standard`,value:t};continue}w(t)&&(yield{type:`non_standard`,value:t})}}return Array.from(t())}function Je(e){function*t(){yield*qe(e);for(let t of e.tool_call_chunks??[])yield{type:`tool_call_chunk`,id:t.id,name:t.name,args:t.args}}return Array.from(t())}var Ye={translateContent:e=>typeof e.content==`string`?Ue(e):qe(e),translateContentChunk:e=>typeof e.content==`string`?We(e):Je(e)};function Xe(e){return typeof e==`object`&&!!e&&`type`in e&&`content`in e&&(typeof e.content==`string`||Array.isArray(e.content))}function Ze(e,t=`pretty`){return t===`pretty`?Qe(e):JSON.stringify(e)}function Qe(e){let t=[],n=` ${e.type.charAt(0).toUpperCase()+e.type.slice(1)} Message `,r=Math.floor((80-n.length)/2),i=`=`.repeat(r),a=n.length%2==0?i:`${i}=`;if(t.push(`${i}${n}${a}`),e.type===`ai`){let n=e;if(n.tool_calls&&n.tool_calls.length>0){t.push(`Tool Calls:`);for(let e of n.tool_calls){t.push(` ${e.name} (${e.id})`),t.push(` Call ID: ${e.id}`),t.push(` Args:`);for(let[n,r]of Object.entries(e.args))t.push(` ${n}: ${typeof r==`object`?JSON.stringify(r):r}`)}}}if(e.type===`tool`){let n=e;n.name&&t.push(`Name: ${n.name}`)}return typeof e.content==`string`&&e.content.trim()&&(t.length>1&&t.push(``),t.push(e.content)),t.join(`