@link-assistant/agent 0.16.17 → 0.17.0
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.
- package/package.json +1 -1
- package/src/auth/claude-oauth.ts +5 -3
- package/src/auth/plugins.ts +56 -48
- package/src/cli/cmd/auth.ts +6 -3
- package/src/cli/continuous-mode.js +5 -1
- package/src/config/config.ts +5 -3
- package/src/file/ripgrep.ts +3 -1
- package/src/flag/flag.ts +13 -7
- package/src/index.js +19 -4
- package/src/provider/google-cloudcode.ts +4 -2
- package/src/provider/models.ts +3 -1
- package/src/provider/provider.ts +130 -51
- package/src/session/compaction.ts +88 -1
- package/src/session/message-v2.ts +24 -0
- package/src/session/processor.ts +18 -0
- package/src/session/summary.ts +121 -22
- package/src/tool/codesearch.ts +4 -1
- package/src/tool/webfetch.ts +4 -1
- package/src/tool/websearch.ts +4 -1
- package/src/util/verbose-fetch.ts +303 -0
package/package.json
CHANGED
package/src/auth/claude-oauth.ts
CHANGED
|
@@ -2,6 +2,7 @@ import crypto from 'crypto';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { Global } from '../global';
|
|
4
4
|
import { Log } from '../util/log';
|
|
5
|
+
import { createVerboseFetch } from '../util/verbose-fetch';
|
|
5
6
|
import z from 'zod';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -24,6 +25,7 @@ import z from 'zod';
|
|
|
24
25
|
*/
|
|
25
26
|
export namespace ClaudeOAuth {
|
|
26
27
|
const log = Log.create({ service: 'claude-oauth' });
|
|
28
|
+
const verboseFetch = createVerboseFetch(fetch, { caller: 'claude-oauth' });
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* OAuth Configuration
|
|
@@ -218,7 +220,7 @@ export namespace ClaudeOAuth {
|
|
|
218
220
|
message: 'exchanging authorization code for tokens',
|
|
219
221
|
}));
|
|
220
222
|
|
|
221
|
-
const response = await
|
|
223
|
+
const response = await verboseFetch(Config.tokenUrl, {
|
|
222
224
|
method: 'POST',
|
|
223
225
|
headers: {
|
|
224
226
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -402,7 +404,7 @@ export namespace ClaudeOAuth {
|
|
|
402
404
|
log.info(() => ({ message: 'refreshing access token' }));
|
|
403
405
|
|
|
404
406
|
try {
|
|
405
|
-
const response = await
|
|
407
|
+
const response = await verboseFetch(Config.tokenUrl, {
|
|
406
408
|
method: 'POST',
|
|
407
409
|
headers: {
|
|
408
410
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -446,7 +448,7 @@ export namespace ClaudeOAuth {
|
|
|
446
448
|
} else {
|
|
447
449
|
headers.set('anthropic-beta', Config.betaHeader);
|
|
448
450
|
}
|
|
449
|
-
return
|
|
451
|
+
return verboseFetch(url, { ...init, headers });
|
|
450
452
|
};
|
|
451
453
|
}
|
|
452
454
|
}
|
package/src/auth/plugins.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as http from 'node:http';
|
|
|
3
3
|
import * as net from 'node:net';
|
|
4
4
|
import { Auth } from './index';
|
|
5
5
|
import { Log } from '../util/log';
|
|
6
|
+
import { createVerboseFetch } from '../util/verbose-fetch';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Auth Plugins Module
|
|
@@ -12,6 +13,7 @@ import { Log } from '../util/log';
|
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
const log = Log.create({ service: 'auth-plugins' });
|
|
16
|
+
const verboseFetch = createVerboseFetch(fetch, { caller: 'auth-plugins' });
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* OAuth callback result types
|
|
@@ -142,7 +144,7 @@ const AnthropicPlugin: AuthPlugin = {
|
|
|
142
144
|
if (!code) return { type: 'failed' };
|
|
143
145
|
|
|
144
146
|
const splits = code.split('#');
|
|
145
|
-
const result = await
|
|
147
|
+
const result = await verboseFetch(
|
|
146
148
|
'https://console.anthropic.com/v1/oauth/token',
|
|
147
149
|
{
|
|
148
150
|
method: 'POST',
|
|
@@ -210,7 +212,7 @@ const AnthropicPlugin: AuthPlugin = {
|
|
|
210
212
|
if (!code) return { type: 'failed' };
|
|
211
213
|
|
|
212
214
|
const splits = code.split('#');
|
|
213
|
-
const tokenResult = await
|
|
215
|
+
const tokenResult = await verboseFetch(
|
|
214
216
|
'https://console.anthropic.com/v1/oauth/token',
|
|
215
217
|
{
|
|
216
218
|
method: 'POST',
|
|
@@ -240,7 +242,7 @@ const AnthropicPlugin: AuthPlugin = {
|
|
|
240
242
|
const credentials = await tokenResult.json();
|
|
241
243
|
|
|
242
244
|
// Create API key using the access token
|
|
243
|
-
const apiKeyResult = await
|
|
245
|
+
const apiKeyResult = await verboseFetch(
|
|
244
246
|
'https://api.anthropic.com/api/oauth/claude_cli/create_api_key',
|
|
245
247
|
{
|
|
246
248
|
method: 'POST',
|
|
@@ -291,7 +293,7 @@ const AnthropicPlugin: AuthPlugin = {
|
|
|
291
293
|
log.info(() => ({
|
|
292
294
|
message: 'refreshing anthropic oauth token',
|
|
293
295
|
}));
|
|
294
|
-
const response = await
|
|
296
|
+
const response = await verboseFetch(
|
|
295
297
|
'https://console.anthropic.com/v1/oauth/token',
|
|
296
298
|
{
|
|
297
299
|
method: 'POST',
|
|
@@ -446,7 +448,7 @@ const GitHubCopilotPlugin: AuthPlugin = {
|
|
|
446
448
|
|
|
447
449
|
const urls = getCopilotUrls(domain);
|
|
448
450
|
|
|
449
|
-
const deviceResponse = await
|
|
451
|
+
const deviceResponse = await verboseFetch(urls.DEVICE_CODE_URL, {
|
|
450
452
|
method: 'POST',
|
|
451
453
|
headers: {
|
|
452
454
|
Accept: 'application/json',
|
|
@@ -476,7 +478,7 @@ const GitHubCopilotPlugin: AuthPlugin = {
|
|
|
476
478
|
method: 'auto',
|
|
477
479
|
async callback(): Promise<AuthResult> {
|
|
478
480
|
while (true) {
|
|
479
|
-
const response = await
|
|
481
|
+
const response = await verboseFetch(urls.ACCESS_TOKEN_URL, {
|
|
480
482
|
method: 'POST',
|
|
481
483
|
headers: {
|
|
482
484
|
Accept: 'application/json',
|
|
@@ -571,7 +573,7 @@ const GitHubCopilotPlugin: AuthPlugin = {
|
|
|
571
573
|
const urls = getCopilotUrls(domain);
|
|
572
574
|
|
|
573
575
|
log.info(() => ({ message: 'refreshing github copilot token' }));
|
|
574
|
-
const response = await
|
|
576
|
+
const response = await verboseFetch(urls.COPILOT_API_KEY_URL, {
|
|
575
577
|
headers: {
|
|
576
578
|
Accept: 'application/json',
|
|
577
579
|
Authorization: `Bearer ${currentInfo.refresh}`,
|
|
@@ -731,7 +733,7 @@ const OpenAIPlugin: AuthPlugin = {
|
|
|
731
733
|
}
|
|
732
734
|
|
|
733
735
|
// Exchange authorization code for tokens
|
|
734
|
-
const tokenResult = await
|
|
736
|
+
const tokenResult = await verboseFetch(OPENAI_TOKEN_URL, {
|
|
735
737
|
method: 'POST',
|
|
736
738
|
headers: {
|
|
737
739
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -797,7 +799,7 @@ const OpenAIPlugin: AuthPlugin = {
|
|
|
797
799
|
// Refresh token if expired
|
|
798
800
|
if (!currentAuth.access || currentAuth.expires < Date.now()) {
|
|
799
801
|
log.info(() => ({ message: 'refreshing openai oauth token' }));
|
|
800
|
-
const response = await
|
|
802
|
+
const response = await verboseFetch(OPENAI_TOKEN_URL, {
|
|
801
803
|
method: 'POST',
|
|
802
804
|
headers: {
|
|
803
805
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -1091,7 +1093,7 @@ const GooglePlugin: AuthPlugin = {
|
|
|
1091
1093
|
const { code } = await authPromise;
|
|
1092
1094
|
|
|
1093
1095
|
// Exchange authorization code for tokens
|
|
1094
|
-
const tokenResult = await
|
|
1096
|
+
const tokenResult = await verboseFetch(GOOGLE_TOKEN_URL, {
|
|
1095
1097
|
method: 'POST',
|
|
1096
1098
|
headers: {
|
|
1097
1099
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -1187,7 +1189,7 @@ const GooglePlugin: AuthPlugin = {
|
|
|
1187
1189
|
|
|
1188
1190
|
try {
|
|
1189
1191
|
// Exchange authorization code for tokens
|
|
1190
|
-
const tokenResult = await
|
|
1192
|
+
const tokenResult = await verboseFetch(GOOGLE_TOKEN_URL, {
|
|
1191
1193
|
method: 'POST',
|
|
1192
1194
|
headers: {
|
|
1193
1195
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -1348,7 +1350,7 @@ const GooglePlugin: AuthPlugin = {
|
|
|
1348
1350
|
// Call loadCodeAssist to discover project and tier
|
|
1349
1351
|
try {
|
|
1350
1352
|
const loadUrl = `${CLOUD_CODE_ENDPOINT}/${CLOUD_CODE_API_VERSION}:loadCodeAssist`;
|
|
1351
|
-
const loadRes = await
|
|
1353
|
+
const loadRes = await verboseFetch(loadUrl, {
|
|
1352
1354
|
method: 'POST',
|
|
1353
1355
|
headers: {
|
|
1354
1356
|
'Content-Type': 'application/json',
|
|
@@ -1440,7 +1442,7 @@ const GooglePlugin: AuthPlugin = {
|
|
|
1440
1442
|
},
|
|
1441
1443
|
};
|
|
1442
1444
|
|
|
1443
|
-
let lroRes = await
|
|
1445
|
+
let lroRes = await verboseFetch(onboardUrl, {
|
|
1444
1446
|
method: 'POST',
|
|
1445
1447
|
headers: {
|
|
1446
1448
|
'Content-Type': 'application/json',
|
|
@@ -1456,11 +1458,11 @@ const GooglePlugin: AuthPlugin = {
|
|
|
1456
1458
|
if (lroRes.name) {
|
|
1457
1459
|
// Poll operation status
|
|
1458
1460
|
const opUrl = `${CLOUD_CODE_ENDPOINT}/${CLOUD_CODE_API_VERSION}/${lroRes.name}`;
|
|
1459
|
-
lroRes = await
|
|
1461
|
+
lroRes = await verboseFetch(opUrl, {
|
|
1460
1462
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
1461
1463
|
}).then((r) => r.json());
|
|
1462
1464
|
} else {
|
|
1463
|
-
lroRes = await
|
|
1465
|
+
lroRes = await verboseFetch(onboardUrl, {
|
|
1464
1466
|
method: 'POST',
|
|
1465
1467
|
headers: {
|
|
1466
1468
|
'Content-Type': 'application/json',
|
|
@@ -1924,7 +1926,7 @@ const GooglePlugin: AuthPlugin = {
|
|
|
1924
1926
|
// Invalidate project cache when token changes
|
|
1925
1927
|
cachedProjectContext = null;
|
|
1926
1928
|
|
|
1927
|
-
const response = await
|
|
1929
|
+
const response = await verboseFetch(GOOGLE_TOKEN_URL, {
|
|
1928
1930
|
method: 'POST',
|
|
1929
1931
|
headers: {
|
|
1930
1932
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -2043,7 +2045,7 @@ const GooglePlugin: AuthPlugin = {
|
|
|
2043
2045
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2044
2046
|
}
|
|
2045
2047
|
|
|
2046
|
-
const cloudCodeResponse = await
|
|
2048
|
+
const cloudCodeResponse = await verboseFetch(finalCloudCodeUrl, {
|
|
2047
2049
|
...init,
|
|
2048
2050
|
body,
|
|
2049
2051
|
headers,
|
|
@@ -2135,7 +2137,7 @@ const GooglePlugin: AuthPlugin = {
|
|
|
2135
2137
|
};
|
|
2136
2138
|
delete headers['x-goog-api-key'];
|
|
2137
2139
|
|
|
2138
|
-
const oauthResponse = await
|
|
2140
|
+
const oauthResponse = await verboseFetch(input, {
|
|
2139
2141
|
...init,
|
|
2140
2142
|
headers,
|
|
2141
2143
|
});
|
|
@@ -2248,19 +2250,22 @@ const QwenPlugin: AuthPlugin = {
|
|
|
2248
2250
|
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
2249
2251
|
|
|
2250
2252
|
// Request device code
|
|
2251
|
-
const deviceResponse = await
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2253
|
+
const deviceResponse = await verboseFetch(
|
|
2254
|
+
QWEN_OAUTH_DEVICE_CODE_ENDPOINT,
|
|
2255
|
+
{
|
|
2256
|
+
method: 'POST',
|
|
2257
|
+
headers: {
|
|
2258
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
2259
|
+
Accept: 'application/json',
|
|
2260
|
+
},
|
|
2261
|
+
body: new URLSearchParams({
|
|
2262
|
+
client_id: QWEN_OAUTH_CLIENT_ID,
|
|
2263
|
+
scope: QWEN_OAUTH_SCOPE,
|
|
2264
|
+
code_challenge: codeChallenge,
|
|
2265
|
+
code_challenge_method: 'S256',
|
|
2266
|
+
}).toString(),
|
|
2267
|
+
}
|
|
2268
|
+
);
|
|
2264
2269
|
|
|
2265
2270
|
if (!deviceResponse.ok) {
|
|
2266
2271
|
const errorText = await deviceResponse.text();
|
|
@@ -2308,19 +2313,22 @@ const QwenPlugin: AuthPlugin = {
|
|
|
2308
2313
|
async callback(): Promise<AuthResult> {
|
|
2309
2314
|
// Poll for authorization completion
|
|
2310
2315
|
for (let attempt = 0; attempt < maxPollAttempts; attempt++) {
|
|
2311
|
-
const tokenResponse = await
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2316
|
+
const tokenResponse = await verboseFetch(
|
|
2317
|
+
QWEN_OAUTH_TOKEN_ENDPOINT,
|
|
2318
|
+
{
|
|
2319
|
+
method: 'POST',
|
|
2320
|
+
headers: {
|
|
2321
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
2322
|
+
Accept: 'application/json',
|
|
2323
|
+
},
|
|
2324
|
+
body: new URLSearchParams({
|
|
2325
|
+
client_id: QWEN_OAUTH_CLIENT_ID,
|
|
2326
|
+
device_code: deviceData.device_code,
|
|
2327
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
2328
|
+
code_verifier: codeVerifier,
|
|
2329
|
+
}).toString(),
|
|
2330
|
+
}
|
|
2331
|
+
);
|
|
2324
2332
|
|
|
2325
2333
|
if (!tokenResponse.ok) {
|
|
2326
2334
|
const errorText = await tokenResponse.text();
|
|
@@ -2426,7 +2434,7 @@ const QwenPlugin: AuthPlugin = {
|
|
|
2426
2434
|
: 'token expiring soon',
|
|
2427
2435
|
}));
|
|
2428
2436
|
|
|
2429
|
-
const response = await
|
|
2437
|
+
const response = await verboseFetch(QWEN_OAUTH_TOKEN_ENDPOINT, {
|
|
2430
2438
|
method: 'POST',
|
|
2431
2439
|
headers: {
|
|
2432
2440
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -2575,7 +2583,7 @@ const AlibabaPlugin: AuthPlugin = {
|
|
|
2575
2583
|
message: 'refreshing qwen oauth token (alibaba provider)',
|
|
2576
2584
|
}));
|
|
2577
2585
|
|
|
2578
|
-
const response = await
|
|
2586
|
+
const response = await verboseFetch(QWEN_OAUTH_TOKEN_ENDPOINT, {
|
|
2579
2587
|
method: 'POST',
|
|
2580
2588
|
headers: {
|
|
2581
2589
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -2651,7 +2659,7 @@ const KiloPlugin: AuthPlugin = {
|
|
|
2651
2659
|
type: 'oauth',
|
|
2652
2660
|
async authorize() {
|
|
2653
2661
|
// Initiate device authorization
|
|
2654
|
-
const initResponse = await
|
|
2662
|
+
const initResponse = await verboseFetch(
|
|
2655
2663
|
`${KILO_API_BASE}/api/device-auth/codes`,
|
|
2656
2664
|
{
|
|
2657
2665
|
method: 'POST',
|
|
@@ -2704,7 +2712,7 @@ const KiloPlugin: AuthPlugin = {
|
|
|
2704
2712
|
setTimeout(resolve, KILO_POLL_INTERVAL_MS)
|
|
2705
2713
|
);
|
|
2706
2714
|
|
|
2707
|
-
const pollResponse = await
|
|
2715
|
+
const pollResponse = await verboseFetch(
|
|
2708
2716
|
`${KILO_API_BASE}/api/device-auth/codes/${authData.code}`
|
|
2709
2717
|
);
|
|
2710
2718
|
|
package/src/cli/cmd/auth.ts
CHANGED
|
@@ -9,6 +9,9 @@ import path from 'path';
|
|
|
9
9
|
import os from 'os';
|
|
10
10
|
import { Global } from '../../global';
|
|
11
11
|
import { map, pipe, sortBy, values } from 'remeda';
|
|
12
|
+
import { createVerboseFetch } from '../../util/verbose-fetch';
|
|
13
|
+
|
|
14
|
+
const verboseFetch = createVerboseFetch(fetch, { caller: 'auth-cmd' });
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* Auth Command
|
|
@@ -86,9 +89,9 @@ export const AuthLoginCommand = cmd({
|
|
|
86
89
|
// Handle wellknown URL login
|
|
87
90
|
if (args.url) {
|
|
88
91
|
try {
|
|
89
|
-
const wellknown = await
|
|
90
|
-
|
|
91
|
-
);
|
|
92
|
+
const wellknown = await verboseFetch(
|
|
93
|
+
`${args.url}/.well-known/opencode`
|
|
94
|
+
).then((x) => x.json() as any);
|
|
92
95
|
prompts.log.info(`Running \`${wellknown.auth.command.join(' ')}\``);
|
|
93
96
|
const proc = Bun.spawn({
|
|
94
97
|
cmd: wellknown.auth.command,
|
|
@@ -12,6 +12,7 @@ import { createEventHandler } from '../json-standard/index.ts';
|
|
|
12
12
|
import { createContinuousStdinReader } from './input-queue.js';
|
|
13
13
|
import { Log } from '../util/log.ts';
|
|
14
14
|
import { Flag } from '../flag/flag.ts';
|
|
15
|
+
import { createVerboseFetch } from '../util/verbose-fetch.ts';
|
|
15
16
|
import { outputStatus, outputError, outputInput } from './output.ts';
|
|
16
17
|
|
|
17
18
|
// Shared error tracking
|
|
@@ -215,7 +216,10 @@ export async function runContinuousServerMode(
|
|
|
215
216
|
sessionID = resumeInfo.sessionID;
|
|
216
217
|
} else {
|
|
217
218
|
// Create a new session
|
|
218
|
-
const
|
|
219
|
+
const localVerboseFetch = createVerboseFetch(fetch, {
|
|
220
|
+
caller: 'continuous-mode',
|
|
221
|
+
});
|
|
222
|
+
const createRes = await localVerboseFetch(
|
|
219
223
|
`http://${server.hostname}:${server.port}/session`,
|
|
220
224
|
{
|
|
221
225
|
method: 'POST',
|
package/src/config/config.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { lazy } from '../util/lazy';
|
|
|
11
11
|
import { NamedError } from '../util/error';
|
|
12
12
|
import { Flag } from '../flag/flag';
|
|
13
13
|
import { Auth } from '../auth';
|
|
14
|
+
import { createVerboseFetch } from '../util/verbose-fetch';
|
|
14
15
|
import {
|
|
15
16
|
type ParseError as JsoncParseError,
|
|
16
17
|
parse as parseJsonc,
|
|
@@ -21,6 +22,7 @@ import { ConfigMarkdown } from './markdown';
|
|
|
21
22
|
|
|
22
23
|
export namespace Config {
|
|
23
24
|
const log = Log.create({ service: 'config' });
|
|
25
|
+
const verboseFetch = createVerboseFetch(fetch, { caller: 'config' });
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* Automatically migrate .opencode directories to .link-assistant-agent
|
|
@@ -163,9 +165,9 @@ export namespace Config {
|
|
|
163
165
|
for (const [key, value] of Object.entries(auth)) {
|
|
164
166
|
if (value.type === 'wellknown') {
|
|
165
167
|
process.env[value.key] = value.token;
|
|
166
|
-
const wellknown = (await
|
|
167
|
-
|
|
168
|
-
)) as any;
|
|
168
|
+
const wellknown = (await verboseFetch(
|
|
169
|
+
`${key}/.well-known/opencode`
|
|
170
|
+
).then((x) => x.json())) as any;
|
|
169
171
|
result = mergeDeep(
|
|
170
172
|
result,
|
|
171
173
|
await load(JSON.stringify(wellknown.config ?? {}), process.cwd())
|
package/src/file/ripgrep.ts
CHANGED
|
@@ -9,9 +9,11 @@ import { $ } from 'bun';
|
|
|
9
9
|
|
|
10
10
|
import { ZipReader, BlobReader, BlobWriter } from '@zip.js/zip.js';
|
|
11
11
|
import { Log } from '../util/log';
|
|
12
|
+
import { createVerboseFetch } from '../util/verbose-fetch';
|
|
12
13
|
|
|
13
14
|
export namespace Ripgrep {
|
|
14
15
|
const log = Log.create({ service: 'ripgrep' });
|
|
16
|
+
const verboseFetch = createVerboseFetch(fetch, { caller: 'ripgrep' });
|
|
15
17
|
const Stats = z.object({
|
|
16
18
|
elapsed: z.object({
|
|
17
19
|
secs: z.number(),
|
|
@@ -142,7 +144,7 @@ export namespace Ripgrep {
|
|
|
142
144
|
const filename = `ripgrep-${version}-${config.platform}.${config.extension}`;
|
|
143
145
|
const url = `https://github.com/BurntSushi/ripgrep/releases/download/${version}/${filename}`;
|
|
144
146
|
|
|
145
|
-
const response = await
|
|
147
|
+
const response = await verboseFetch(url);
|
|
146
148
|
if (!response.ok)
|
|
147
149
|
throw new DownloadFailedError({ url, status: response.status });
|
|
148
150
|
|
package/src/flag/flag.ts
CHANGED
|
@@ -103,13 +103,19 @@ export namespace Flag {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// Session summarization configuration
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
// See: https://github.com/link-assistant/agent/issues/
|
|
109
|
-
export let SUMMARIZE_SESSION =
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
// Enabled by default - generates AI-powered session summaries using the same model
|
|
107
|
+
// Can be disabled with --no-summarize-session or AGENT_SUMMARIZE_SESSION=false
|
|
108
|
+
// See: https://github.com/link-assistant/agent/issues/217
|
|
109
|
+
export let SUMMARIZE_SESSION = (() => {
|
|
110
|
+
const value = (
|
|
111
|
+
getEnv(
|
|
112
|
+
'LINK_ASSISTANT_AGENT_SUMMARIZE_SESSION',
|
|
113
|
+
'AGENT_SUMMARIZE_SESSION'
|
|
114
|
+
) ?? ''
|
|
115
|
+
).toLowerCase();
|
|
116
|
+
if (value === 'false' || value === '0') return false;
|
|
117
|
+
return true; // Default to true
|
|
118
|
+
})();
|
|
113
119
|
|
|
114
120
|
// Allow setting summarize-session mode programmatically (e.g., from CLI --summarize-session flag)
|
|
115
121
|
export function setSummarizeSession(value: boolean) {
|
package/src/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import { McpCommand } from './cli/cmd/mcp.ts';
|
|
|
21
21
|
import { AuthCommand } from './cli/cmd/auth.ts';
|
|
22
22
|
import { FormatError } from './cli/error.ts';
|
|
23
23
|
import { UI } from './cli/ui.ts';
|
|
24
|
+
import { createVerboseFetch } from './util/verbose-fetch.ts';
|
|
24
25
|
import {
|
|
25
26
|
runContinuousServerMode,
|
|
26
27
|
runContinuousDirectMode,
|
|
@@ -427,7 +428,8 @@ async function runServerMode(
|
|
|
427
428
|
sessionID = resumeInfo.sessionID;
|
|
428
429
|
} else {
|
|
429
430
|
// Create a new session
|
|
430
|
-
const
|
|
431
|
+
const localVerboseFetch = createVerboseFetch(fetch, { caller: 'cli' });
|
|
432
|
+
const createRes = await localVerboseFetch(
|
|
431
433
|
`http://${server.hostname}:${server.port}/session`,
|
|
432
434
|
{
|
|
433
435
|
method: 'POST',
|
|
@@ -731,8 +733,9 @@ async function main() {
|
|
|
731
733
|
})
|
|
732
734
|
.option('summarize-session', {
|
|
733
735
|
type: 'boolean',
|
|
734
|
-
description:
|
|
735
|
-
|
|
736
|
+
description:
|
|
737
|
+
'Generate AI session summaries (default: true). Use --no-summarize-session to disable.',
|
|
738
|
+
default: true,
|
|
736
739
|
}),
|
|
737
740
|
handler: async (argv) => {
|
|
738
741
|
// Check both CLI flag and environment variable for compact JSON mode
|
|
@@ -915,7 +918,10 @@ async function main() {
|
|
|
915
918
|
if (argv['output-response-model'] === false) {
|
|
916
919
|
Flag.setOutputResponseModel(false);
|
|
917
920
|
}
|
|
918
|
-
|
|
921
|
+
// summarize-session is enabled by default, only set if explicitly disabled
|
|
922
|
+
if (argv['summarize-session'] === false) {
|
|
923
|
+
Flag.setSummarizeSession(false);
|
|
924
|
+
} else {
|
|
919
925
|
Flag.setSummarizeSession(true);
|
|
920
926
|
}
|
|
921
927
|
// retry-on-rate-limits is enabled by default, only set if explicitly disabled
|
|
@@ -927,6 +933,15 @@ async function main() {
|
|
|
927
933
|
level: Flag.OPENCODE_VERBOSE ? 'DEBUG' : 'INFO',
|
|
928
934
|
compactJson: isCompact,
|
|
929
935
|
});
|
|
936
|
+
|
|
937
|
+
// Monkey-patch globalThis.fetch for raw HTTP logging in --verbose mode.
|
|
938
|
+
// Catches ALL HTTP calls regardless of AI SDK fetch passthrough. (#217)
|
|
939
|
+
if (!globalThis.__agentVerboseFetchInstalled) {
|
|
940
|
+
globalThis.fetch = createVerboseFetch(globalThis.fetch, {
|
|
941
|
+
caller: 'global',
|
|
942
|
+
});
|
|
943
|
+
globalThis.__agentVerboseFetchInstalled = true;
|
|
944
|
+
}
|
|
930
945
|
})
|
|
931
946
|
.fail((msg, err, yargs) => {
|
|
932
947
|
// Handle errors from command handlers
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
import { Log } from '../util/log';
|
|
17
17
|
import { Auth } from '../auth';
|
|
18
|
+
import { createVerboseFetch } from '../util/verbose-fetch';
|
|
18
19
|
|
|
19
20
|
const log = Log.create({ service: 'google-cloudcode' });
|
|
21
|
+
const verboseFetch = createVerboseFetch(fetch, { caller: 'google-cloudcode' });
|
|
20
22
|
|
|
21
23
|
// Cloud Code API endpoints (from gemini-cli)
|
|
22
24
|
// Configurable via environment variables for testing or alternative endpoints
|
|
@@ -179,7 +181,7 @@ export class CloudCodeClient {
|
|
|
179
181
|
message: 'refreshing google oauth token for cloud code',
|
|
180
182
|
}));
|
|
181
183
|
|
|
182
|
-
const response = await
|
|
184
|
+
const response = await verboseFetch(GOOGLE_TOKEN_URL, {
|
|
183
185
|
method: 'POST',
|
|
184
186
|
headers: {
|
|
185
187
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -223,7 +225,7 @@ export class CloudCodeClient {
|
|
|
223
225
|
const baseUrl = `${CODE_ASSIST_ENDPOINT}/${CODE_ASSIST_API_VERSION}:${method}`;
|
|
224
226
|
const url = options.stream ? `${baseUrl}?alt=sse` : baseUrl;
|
|
225
227
|
|
|
226
|
-
const response = await
|
|
228
|
+
const response = await verboseFetch(url, {
|
|
227
229
|
method: 'POST',
|
|
228
230
|
headers: {
|
|
229
231
|
'Content-Type': 'application/json',
|
package/src/provider/models.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Global } from '../global';
|
|
2
2
|
import { Log } from '../util/log';
|
|
3
|
+
import { createVerboseFetch } from '../util/verbose-fetch';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import z from 'zod';
|
|
5
6
|
import { data } from './models-macro';
|
|
6
7
|
|
|
7
8
|
export namespace ModelsDev {
|
|
8
9
|
const log = Log.create({ service: 'models.dev' });
|
|
10
|
+
const verboseFetch = createVerboseFetch(fetch, { caller: 'models.dev' });
|
|
9
11
|
const filepath = path.join(Global.Path.cache, 'models.json');
|
|
10
12
|
|
|
11
13
|
export const Model = z
|
|
@@ -145,7 +147,7 @@ export namespace ModelsDev {
|
|
|
145
147
|
export async function refresh() {
|
|
146
148
|
const file = Bun.file(filepath);
|
|
147
149
|
log.info(() => ({ message: 'refreshing', file }));
|
|
148
|
-
const result = await
|
|
150
|
+
const result = await verboseFetch('https://models.dev/api.json', {
|
|
149
151
|
headers: {
|
|
150
152
|
'User-Agent': 'agent-cli/1.0.0',
|
|
151
153
|
},
|