@quireco/cli 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,31 +1,95 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-Vs_PY4HZ.mjs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import { defineCommand, parseArgs, renderUsage, runCommand } from "citty";
|
|
3
|
-
import {
|
|
4
|
+
import { createInterface } from "node:readline/promises";
|
|
5
|
+
import { loginOpenAICodex } from "@earendil-works/pi-ai/oauth";
|
|
6
|
+
import { AuthStorage, DefaultResourceLoader, ModelRegistry, SessionManager, SettingsManager, createAgentSession, defineTool, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { exec, execFile, execFileSync, spawn } from "node:child_process";
|
|
8
|
+
import os, { homedir, networkInterfaces, tmpdir } from "node:os";
|
|
4
9
|
import { basename, delimiter, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
10
|
+
import { calculateCost, createAssistantMessageEventStream } from "@earendil-works/pi-ai";
|
|
11
|
+
import { convertMessages } from "@earendil-works/pi-ai/openai-completions";
|
|
12
|
+
import { access, constants, mkdir, mkdtemp, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
13
|
+
import { closeSync, constants as constants$1, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, watch, writeFileSync } from "node:fs";
|
|
5
14
|
import { Type } from "@sinclair/typebox";
|
|
6
15
|
import { Value } from "@sinclair/typebox/value";
|
|
7
|
-
import { exec, execFile, execFileSync, spawn } from "node:child_process";
|
|
8
|
-
import { access, constants as constants$1, mkdir, mkdtemp, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
9
16
|
import { promisify } from "node:util";
|
|
10
|
-
import { homedir, networkInterfaces, tmpdir } from "node:os";
|
|
11
17
|
import { createHash, randomBytes } from "node:crypto";
|
|
12
18
|
import * as net from "net";
|
|
13
19
|
import { promisify as promisify$1 } from "util";
|
|
14
|
-
import
|
|
20
|
+
import process$1 from "node:process";
|
|
21
|
+
import tty from "node:tty";
|
|
15
22
|
import { createServer } from "node:http";
|
|
16
23
|
import { pathToFileURL } from "node:url";
|
|
17
24
|
import path, { basename as basename$1 } from "path";
|
|
18
25
|
import * as crypto$1 from "crypto";
|
|
19
26
|
import crypto, { createHash as createHash$1 } from "crypto";
|
|
20
27
|
import fs, { promises } from "fs";
|
|
28
|
+
import os$1 from "os";
|
|
21
29
|
import { Readable } from "stream";
|
|
22
30
|
import * as zlib$1 from "zlib";
|
|
23
31
|
import { execFile as execFile$1 } from "child_process";
|
|
24
32
|
import { EventEmitter } from "events";
|
|
25
33
|
import { pipeline } from "stream/promises";
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
//#region src/auth/open-browser.ts
|
|
35
|
+
async function openBrowser(url) {
|
|
36
|
+
const command = browserCommand(url);
|
|
37
|
+
if (command === null) return false;
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const child = spawn(command.command, command.args, {
|
|
40
|
+
detached: true,
|
|
41
|
+
stdio: "ignore",
|
|
42
|
+
shell: false
|
|
43
|
+
});
|
|
44
|
+
child.once("error", () => resolve(false));
|
|
45
|
+
child.once("spawn", () => {
|
|
46
|
+
child.unref();
|
|
47
|
+
resolve(true);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function browserCommand(url) {
|
|
52
|
+
if (process.platform === "darwin") return {
|
|
53
|
+
command: "open",
|
|
54
|
+
args: [url]
|
|
55
|
+
};
|
|
56
|
+
if (process.platform === "win32") return {
|
|
57
|
+
command: "cmd",
|
|
58
|
+
args: [
|
|
59
|
+
"/c",
|
|
60
|
+
"start",
|
|
61
|
+
"",
|
|
62
|
+
url
|
|
63
|
+
]
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
command: "xdg-open",
|
|
67
|
+
args: [url]
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/exit-codes.ts
|
|
72
|
+
const ExitCode = {
|
|
73
|
+
Success: 0,
|
|
74
|
+
InternalError: 1,
|
|
75
|
+
InvalidInput: 2,
|
|
76
|
+
AuthFailure: 10,
|
|
77
|
+
NetworkFailure: 11
|
|
78
|
+
};
|
|
79
|
+
var CliError$1 = class extends Error {
|
|
80
|
+
constructor(message, exitCode = ExitCode.InternalError) {
|
|
81
|
+
super(message);
|
|
82
|
+
this.exitCode = exitCode;
|
|
83
|
+
this.name = "CliError";
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
function readExitCode(error) {
|
|
87
|
+
return error instanceof CliError$1 ? error.exitCode : ExitCode.InternalError;
|
|
88
|
+
}
|
|
89
|
+
function toOneLineError(error) {
|
|
90
|
+
return (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim() || "unknown error";
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
29
93
|
//#region src/output.ts
|
|
30
94
|
function writeLine(output, message = "") {
|
|
31
95
|
output?.write(`${message}\n`);
|
|
@@ -34,6 +98,885 @@ function writeJson(output, value) {
|
|
|
34
98
|
writeLine(output, JSON.stringify(value));
|
|
35
99
|
}
|
|
36
100
|
//#endregion
|
|
101
|
+
//#region src/auth/constants.ts
|
|
102
|
+
const QUIRE_API_TOKEN_ENV = "QUIRE_API_TOKEN";
|
|
103
|
+
const QUIRE_API_TOKEN_TYPE = "QuireApiKey";
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/auth/api.ts
|
|
106
|
+
const CLIENT_ID = "quire-cli";
|
|
107
|
+
const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
108
|
+
var HttpError = class extends CliError$1 {
|
|
109
|
+
constructor(message, status, body, code) {
|
|
110
|
+
super(message, status === 401 || status === 403 ? ExitCode.AuthFailure : ExitCode.NetworkFailure);
|
|
111
|
+
this.status = status;
|
|
112
|
+
this.body = body;
|
|
113
|
+
this.code = code;
|
|
114
|
+
this.name = "HttpError";
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
function readApiBaseUrl(value = process.env.QUIRE_API_URL ?? "https://quire.sh") {
|
|
118
|
+
return normalizeApiBaseUrl(value);
|
|
119
|
+
}
|
|
120
|
+
function normalizeApiBaseUrl(value) {
|
|
121
|
+
try {
|
|
122
|
+
const url = new URL(value);
|
|
123
|
+
url.pathname = url.pathname.replace(/\/+$/, "");
|
|
124
|
+
url.search = "";
|
|
125
|
+
url.hash = "";
|
|
126
|
+
return url.toString().replace(/\/$/, "");
|
|
127
|
+
} catch {
|
|
128
|
+
throw new CliError$1(`Invalid Quire API URL: ${value}`, ExitCode.InvalidInput);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function requestDeviceCode(options) {
|
|
132
|
+
return parseDeviceCodeResponse((await requestJson$1({
|
|
133
|
+
url: authUrl(options.apiBaseUrl, "/device/code"),
|
|
134
|
+
fetchFn: options.fetchFn,
|
|
135
|
+
init: {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: jsonHeaders(),
|
|
138
|
+
body: JSON.stringify({
|
|
139
|
+
client_id: CLIENT_ID,
|
|
140
|
+
...options.scope === void 0 ? {} : { scope: options.scope }
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
})).body);
|
|
144
|
+
}
|
|
145
|
+
async function requestDeviceToken(options) {
|
|
146
|
+
return parseDeviceTokenResponse((await requestJson$1({
|
|
147
|
+
url: authUrl(options.apiBaseUrl, "/device/token"),
|
|
148
|
+
fetchFn: options.fetchFn,
|
|
149
|
+
init: {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: jsonHeaders(),
|
|
152
|
+
body: JSON.stringify({
|
|
153
|
+
grant_type: DEVICE_GRANT_TYPE,
|
|
154
|
+
device_code: options.deviceCode,
|
|
155
|
+
client_id: CLIENT_ID
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
})).body);
|
|
159
|
+
}
|
|
160
|
+
async function fetchCurrentSession(options) {
|
|
161
|
+
const response = await requestJson$1({
|
|
162
|
+
url: authUrl(options.apiBaseUrl, "/get-session"),
|
|
163
|
+
fetchFn: options.fetchFn,
|
|
164
|
+
init: {
|
|
165
|
+
method: "GET",
|
|
166
|
+
headers: {
|
|
167
|
+
Accept: "application/json",
|
|
168
|
+
...authHeaders(options)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const refreshedAccessToken = response.response.headers.get("set-auth-token") ?? void 0;
|
|
173
|
+
return {
|
|
174
|
+
data: parseCurrentSession(response.body),
|
|
175
|
+
...refreshedAccessToken === void 0 ? {} : { refreshedAccessToken }
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
async function fetchModelSourceBrokerStatus(options) {
|
|
179
|
+
return parseModelSourceBrokerStatus((await requestJson$1({
|
|
180
|
+
url: apiUrl(options.apiBaseUrl, "/api/model-sources"),
|
|
181
|
+
fetchFn: options.fetchFn,
|
|
182
|
+
init: {
|
|
183
|
+
method: "GET",
|
|
184
|
+
headers: {
|
|
185
|
+
Accept: "application/json",
|
|
186
|
+
...authHeaders(options),
|
|
187
|
+
"User-Agent": "quire-cli"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
})).body);
|
|
191
|
+
}
|
|
192
|
+
function authUrl(apiBaseUrl, path) {
|
|
193
|
+
return apiUrl(apiBaseUrl, `/api/auth${path}`);
|
|
194
|
+
}
|
|
195
|
+
function apiUrl(apiBaseUrl, path) {
|
|
196
|
+
return new URL(path, apiBaseUrl).toString();
|
|
197
|
+
}
|
|
198
|
+
function jsonHeaders() {
|
|
199
|
+
return {
|
|
200
|
+
Accept: "application/json",
|
|
201
|
+
"Content-Type": "application/json",
|
|
202
|
+
"User-Agent": "quire-cli"
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function authHeaders(credentials) {
|
|
206
|
+
if (credentials.tokenType === "QuireApiKey") return { "X-Quire-API-Key": credentials.accessToken };
|
|
207
|
+
return { Authorization: `Bearer ${credentials.accessToken}` };
|
|
208
|
+
}
|
|
209
|
+
async function requestJson$1(options) {
|
|
210
|
+
let response;
|
|
211
|
+
try {
|
|
212
|
+
response = await (options.fetchFn ?? fetch)(options.url, options.init);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
throw new CliError$1(`Could not reach Quire API: ${error instanceof Error ? error.message : String(error)}`, ExitCode.NetworkFailure);
|
|
215
|
+
}
|
|
216
|
+
const body = await readResponseBody(response);
|
|
217
|
+
if (!response.ok) {
|
|
218
|
+
const { code, description } = readErrorBody(body);
|
|
219
|
+
throw new HttpError(description ?? `Quire API request failed with HTTP ${response.status}`, response.status, body, code);
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
body,
|
|
223
|
+
response
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
async function readResponseBody(response) {
|
|
227
|
+
const text = await response.text();
|
|
228
|
+
if (!text) return null;
|
|
229
|
+
try {
|
|
230
|
+
return JSON.parse(text);
|
|
231
|
+
} catch {
|
|
232
|
+
return text;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function readErrorBody(body) {
|
|
236
|
+
if (!isRecord$21(body)) return {};
|
|
237
|
+
return {
|
|
238
|
+
code: typeof body.error === "string" ? body.error : void 0,
|
|
239
|
+
description: typeof body.error_description === "string" ? body.error_description : typeof body.message === "string" ? body.message : void 0
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function parseDeviceCodeResponse(value) {
|
|
243
|
+
if (!isRecord$21(value)) throw new CliError$1("Quire API returned an invalid device code response", ExitCode.NetworkFailure);
|
|
244
|
+
const response = {
|
|
245
|
+
device_code: value.device_code,
|
|
246
|
+
user_code: value.user_code,
|
|
247
|
+
verification_uri: value.verification_uri,
|
|
248
|
+
verification_uri_complete: value.verification_uri_complete,
|
|
249
|
+
expires_in: value.expires_in,
|
|
250
|
+
interval: value.interval
|
|
251
|
+
};
|
|
252
|
+
if (typeof response.device_code !== "string" || typeof response.user_code !== "string" || typeof response.verification_uri !== "string" || typeof response.verification_uri_complete !== "string" || typeof response.expires_in !== "number" || typeof response.interval !== "number") throw new CliError$1("Quire API returned an invalid device code response", ExitCode.NetworkFailure);
|
|
253
|
+
return response;
|
|
254
|
+
}
|
|
255
|
+
function parseDeviceTokenResponse(value) {
|
|
256
|
+
if (!isRecord$21(value) || typeof value.access_token !== "string") throw new CliError$1("Quire API returned an invalid device token response", ExitCode.NetworkFailure);
|
|
257
|
+
if (value.expires_in !== void 0 && typeof value.expires_in !== "number") throw new CliError$1("Quire API returned an invalid device token response", ExitCode.NetworkFailure);
|
|
258
|
+
if (value.scope !== void 0 && typeof value.scope !== "string") throw new CliError$1("Quire API returned an invalid device token response", ExitCode.NetworkFailure);
|
|
259
|
+
return {
|
|
260
|
+
access_token: value.access_token,
|
|
261
|
+
token_type: typeof value.token_type === "string" ? value.token_type : "Bearer",
|
|
262
|
+
...value.expires_in === void 0 ? {} : { expires_in: value.expires_in },
|
|
263
|
+
...value.scope === void 0 ? {} : { scope: value.scope }
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function parseCurrentSession(value) {
|
|
267
|
+
if (value === null) return null;
|
|
268
|
+
if (!isRecord$21(value) || !isRecord$21(value.session) || !isRecord$21(value.user)) throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
269
|
+
if (typeof value.session.id !== "string" || typeof value.user.id !== "string") throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
270
|
+
if (value.user.email !== void 0 && value.user.email !== null && typeof value.user.email !== "string") throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
271
|
+
if (value.user.name !== void 0 && value.user.name !== null && typeof value.user.name !== "string") throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
272
|
+
return {
|
|
273
|
+
session: {
|
|
274
|
+
id: value.session.id,
|
|
275
|
+
...typeof value.session.expiresAt === "string" ? { expiresAt: value.session.expiresAt } : {}
|
|
276
|
+
},
|
|
277
|
+
user: {
|
|
278
|
+
id: value.user.id,
|
|
279
|
+
...value.user.email === void 0 ? {} : { email: value.user.email },
|
|
280
|
+
...value.user.name === void 0 ? {} : { name: value.user.name }
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function parseModelSourceBrokerStatus(value) {
|
|
285
|
+
if (!isRecord$21(value) || !Array.isArray(value.selectedOrder)) throw new CliError$1("Quire API returned an invalid model-source status response", ExitCode.NetworkFailure);
|
|
286
|
+
const resolvedAvailability = value.resolvedAvailability;
|
|
287
|
+
if (!isRecord$21(resolvedAvailability)) throw new CliError$1("Quire API returned an invalid model-source status response", ExitCode.NetworkFailure);
|
|
288
|
+
const status = resolvedAvailability.status;
|
|
289
|
+
const reason = resolvedAvailability.reason;
|
|
290
|
+
const selectedProviderMode = resolvedAvailability.mode;
|
|
291
|
+
const requiredNextAction = resolvedAvailability.nextAction;
|
|
292
|
+
if (status !== "available" && status !== "unavailable" || typeof reason !== "string" || selectedProviderMode !== null && typeof selectedProviderMode !== "string" || requiredNextAction !== null && typeof requiredNextAction !== "string" || !value.selectedOrder.every((mode) => typeof mode === "string")) throw new CliError$1("Quire API returned an invalid model-source status response", ExitCode.NetworkFailure);
|
|
293
|
+
const actor = readActor(value);
|
|
294
|
+
return {
|
|
295
|
+
...actor === void 0 ? {} : { actor },
|
|
296
|
+
available: status === "available",
|
|
297
|
+
status,
|
|
298
|
+
selectedProviderMode,
|
|
299
|
+
selectedOrder: value.selectedOrder,
|
|
300
|
+
reason,
|
|
301
|
+
requiredNextAction,
|
|
302
|
+
requiredBalance: readWalletRequiredBalance(value),
|
|
303
|
+
remainingBalance: readWalletRemainingBalance(value),
|
|
304
|
+
recentUsage: readRecentUsage(value)
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function readActor(value) {
|
|
308
|
+
const actor = value.actor;
|
|
309
|
+
if (!isRecord$21(actor)) return;
|
|
310
|
+
const actorType = actor.actorType;
|
|
311
|
+
if (actorType !== "user_session" && actorType !== "api_key") return;
|
|
312
|
+
return {
|
|
313
|
+
actorType,
|
|
314
|
+
actorId: typeof actor.actorId === "string" ? actor.actorId : null,
|
|
315
|
+
environmentId: typeof actor.environmentId === "string" ? actor.environmentId : null,
|
|
316
|
+
environmentName: typeof actor.environmentName === "string" ? actor.environmentName : null,
|
|
317
|
+
triggerSource: typeof actor.triggerSource === "string" ? actor.triggerSource : null
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function isRecord$21(value) {
|
|
321
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
322
|
+
}
|
|
323
|
+
function readWalletRequiredBalance(value) {
|
|
324
|
+
const source = readFirstSource(value);
|
|
325
|
+
const requiredBalance = (isRecord$21(source?.wallet) ? source.wallet : null)?.requiredBalance;
|
|
326
|
+
return typeof requiredBalance === "number" && Number.isFinite(requiredBalance) ? requiredBalance : null;
|
|
327
|
+
}
|
|
328
|
+
function readWalletRemainingBalance(value) {
|
|
329
|
+
const source = readFirstSource(value);
|
|
330
|
+
const wallet = isRecord$21(source?.wallet) ? source.wallet : null;
|
|
331
|
+
const remaining = (isRecord$21(wallet?.balance) ? wallet.balance : null)?.remaining;
|
|
332
|
+
return typeof remaining === "number" && Number.isFinite(remaining) ? remaining : null;
|
|
333
|
+
}
|
|
334
|
+
function readFirstSource(value) {
|
|
335
|
+
if (!Array.isArray(value.sources)) return null;
|
|
336
|
+
const [source] = value.sources;
|
|
337
|
+
return isRecord$21(source) ? source : null;
|
|
338
|
+
}
|
|
339
|
+
function readRecentUsage(value) {
|
|
340
|
+
if (!Array.isArray(value.recentUsage)) return [];
|
|
341
|
+
return value.recentUsage.flatMap((event) => {
|
|
342
|
+
if (!isRecord$21(event)) return [];
|
|
343
|
+
if (typeof event.modelId !== "string" || typeof event.status !== "string" || typeof event.totalTokens !== "number" || typeof event.createdAt !== "string") return [];
|
|
344
|
+
return [{
|
|
345
|
+
modelId: event.modelId,
|
|
346
|
+
status: event.status,
|
|
347
|
+
totalTokens: event.totalTokens,
|
|
348
|
+
runId: typeof event.runId === "string" ? event.runId : null,
|
|
349
|
+
createdAt: event.createdAt
|
|
350
|
+
}];
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
//#endregion
|
|
354
|
+
//#region src/auth/store.ts
|
|
355
|
+
function defaultAuthPath(env = process.env) {
|
|
356
|
+
if (env.QUIRE_AUTH_FILE) return resolve(env.QUIRE_AUTH_FILE);
|
|
357
|
+
return join(resolve(env.QUIRE_HOME ?? join(homedir(), ".quire")), "auth.json");
|
|
358
|
+
}
|
|
359
|
+
function createAuthStore(path = defaultAuthPath()) {
|
|
360
|
+
async function get() {
|
|
361
|
+
try {
|
|
362
|
+
const contents = await readFile(path, "utf8");
|
|
363
|
+
return parseStoredCredentials(JSON.parse(contents));
|
|
364
|
+
} catch {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async function set(credentials) {
|
|
369
|
+
await mkdir(dirname(path), {
|
|
370
|
+
recursive: true,
|
|
371
|
+
mode: 448
|
|
372
|
+
});
|
|
373
|
+
await writeFile(path, `${JSON.stringify(credentials, null, 2)}\n`, { mode: 384 });
|
|
374
|
+
}
|
|
375
|
+
async function clear() {
|
|
376
|
+
try {
|
|
377
|
+
await unlink(path);
|
|
378
|
+
} catch {}
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
path,
|
|
382
|
+
get,
|
|
383
|
+
set,
|
|
384
|
+
clear
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
const authStore = createAuthStore();
|
|
388
|
+
async function resolveAuthCredentials(options = {}) {
|
|
389
|
+
const env = options.env ?? process.env;
|
|
390
|
+
const apiToken = env[QUIRE_API_TOKEN_ENV]?.trim();
|
|
391
|
+
if (apiToken) return createStoredCredentials({
|
|
392
|
+
apiBaseUrl: readApiBaseUrl(env.QUIRE_API_URL),
|
|
393
|
+
accessToken: apiToken,
|
|
394
|
+
tokenType: QUIRE_API_TOKEN_TYPE,
|
|
395
|
+
user: {
|
|
396
|
+
id: "api-token",
|
|
397
|
+
name: "API token"
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
return (options.store ?? authStore).get();
|
|
401
|
+
}
|
|
402
|
+
function createStoredCredentials(input) {
|
|
403
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
404
|
+
const timestamp = now.toISOString();
|
|
405
|
+
const expiresAt = input.expiresAt ?? expiresAtFromSeconds(input.expiresIn, now);
|
|
406
|
+
return {
|
|
407
|
+
version: 1,
|
|
408
|
+
apiBaseUrl: input.apiBaseUrl,
|
|
409
|
+
accessToken: input.accessToken,
|
|
410
|
+
tokenType: input.tokenType ?? "Bearer",
|
|
411
|
+
...expiresAt === void 0 ? {} : { expiresAt },
|
|
412
|
+
...input.user === void 0 ? {} : { user: input.user },
|
|
413
|
+
createdAt: timestamp,
|
|
414
|
+
updatedAt: timestamp
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
function updateStoredCredentials(credentials, input) {
|
|
418
|
+
return {
|
|
419
|
+
...credentials,
|
|
420
|
+
accessToken: input.accessToken ?? credentials.accessToken,
|
|
421
|
+
tokenType: input.tokenType ?? credentials.tokenType,
|
|
422
|
+
...input.expiresAt === void 0 ? {} : { expiresAt: input.expiresAt },
|
|
423
|
+
...input.user === void 0 ? {} : { user: input.user },
|
|
424
|
+
updatedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString()
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function expiresAtFromSeconds(expiresIn, now) {
|
|
428
|
+
return typeof expiresIn === "number" ? new Date(now.getTime() + expiresIn * 1e3).toISOString() : void 0;
|
|
429
|
+
}
|
|
430
|
+
function parseStoredCredentials(value) {
|
|
431
|
+
if (!isRecord$20(value)) return null;
|
|
432
|
+
if (value.version !== 1 || typeof value.apiBaseUrl !== "string" || typeof value.accessToken !== "string" || typeof value.tokenType !== "string" || typeof value.createdAt !== "string" || typeof value.updatedAt !== "string") return null;
|
|
433
|
+
if (value.expiresAt !== void 0 && typeof value.expiresAt !== "string") return null;
|
|
434
|
+
const user = parseStoredUser(value.user);
|
|
435
|
+
if (value.user !== void 0 && user === null) return null;
|
|
436
|
+
return {
|
|
437
|
+
version: 1,
|
|
438
|
+
apiBaseUrl: value.apiBaseUrl,
|
|
439
|
+
accessToken: value.accessToken,
|
|
440
|
+
tokenType: value.tokenType,
|
|
441
|
+
...value.expiresAt === void 0 ? {} : { expiresAt: value.expiresAt },
|
|
442
|
+
...user === void 0 || user === null ? {} : { user },
|
|
443
|
+
createdAt: value.createdAt,
|
|
444
|
+
updatedAt: value.updatedAt
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function parseStoredUser(value) {
|
|
448
|
+
if (value === void 0) return;
|
|
449
|
+
if (!isRecord$20(value) || typeof value.id !== "string") return null;
|
|
450
|
+
if (value.email !== void 0 && value.email !== null && typeof value.email !== "string") return null;
|
|
451
|
+
if (value.name !== void 0 && value.name !== null && typeof value.name !== "string") return null;
|
|
452
|
+
return {
|
|
453
|
+
id: value.id,
|
|
454
|
+
...value.email === void 0 ? {} : { email: value.email },
|
|
455
|
+
...value.name === void 0 ? {} : { name: value.name }
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function isRecord$20(value) {
|
|
459
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
460
|
+
}
|
|
461
|
+
//#endregion
|
|
462
|
+
//#region src/pipeline/quire-model-provider.ts
|
|
463
|
+
const QUIRE_MODEL_PROVIDER = "quire";
|
|
464
|
+
const QUIRE_MODEL_ID = "gpt-5.1";
|
|
465
|
+
const PI_CODEX_MODEL_PROVIDER = "openai-codex";
|
|
466
|
+
const PI_CODEX_MODEL_ID = "gpt-5.5";
|
|
467
|
+
const QUIRE_MODEL_API = "quire-chat-completions";
|
|
468
|
+
const QUIRE_RUNTIME_AUTH_ENV = "QUIRE_RUNTIME_AUTH_TOKEN";
|
|
469
|
+
const QUIRE_MODEL_AUTH_PATH_ENV = "QUIRE_MODEL_AUTH_PATH";
|
|
470
|
+
const openAiCompletionCompat = {
|
|
471
|
+
supportsStore: false,
|
|
472
|
+
supportsDeveloperRole: false,
|
|
473
|
+
supportsReasoningEffort: true,
|
|
474
|
+
supportsUsageInStreaming: false,
|
|
475
|
+
maxTokensField: "max_completion_tokens",
|
|
476
|
+
requiresToolResultName: false,
|
|
477
|
+
requiresAssistantAfterToolResult: false,
|
|
478
|
+
requiresThinkingAsText: false,
|
|
479
|
+
requiresReasoningContentOnAssistantMessages: false,
|
|
480
|
+
thinkingFormat: "openai",
|
|
481
|
+
zaiToolStream: false,
|
|
482
|
+
supportsStrictMode: true,
|
|
483
|
+
sendSessionAffinityHeaders: false,
|
|
484
|
+
supportsLongCacheRetention: true
|
|
485
|
+
};
|
|
486
|
+
async function createQuireModelSessionDependencies({ runId, store = authStore, fetchFn }) {
|
|
487
|
+
const credentials = await readValidatedQuireCredentials({
|
|
488
|
+
store,
|
|
489
|
+
fetchFn
|
|
490
|
+
});
|
|
491
|
+
const authStorage = AuthStorage.inMemory();
|
|
492
|
+
authStorage.setRuntimeApiKey(QUIRE_MODEL_PROVIDER, credentials.accessToken);
|
|
493
|
+
const modelRegistry = ModelRegistry.inMemory(authStorage);
|
|
494
|
+
modelRegistry.registerProvider(QUIRE_MODEL_PROVIDER, {
|
|
495
|
+
name: "Quire Credits",
|
|
496
|
+
baseUrl: credentials.apiBaseUrl,
|
|
497
|
+
apiKey: QUIRE_RUNTIME_AUTH_ENV,
|
|
498
|
+
api: QUIRE_MODEL_API,
|
|
499
|
+
models: [quireModelDefinition()],
|
|
500
|
+
streamSimple: createQuireCreditsStream({
|
|
501
|
+
apiBaseUrl: credentials.apiBaseUrl,
|
|
502
|
+
tokenType: credentials.tokenType,
|
|
503
|
+
runId,
|
|
504
|
+
fetchFn
|
|
505
|
+
})
|
|
506
|
+
});
|
|
507
|
+
const model = modelRegistry.find(QUIRE_MODEL_PROVIDER, QUIRE_MODEL_ID);
|
|
508
|
+
if (!model) throw new Error(`Quire model not found: ${QUIRE_MODEL_PROVIDER}/${QUIRE_MODEL_ID}`);
|
|
509
|
+
return {
|
|
510
|
+
authStorage,
|
|
511
|
+
modelRegistry,
|
|
512
|
+
model,
|
|
513
|
+
source: "quire_credits"
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
async function createInvestigationModelSessionDependencies({ runId, store = authStore, fetchFn, localAuthStorage }) {
|
|
517
|
+
const localCodex = await createLocalCodexSessionDependencies(localAuthStorage);
|
|
518
|
+
if (localCodex) return localCodex;
|
|
519
|
+
return createQuireModelSessionDependencies({
|
|
520
|
+
runId,
|
|
521
|
+
store,
|
|
522
|
+
fetchFn
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
async function createLocalCodexSessionDependencies(localAuthStorage) {
|
|
526
|
+
const authStorages = localAuthStorage === void 0 ? [AuthStorage.create(readQuireModelAuthPath()), AuthStorage.create()] : [localAuthStorage];
|
|
527
|
+
for (const authStorage of authStorages) {
|
|
528
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
529
|
+
const model = modelRegistry.find(PI_CODEX_MODEL_PROVIDER, PI_CODEX_MODEL_ID);
|
|
530
|
+
if (!model || !modelRegistry.hasConfiguredAuth(model)) continue;
|
|
531
|
+
const auth = await modelRegistry.getApiKeyAndHeaders(model);
|
|
532
|
+
if (!auth.ok || !auth.apiKey && !auth.headers) continue;
|
|
533
|
+
return {
|
|
534
|
+
authStorage,
|
|
535
|
+
modelRegistry,
|
|
536
|
+
model,
|
|
537
|
+
source: "local_openai_codex"
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
function readQuireModelAuthPath() {
|
|
543
|
+
const envPath = process.env[QUIRE_MODEL_AUTH_PATH_ENV]?.trim();
|
|
544
|
+
return envPath && envPath.length > 0 ? envPath : join(homedir(), ".quire", "model-auth.json");
|
|
545
|
+
}
|
|
546
|
+
function quireModelDefinition() {
|
|
547
|
+
return {
|
|
548
|
+
id: QUIRE_MODEL_ID,
|
|
549
|
+
name: "Quire Credits GPT-5.1",
|
|
550
|
+
api: QUIRE_MODEL_API,
|
|
551
|
+
reasoning: true,
|
|
552
|
+
thinkingLevelMap: {
|
|
553
|
+
off: null,
|
|
554
|
+
xhigh: "high"
|
|
555
|
+
},
|
|
556
|
+
input: ["text"],
|
|
557
|
+
cost: {
|
|
558
|
+
input: 1.25,
|
|
559
|
+
output: 10,
|
|
560
|
+
cacheRead: .125,
|
|
561
|
+
cacheWrite: 0
|
|
562
|
+
},
|
|
563
|
+
contextWindow: 128e3,
|
|
564
|
+
maxTokens: 32e3
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function createQuireCreditsStream(options) {
|
|
568
|
+
return (model, context, streamOptions) => {
|
|
569
|
+
const stream = createAssistantMessageEventStream();
|
|
570
|
+
(async () => {
|
|
571
|
+
const output = createEmptyAssistantMessage(model);
|
|
572
|
+
try {
|
|
573
|
+
const accessToken = streamOptions?.apiKey;
|
|
574
|
+
if (!accessToken) throw new CliError$1("Not logged in. Run `quire login` before `quire investigate` so Quire Credits can be checked.", ExitCode.AuthFailure);
|
|
575
|
+
stream.push({
|
|
576
|
+
type: "start",
|
|
577
|
+
partial: output
|
|
578
|
+
});
|
|
579
|
+
applyBrokerResponseToStream(stream, output, model, await requestBrokerChatCompletion({
|
|
580
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
581
|
+
accessToken,
|
|
582
|
+
tokenType: options.tokenType,
|
|
583
|
+
runId: options.runId,
|
|
584
|
+
model,
|
|
585
|
+
context,
|
|
586
|
+
streamOptions,
|
|
587
|
+
fetchFn: options.fetchFn
|
|
588
|
+
}));
|
|
589
|
+
} catch (error) {
|
|
590
|
+
output.stopReason = streamOptions?.signal?.aborted ? "aborted" : "error";
|
|
591
|
+
output.errorMessage = error instanceof Error ? error.message : String(error);
|
|
592
|
+
stream.push({
|
|
593
|
+
type: "error",
|
|
594
|
+
reason: output.stopReason,
|
|
595
|
+
error: output
|
|
596
|
+
});
|
|
597
|
+
stream.end();
|
|
598
|
+
}
|
|
599
|
+
})();
|
|
600
|
+
return stream;
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
async function readValidatedQuireCredentials(options) {
|
|
604
|
+
const credentials = await resolveAuthCredentials({ store: options.store });
|
|
605
|
+
if (!credentials) throw new CliError$1("Not logged in. Run `quire login` or set QUIRE_API_TOKEN before `quire investigate` so Quire Credits can be checked.", ExitCode.AuthFailure);
|
|
606
|
+
if (credentials.tokenType === "QuireApiKey") return credentials;
|
|
607
|
+
const sessionLookup = await fetchCurrentSession({
|
|
608
|
+
apiBaseUrl: credentials.apiBaseUrl,
|
|
609
|
+
accessToken: credentials.accessToken,
|
|
610
|
+
tokenType: credentials.tokenType,
|
|
611
|
+
fetchFn: options.fetchFn
|
|
612
|
+
});
|
|
613
|
+
if (!sessionLookup.data) {
|
|
614
|
+
await options.store.clear();
|
|
615
|
+
throw new CliError$1("Stored Quire credentials are no longer valid. Run `quire login`.", ExitCode.AuthFailure);
|
|
616
|
+
}
|
|
617
|
+
if (!sessionLookup.refreshedAccessToken) return credentials;
|
|
618
|
+
const refreshedCredentials = updateStoredCredentials(credentials, {
|
|
619
|
+
accessToken: sessionLookup.refreshedAccessToken,
|
|
620
|
+
expiresAt: sessionLookup.data.session.expiresAt,
|
|
621
|
+
user: sessionLookup.data.user
|
|
622
|
+
});
|
|
623
|
+
await options.store.set(refreshedCredentials);
|
|
624
|
+
return refreshedCredentials;
|
|
625
|
+
}
|
|
626
|
+
async function requestBrokerChatCompletion(input) {
|
|
627
|
+
const response = await (input.fetchFn ?? fetch)(new URL("/api/model-broker/chat-completions", input.apiBaseUrl).toString(), {
|
|
628
|
+
method: "POST",
|
|
629
|
+
headers: {
|
|
630
|
+
Accept: "application/json",
|
|
631
|
+
...authHeaders(input),
|
|
632
|
+
"Content-Type": "application/json",
|
|
633
|
+
"User-Agent": "quire-cli"
|
|
634
|
+
},
|
|
635
|
+
signal: input.streamOptions?.signal,
|
|
636
|
+
body: JSON.stringify({
|
|
637
|
+
model: input.model.id,
|
|
638
|
+
messages: toBrokerMessages(input.model, input.context),
|
|
639
|
+
runId: input.runId,
|
|
640
|
+
stream: false,
|
|
641
|
+
agentContext: {
|
|
642
|
+
messages: [],
|
|
643
|
+
tools: toBrokerTools(input.context.tools)
|
|
644
|
+
},
|
|
645
|
+
agentOptions: {
|
|
646
|
+
reasoning: normalizeReasoning(input.streamOptions?.reasoning),
|
|
647
|
+
sessionId: input.streamOptions?.sessionId ?? null
|
|
648
|
+
}
|
|
649
|
+
})
|
|
650
|
+
});
|
|
651
|
+
const body = await readJsonBody(response);
|
|
652
|
+
if (!response.ok || body?.status !== "succeeded") throw brokerResponseError(response, body);
|
|
653
|
+
const rawResponse = body.data?.response;
|
|
654
|
+
if (!rawResponse || typeof rawResponse !== "object" || Array.isArray(rawResponse)) throw new Error("Quire model broker returned an invalid model response.");
|
|
655
|
+
return rawResponse;
|
|
656
|
+
}
|
|
657
|
+
function toBrokerMessages(model, context) {
|
|
658
|
+
return convertMessages(model, context, openAiCompletionCompat).map((message) => {
|
|
659
|
+
const record = message;
|
|
660
|
+
const role = normalizeRole(record.role);
|
|
661
|
+
const toolCalls = parseBrokerToolCalls(record.tool_calls);
|
|
662
|
+
return {
|
|
663
|
+
role,
|
|
664
|
+
content: normalizeMessageContent(record.content),
|
|
665
|
+
...typeof record.name === "string" ? { name: record.name } : {},
|
|
666
|
+
...typeof record.tool_call_id === "string" ? { tool_call_id: record.tool_call_id } : {},
|
|
667
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
668
|
+
};
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
function toBrokerTools(tools) {
|
|
672
|
+
return (tools ?? []).map((tool) => ({
|
|
673
|
+
type: "function",
|
|
674
|
+
function: {
|
|
675
|
+
name: tool.name,
|
|
676
|
+
description: tool.description,
|
|
677
|
+
parameters: tool.parameters,
|
|
678
|
+
strict: false
|
|
679
|
+
}
|
|
680
|
+
}));
|
|
681
|
+
}
|
|
682
|
+
function applyBrokerResponseToStream(stream, output, model, response) {
|
|
683
|
+
output.responseId = typeof response.id === "string" ? response.id : void 0;
|
|
684
|
+
output.responseModel = typeof response.model === "string" ? response.model : void 0;
|
|
685
|
+
output.usage = readUsage(response.usage, model);
|
|
686
|
+
const choice = response.choices?.[0];
|
|
687
|
+
const message = choice?.message;
|
|
688
|
+
const content = typeof message?.content === "string" ? message.content : "";
|
|
689
|
+
if (content.length > 0) {
|
|
690
|
+
const textBlock = {
|
|
691
|
+
type: "text",
|
|
692
|
+
text: content
|
|
693
|
+
};
|
|
694
|
+
output.content.push(textBlock);
|
|
695
|
+
const contentIndex = output.content.length - 1;
|
|
696
|
+
stream.push({
|
|
697
|
+
type: "text_start",
|
|
698
|
+
contentIndex,
|
|
699
|
+
partial: output
|
|
700
|
+
});
|
|
701
|
+
stream.push({
|
|
702
|
+
type: "text_delta",
|
|
703
|
+
contentIndex,
|
|
704
|
+
delta: content,
|
|
705
|
+
partial: output
|
|
706
|
+
});
|
|
707
|
+
stream.push({
|
|
708
|
+
type: "text_end",
|
|
709
|
+
contentIndex,
|
|
710
|
+
content,
|
|
711
|
+
partial: output
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
const toolCalls = parseBrokerToolCalls(message?.tool_calls);
|
|
715
|
+
for (const toolCall of toolCalls) {
|
|
716
|
+
const block = {
|
|
717
|
+
type: "toolCall",
|
|
718
|
+
id: toolCall.id,
|
|
719
|
+
name: toolCall.function.name,
|
|
720
|
+
arguments: parseToolCallArguments(toolCall.function.arguments)
|
|
721
|
+
};
|
|
722
|
+
output.content.push(block);
|
|
723
|
+
const contentIndex = output.content.length - 1;
|
|
724
|
+
stream.push({
|
|
725
|
+
type: "toolcall_start",
|
|
726
|
+
contentIndex,
|
|
727
|
+
partial: output
|
|
728
|
+
});
|
|
729
|
+
stream.push({
|
|
730
|
+
type: "toolcall_delta",
|
|
731
|
+
contentIndex,
|
|
732
|
+
delta: toolCall.function.arguments,
|
|
733
|
+
partial: output
|
|
734
|
+
});
|
|
735
|
+
stream.push({
|
|
736
|
+
type: "toolcall_end",
|
|
737
|
+
contentIndex,
|
|
738
|
+
toolCall: block,
|
|
739
|
+
partial: output
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
output.stopReason = mapStopReason(choice?.finish_reason, toolCalls.length > 0);
|
|
743
|
+
stream.push({
|
|
744
|
+
type: "done",
|
|
745
|
+
reason: output.stopReason,
|
|
746
|
+
message: output
|
|
747
|
+
});
|
|
748
|
+
stream.end();
|
|
749
|
+
}
|
|
750
|
+
function createEmptyAssistantMessage(model) {
|
|
751
|
+
return {
|
|
752
|
+
role: "assistant",
|
|
753
|
+
content: [],
|
|
754
|
+
api: model.api,
|
|
755
|
+
provider: model.provider,
|
|
756
|
+
model: model.id,
|
|
757
|
+
usage: emptyUsage(),
|
|
758
|
+
stopReason: "stop",
|
|
759
|
+
timestamp: Date.now()
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
function emptyUsage() {
|
|
763
|
+
return {
|
|
764
|
+
input: 0,
|
|
765
|
+
output: 0,
|
|
766
|
+
cacheRead: 0,
|
|
767
|
+
cacheWrite: 0,
|
|
768
|
+
totalTokens: 0,
|
|
769
|
+
cost: {
|
|
770
|
+
input: 0,
|
|
771
|
+
output: 0,
|
|
772
|
+
cacheRead: 0,
|
|
773
|
+
cacheWrite: 0,
|
|
774
|
+
total: 0
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function readUsage(rawUsage, model) {
|
|
779
|
+
const input = readNumber(rawUsage?.prompt_tokens ?? rawUsage?.promptTokens) ?? 0;
|
|
780
|
+
const output = readNumber(rawUsage?.completion_tokens ?? rawUsage?.completionTokens) ?? 0;
|
|
781
|
+
const usage = {
|
|
782
|
+
input,
|
|
783
|
+
output,
|
|
784
|
+
cacheRead: 0,
|
|
785
|
+
cacheWrite: 0,
|
|
786
|
+
totalTokens: readNumber(rawUsage?.total_tokens ?? rawUsage?.totalTokens) ?? input + output,
|
|
787
|
+
cost: {
|
|
788
|
+
input: 0,
|
|
789
|
+
output: 0,
|
|
790
|
+
cacheRead: 0,
|
|
791
|
+
cacheWrite: 0,
|
|
792
|
+
total: 0
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
calculateCost(model, usage);
|
|
796
|
+
return usage;
|
|
797
|
+
}
|
|
798
|
+
function mapStopReason(finishReason, hasToolCalls) {
|
|
799
|
+
if (finishReason === "length") return "length";
|
|
800
|
+
if (hasToolCalls || finishReason === "tool_calls" || finishReason === "function_call") return "toolUse";
|
|
801
|
+
return "stop";
|
|
802
|
+
}
|
|
803
|
+
function normalizeRole(value) {
|
|
804
|
+
if (value === "developer") return "system";
|
|
805
|
+
if (value === "system" || value === "user" || value === "assistant" || value === "tool") return value;
|
|
806
|
+
throw new Error(`Unsupported broker message role: ${String(value)}`);
|
|
807
|
+
}
|
|
808
|
+
function normalizeMessageContent(value) {
|
|
809
|
+
if (typeof value === "string") return value;
|
|
810
|
+
if (value === null || value === void 0) return "";
|
|
811
|
+
if (Array.isArray(value)) {
|
|
812
|
+
const text = value.map((part) => {
|
|
813
|
+
if (!part || typeof part !== "object" || Array.isArray(part)) return "";
|
|
814
|
+
const record = part;
|
|
815
|
+
return record.type === "text" && typeof record.text === "string" ? record.text : "[non-text content omitted]";
|
|
816
|
+
}).filter((part) => part.length > 0).join("\n");
|
|
817
|
+
return text.length > 0 ? text : "[non-text content omitted]";
|
|
818
|
+
}
|
|
819
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
820
|
+
return "[non-text content omitted]";
|
|
821
|
+
}
|
|
822
|
+
function parseBrokerToolCalls(value) {
|
|
823
|
+
if (!Array.isArray(value)) return [];
|
|
824
|
+
return value.flatMap((toolCall, index) => {
|
|
825
|
+
if (!toolCall || typeof toolCall !== "object" || Array.isArray(toolCall)) return [];
|
|
826
|
+
const record = toolCall;
|
|
827
|
+
const fn = record.function;
|
|
828
|
+
if (!fn || typeof fn !== "object" || Array.isArray(fn)) return [];
|
|
829
|
+
const functionRecord = fn;
|
|
830
|
+
const name = typeof functionRecord.name === "string" ? functionRecord.name : "";
|
|
831
|
+
if (!name) return [];
|
|
832
|
+
return [{
|
|
833
|
+
id: typeof record.id === "string" ? record.id : `call_${index}`,
|
|
834
|
+
type: "function",
|
|
835
|
+
function: {
|
|
836
|
+
name,
|
|
837
|
+
arguments: typeof functionRecord.arguments === "string" ? functionRecord.arguments : "{}"
|
|
838
|
+
}
|
|
839
|
+
}];
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
function parseToolCallArguments(value) {
|
|
843
|
+
try {
|
|
844
|
+
const parsed = JSON.parse(value);
|
|
845
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
846
|
+
} catch {
|
|
847
|
+
return {};
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
async function readJsonBody(response) {
|
|
851
|
+
const text = await response.text();
|
|
852
|
+
if (!text) return null;
|
|
853
|
+
try {
|
|
854
|
+
return JSON.parse(text);
|
|
855
|
+
} catch {
|
|
856
|
+
return text;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
function brokerResponseError(response, body) {
|
|
860
|
+
const code = body?.error?.code ?? `http_${response.status}`;
|
|
861
|
+
const message = body?.error?.message ?? `Quire model broker request failed with HTTP ${response.status}`;
|
|
862
|
+
const action = body?.error?.nextAction;
|
|
863
|
+
const billingDetail = formatBrokerBillingDetail(body);
|
|
864
|
+
return new Error([
|
|
865
|
+
`Quire model broker request failed (${code}): ${message}`,
|
|
866
|
+
billingDetail,
|
|
867
|
+
action === void 0 ? void 0 : `Next action: ${action}.`
|
|
868
|
+
].filter((part) => part !== void 0 && part.length > 0).join(" "));
|
|
869
|
+
}
|
|
870
|
+
function normalizeReasoning(reasoning) {
|
|
871
|
+
return reasoning === "minimal" || reasoning === "low" || reasoning === "medium" || reasoning === "high" || reasoning === "xhigh" ? reasoning : void 0;
|
|
872
|
+
}
|
|
873
|
+
function readNumber(value) {
|
|
874
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
875
|
+
}
|
|
876
|
+
function formatBrokerBillingDetail(body) {
|
|
877
|
+
const requiredBalance = readNumber(body?.metadata?.wallet?.requiredBalance) ?? readNumber(body?.metadata?.billing?.wallet?.requiredBalance) ?? readNumber(body?.metadata?.billing?.wallet?.estimatedTotalTokens);
|
|
878
|
+
const remainingBalance = readNumber(body?.metadata?.wallet?.balance?.remaining);
|
|
879
|
+
if (requiredBalance === null && remainingBalance === null) return;
|
|
880
|
+
return `Wallet: ${[requiredBalance === null ? void 0 : `required=${requiredBalance}`, remainingBalance === null ? void 0 : `remaining=${remainingBalance}`].filter((part) => part !== void 0).join(", ")}.`;
|
|
881
|
+
}
|
|
882
|
+
//#endregion
|
|
883
|
+
//#region src/commands/connect.ts
|
|
884
|
+
const connectCommand = defineCommand({
|
|
885
|
+
meta: {
|
|
886
|
+
name: "connect",
|
|
887
|
+
description: "Connect local provider accounts used by Quire investigations."
|
|
888
|
+
},
|
|
889
|
+
subCommands: { chatgpt: defineCommand({
|
|
890
|
+
meta: {
|
|
891
|
+
name: "chatgpt",
|
|
892
|
+
description: "Connect ChatGPT/Codex subscription auth for local investigations."
|
|
893
|
+
},
|
|
894
|
+
args: {
|
|
895
|
+
"no-open": {
|
|
896
|
+
type: "boolean",
|
|
897
|
+
description: "Print the authorization URL without trying to open a browser."
|
|
898
|
+
},
|
|
899
|
+
json: {
|
|
900
|
+
type: "boolean",
|
|
901
|
+
description: "Print machine-readable connection state to stdout."
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
async run({ args }) {
|
|
905
|
+
await runConnectChatgpt({
|
|
906
|
+
noOpen: args["no-open"] === true,
|
|
907
|
+
json: args.json === true
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
}) }
|
|
911
|
+
});
|
|
912
|
+
async function runConnectChatgpt(options = {}) {
|
|
913
|
+
const stdout = options.io?.stdout ?? process.stdout;
|
|
914
|
+
const stderr = options.io?.stderr ?? process.stderr;
|
|
915
|
+
const modelAuthPath = options.modelAuthPath ?? readQuireModelAuthPath();
|
|
916
|
+
const modelAuthStorage = options.modelAuthStorage ?? AuthStorage.create(modelAuthPath);
|
|
917
|
+
const loginChatgpt = options.loginChatgpt ?? loginOpenAICodex;
|
|
918
|
+
if (options.json !== true) {
|
|
919
|
+
writeLine(stdout, "Connect ChatGPT for local Quire investigations");
|
|
920
|
+
writeLine(stdout, "Quire will store Pi-compatible OpenAI Codex auth locally and use it before Quire Credits.");
|
|
921
|
+
}
|
|
922
|
+
const credentials = await loginChatgpt({
|
|
923
|
+
originator: "quire",
|
|
924
|
+
onAuth: (info) => {
|
|
925
|
+
const authOutput = options.json === true ? stderr : stdout;
|
|
926
|
+
writeLine(authOutput, `Authorization URL: ${info.url}`);
|
|
927
|
+
if (info.instructions) writeLine(authOutput, info.instructions);
|
|
928
|
+
if (options.noOpen === true) return;
|
|
929
|
+
(async () => {
|
|
930
|
+
let opened = false;
|
|
931
|
+
try {
|
|
932
|
+
opened = await (options.opener ?? openBrowser)(info.url);
|
|
933
|
+
} catch {
|
|
934
|
+
opened = false;
|
|
935
|
+
}
|
|
936
|
+
writeLine(stderr, opened ? "Opened ChatGPT authorization in your browser." : "Could not open a browser automatically; open the authorization URL manually.");
|
|
937
|
+
})();
|
|
938
|
+
},
|
|
939
|
+
onPrompt: async (prompt) => {
|
|
940
|
+
const message = prompt.placeholder ? `${prompt.message} (${prompt.placeholder})` : prompt.message;
|
|
941
|
+
return (options.promptForLine ?? promptForLine)(message);
|
|
942
|
+
},
|
|
943
|
+
onProgress: (message) => {
|
|
944
|
+
writeLine(stderr, message);
|
|
945
|
+
}
|
|
946
|
+
});
|
|
947
|
+
modelAuthStorage.set(PI_CODEX_MODEL_PROVIDER, oauthCredential(credentials));
|
|
948
|
+
if (options.json === true) {
|
|
949
|
+
writeJson(stdout, {
|
|
950
|
+
connected: true,
|
|
951
|
+
provider: PI_CODEX_MODEL_PROVIDER,
|
|
952
|
+
authPath: modelAuthPath,
|
|
953
|
+
source: "quire_model_auth"
|
|
954
|
+
});
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
writeLine(stdout, "ChatGPT connected for local Quire investigations.");
|
|
958
|
+
writeLine(stderr, `Credentials saved to ${modelAuthPath}.`);
|
|
959
|
+
}
|
|
960
|
+
function oauthCredential(credentials) {
|
|
961
|
+
return {
|
|
962
|
+
type: "oauth",
|
|
963
|
+
...credentials
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
async function promptForLine(message) {
|
|
967
|
+
const rl = createInterface({
|
|
968
|
+
input: process.stdin,
|
|
969
|
+
output: process.stdout
|
|
970
|
+
});
|
|
971
|
+
try {
|
|
972
|
+
return await rl.question(`${message} `);
|
|
973
|
+
} catch (error) {
|
|
974
|
+
throw new CliError$1(`Could not read authorization code: ${error instanceof Error ? error.message : String(error)}`, ExitCode.InvalidInput);
|
|
975
|
+
} finally {
|
|
976
|
+
rl.close();
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
//#endregion
|
|
37
980
|
//#region src/doctor/render.ts
|
|
38
981
|
const SECTION_TITLES = {
|
|
39
982
|
identity: "Identity",
|
|
@@ -152,352 +1095,6 @@ function normalizeFieldPath(path) {
|
|
|
152
1095
|
return path;
|
|
153
1096
|
}
|
|
154
1097
|
//#endregion
|
|
155
|
-
//#region src/exit-codes.ts
|
|
156
|
-
const ExitCode = {
|
|
157
|
-
Success: 0,
|
|
158
|
-
InternalError: 1,
|
|
159
|
-
InvalidInput: 2,
|
|
160
|
-
AuthFailure: 10,
|
|
161
|
-
NetworkFailure: 11
|
|
162
|
-
};
|
|
163
|
-
var CliError$1 = class extends Error {
|
|
164
|
-
constructor(message, exitCode = ExitCode.InternalError) {
|
|
165
|
-
super(message);
|
|
166
|
-
this.exitCode = exitCode;
|
|
167
|
-
this.name = "CliError";
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
function readExitCode(error) {
|
|
171
|
-
return error instanceof CliError$1 ? error.exitCode : ExitCode.InternalError;
|
|
172
|
-
}
|
|
173
|
-
function toOneLineError(error) {
|
|
174
|
-
return (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim() || "unknown error";
|
|
175
|
-
}
|
|
176
|
-
//#endregion
|
|
177
|
-
//#region src/auth/api.ts
|
|
178
|
-
const CLIENT_ID = "quire-cli";
|
|
179
|
-
const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
180
|
-
var HttpError = class extends CliError$1 {
|
|
181
|
-
constructor(message, status, body, code) {
|
|
182
|
-
super(message, status === 401 || status === 403 ? ExitCode.AuthFailure : ExitCode.NetworkFailure);
|
|
183
|
-
this.status = status;
|
|
184
|
-
this.body = body;
|
|
185
|
-
this.code = code;
|
|
186
|
-
this.name = "HttpError";
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
function readApiBaseUrl(value = process.env.QUIRE_API_URL ?? "https://quire.sh") {
|
|
190
|
-
return normalizeApiBaseUrl(value);
|
|
191
|
-
}
|
|
192
|
-
function normalizeApiBaseUrl(value) {
|
|
193
|
-
try {
|
|
194
|
-
const url = new URL(value);
|
|
195
|
-
url.pathname = url.pathname.replace(/\/+$/, "");
|
|
196
|
-
url.search = "";
|
|
197
|
-
url.hash = "";
|
|
198
|
-
return url.toString().replace(/\/$/, "");
|
|
199
|
-
} catch {
|
|
200
|
-
throw new CliError$1(`Invalid Quire API URL: ${value}`, ExitCode.InvalidInput);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
async function requestDeviceCode(options) {
|
|
204
|
-
return parseDeviceCodeResponse((await requestJson$1({
|
|
205
|
-
url: authUrl(options.apiBaseUrl, "/device/code"),
|
|
206
|
-
fetchFn: options.fetchFn,
|
|
207
|
-
init: {
|
|
208
|
-
method: "POST",
|
|
209
|
-
headers: jsonHeaders(),
|
|
210
|
-
body: JSON.stringify({
|
|
211
|
-
client_id: CLIENT_ID,
|
|
212
|
-
...options.scope === void 0 ? {} : { scope: options.scope }
|
|
213
|
-
})
|
|
214
|
-
}
|
|
215
|
-
})).body);
|
|
216
|
-
}
|
|
217
|
-
async function requestDeviceToken(options) {
|
|
218
|
-
return parseDeviceTokenResponse((await requestJson$1({
|
|
219
|
-
url: authUrl(options.apiBaseUrl, "/device/token"),
|
|
220
|
-
fetchFn: options.fetchFn,
|
|
221
|
-
init: {
|
|
222
|
-
method: "POST",
|
|
223
|
-
headers: jsonHeaders(),
|
|
224
|
-
body: JSON.stringify({
|
|
225
|
-
grant_type: DEVICE_GRANT_TYPE,
|
|
226
|
-
device_code: options.deviceCode,
|
|
227
|
-
client_id: CLIENT_ID
|
|
228
|
-
})
|
|
229
|
-
}
|
|
230
|
-
})).body);
|
|
231
|
-
}
|
|
232
|
-
async function fetchCurrentSession(options) {
|
|
233
|
-
const response = await requestJson$1({
|
|
234
|
-
url: authUrl(options.apiBaseUrl, "/get-session"),
|
|
235
|
-
fetchFn: options.fetchFn,
|
|
236
|
-
init: {
|
|
237
|
-
method: "GET",
|
|
238
|
-
headers: {
|
|
239
|
-
Accept: "application/json",
|
|
240
|
-
Authorization: `Bearer ${options.accessToken}`
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
const refreshedAccessToken = response.response.headers.get("set-auth-token") ?? void 0;
|
|
245
|
-
return {
|
|
246
|
-
data: parseCurrentSession(response.body),
|
|
247
|
-
...refreshedAccessToken === void 0 ? {} : { refreshedAccessToken }
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
async function fetchModelSourceBrokerStatus(options) {
|
|
251
|
-
return parseModelSourceBrokerStatus((await requestJson$1({
|
|
252
|
-
url: apiUrl(options.apiBaseUrl, "/api/model-sources"),
|
|
253
|
-
fetchFn: options.fetchFn,
|
|
254
|
-
init: {
|
|
255
|
-
method: "GET",
|
|
256
|
-
headers: {
|
|
257
|
-
Accept: "application/json",
|
|
258
|
-
Authorization: `Bearer ${options.accessToken}`,
|
|
259
|
-
"User-Agent": "quire-cli"
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
})).body);
|
|
263
|
-
}
|
|
264
|
-
function authUrl(apiBaseUrl, path) {
|
|
265
|
-
return apiUrl(apiBaseUrl, `/api/auth${path}`);
|
|
266
|
-
}
|
|
267
|
-
function apiUrl(apiBaseUrl, path) {
|
|
268
|
-
return new URL(path, apiBaseUrl).toString();
|
|
269
|
-
}
|
|
270
|
-
function jsonHeaders() {
|
|
271
|
-
return {
|
|
272
|
-
Accept: "application/json",
|
|
273
|
-
"Content-Type": "application/json",
|
|
274
|
-
"User-Agent": "quire-cli"
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
async function requestJson$1(options) {
|
|
278
|
-
let response;
|
|
279
|
-
try {
|
|
280
|
-
response = await (options.fetchFn ?? fetch)(options.url, options.init);
|
|
281
|
-
} catch (error) {
|
|
282
|
-
throw new CliError$1(`Could not reach Quire API: ${error instanceof Error ? error.message : String(error)}`, ExitCode.NetworkFailure);
|
|
283
|
-
}
|
|
284
|
-
const body = await readResponseBody(response);
|
|
285
|
-
if (!response.ok) {
|
|
286
|
-
const { code, description } = readErrorBody(body);
|
|
287
|
-
throw new HttpError(description ?? `Quire API request failed with HTTP ${response.status}`, response.status, body, code);
|
|
288
|
-
}
|
|
289
|
-
return {
|
|
290
|
-
body,
|
|
291
|
-
response
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
async function readResponseBody(response) {
|
|
295
|
-
const text = await response.text();
|
|
296
|
-
if (!text) return null;
|
|
297
|
-
try {
|
|
298
|
-
return JSON.parse(text);
|
|
299
|
-
} catch {
|
|
300
|
-
return text;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
function readErrorBody(body) {
|
|
304
|
-
if (!isRecord$21(body)) return {};
|
|
305
|
-
return {
|
|
306
|
-
code: typeof body.error === "string" ? body.error : void 0,
|
|
307
|
-
description: typeof body.error_description === "string" ? body.error_description : typeof body.message === "string" ? body.message : void 0
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
function parseDeviceCodeResponse(value) {
|
|
311
|
-
if (!isRecord$21(value)) throw new CliError$1("Quire API returned an invalid device code response", ExitCode.NetworkFailure);
|
|
312
|
-
const response = {
|
|
313
|
-
device_code: value.device_code,
|
|
314
|
-
user_code: value.user_code,
|
|
315
|
-
verification_uri: value.verification_uri,
|
|
316
|
-
verification_uri_complete: value.verification_uri_complete,
|
|
317
|
-
expires_in: value.expires_in,
|
|
318
|
-
interval: value.interval
|
|
319
|
-
};
|
|
320
|
-
if (typeof response.device_code !== "string" || typeof response.user_code !== "string" || typeof response.verification_uri !== "string" || typeof response.verification_uri_complete !== "string" || typeof response.expires_in !== "number" || typeof response.interval !== "number") throw new CliError$1("Quire API returned an invalid device code response", ExitCode.NetworkFailure);
|
|
321
|
-
return response;
|
|
322
|
-
}
|
|
323
|
-
function parseDeviceTokenResponse(value) {
|
|
324
|
-
if (!isRecord$21(value) || typeof value.access_token !== "string") throw new CliError$1("Quire API returned an invalid device token response", ExitCode.NetworkFailure);
|
|
325
|
-
if (value.expires_in !== void 0 && typeof value.expires_in !== "number") throw new CliError$1("Quire API returned an invalid device token response", ExitCode.NetworkFailure);
|
|
326
|
-
if (value.scope !== void 0 && typeof value.scope !== "string") throw new CliError$1("Quire API returned an invalid device token response", ExitCode.NetworkFailure);
|
|
327
|
-
return {
|
|
328
|
-
access_token: value.access_token,
|
|
329
|
-
token_type: typeof value.token_type === "string" ? value.token_type : "Bearer",
|
|
330
|
-
...value.expires_in === void 0 ? {} : { expires_in: value.expires_in },
|
|
331
|
-
...value.scope === void 0 ? {} : { scope: value.scope }
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
function parseCurrentSession(value) {
|
|
335
|
-
if (value === null) return null;
|
|
336
|
-
if (!isRecord$21(value) || !isRecord$21(value.session) || !isRecord$21(value.user)) throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
337
|
-
if (typeof value.session.id !== "string" || typeof value.user.id !== "string") throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
338
|
-
if (value.user.email !== void 0 && value.user.email !== null && typeof value.user.email !== "string") throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
339
|
-
if (value.user.name !== void 0 && value.user.name !== null && typeof value.user.name !== "string") throw new CliError$1("Quire API returned an invalid session response", ExitCode.NetworkFailure);
|
|
340
|
-
return {
|
|
341
|
-
session: {
|
|
342
|
-
id: value.session.id,
|
|
343
|
-
...typeof value.session.expiresAt === "string" ? { expiresAt: value.session.expiresAt } : {}
|
|
344
|
-
},
|
|
345
|
-
user: {
|
|
346
|
-
id: value.user.id,
|
|
347
|
-
...value.user.email === void 0 ? {} : { email: value.user.email },
|
|
348
|
-
...value.user.name === void 0 ? {} : { name: value.user.name }
|
|
349
|
-
}
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
function parseModelSourceBrokerStatus(value) {
|
|
353
|
-
if (!isRecord$21(value) || !Array.isArray(value.selectedOrder)) throw new CliError$1("Quire API returned an invalid model-source status response", ExitCode.NetworkFailure);
|
|
354
|
-
const resolvedAvailability = value.resolvedAvailability;
|
|
355
|
-
if (!isRecord$21(resolvedAvailability)) throw new CliError$1("Quire API returned an invalid model-source status response", ExitCode.NetworkFailure);
|
|
356
|
-
const status = resolvedAvailability.status;
|
|
357
|
-
const reason = resolvedAvailability.reason;
|
|
358
|
-
const selectedProviderMode = resolvedAvailability.mode;
|
|
359
|
-
const requiredNextAction = resolvedAvailability.nextAction;
|
|
360
|
-
if (status !== "available" && status !== "unavailable" || typeof reason !== "string" || selectedProviderMode !== null && typeof selectedProviderMode !== "string" || requiredNextAction !== null && typeof requiredNextAction !== "string" || !value.selectedOrder.every((mode) => typeof mode === "string")) throw new CliError$1("Quire API returned an invalid model-source status response", ExitCode.NetworkFailure);
|
|
361
|
-
return {
|
|
362
|
-
available: status === "available",
|
|
363
|
-
status,
|
|
364
|
-
selectedProviderMode,
|
|
365
|
-
selectedOrder: value.selectedOrder,
|
|
366
|
-
reason,
|
|
367
|
-
requiredNextAction,
|
|
368
|
-
requiredBalance: readWalletRequiredBalance(value),
|
|
369
|
-
remainingBalance: readWalletRemainingBalance(value),
|
|
370
|
-
recentUsage: readRecentUsage(value)
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
function isRecord$21(value) {
|
|
374
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
375
|
-
}
|
|
376
|
-
function readWalletRequiredBalance(value) {
|
|
377
|
-
const source = readFirstSource(value);
|
|
378
|
-
const requiredBalance = (isRecord$21(source?.wallet) ? source.wallet : null)?.requiredBalance;
|
|
379
|
-
return typeof requiredBalance === "number" && Number.isFinite(requiredBalance) ? requiredBalance : null;
|
|
380
|
-
}
|
|
381
|
-
function readWalletRemainingBalance(value) {
|
|
382
|
-
const source = readFirstSource(value);
|
|
383
|
-
const wallet = isRecord$21(source?.wallet) ? source.wallet : null;
|
|
384
|
-
const remaining = (isRecord$21(wallet?.balance) ? wallet.balance : null)?.remaining;
|
|
385
|
-
return typeof remaining === "number" && Number.isFinite(remaining) ? remaining : null;
|
|
386
|
-
}
|
|
387
|
-
function readFirstSource(value) {
|
|
388
|
-
if (!Array.isArray(value.sources)) return null;
|
|
389
|
-
const [source] = value.sources;
|
|
390
|
-
return isRecord$21(source) ? source : null;
|
|
391
|
-
}
|
|
392
|
-
function readRecentUsage(value) {
|
|
393
|
-
if (!Array.isArray(value.recentUsage)) return [];
|
|
394
|
-
return value.recentUsage.flatMap((event) => {
|
|
395
|
-
if (!isRecord$21(event)) return [];
|
|
396
|
-
if (typeof event.modelId !== "string" || typeof event.status !== "string" || typeof event.totalTokens !== "number" || typeof event.createdAt !== "string") return [];
|
|
397
|
-
return [{
|
|
398
|
-
modelId: event.modelId,
|
|
399
|
-
status: event.status,
|
|
400
|
-
totalTokens: event.totalTokens,
|
|
401
|
-
runId: typeof event.runId === "string" ? event.runId : null,
|
|
402
|
-
createdAt: event.createdAt
|
|
403
|
-
}];
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
//#endregion
|
|
407
|
-
//#region src/auth/store.ts
|
|
408
|
-
function defaultAuthPath(env = process.env) {
|
|
409
|
-
if (env.QUIRE_AUTH_FILE) return resolve(env.QUIRE_AUTH_FILE);
|
|
410
|
-
return join(resolve(env.QUIRE_HOME ?? join(homedir(), ".quire")), "auth.json");
|
|
411
|
-
}
|
|
412
|
-
function createAuthStore(path = defaultAuthPath()) {
|
|
413
|
-
async function get() {
|
|
414
|
-
try {
|
|
415
|
-
const contents = await readFile(path, "utf8");
|
|
416
|
-
return parseStoredCredentials(JSON.parse(contents));
|
|
417
|
-
} catch {
|
|
418
|
-
return null;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
async function set(credentials) {
|
|
422
|
-
await mkdir(dirname(path), {
|
|
423
|
-
recursive: true,
|
|
424
|
-
mode: 448
|
|
425
|
-
});
|
|
426
|
-
await writeFile(path, `${JSON.stringify(credentials, null, 2)}\n`, { mode: 384 });
|
|
427
|
-
}
|
|
428
|
-
async function clear() {
|
|
429
|
-
try {
|
|
430
|
-
await unlink(path);
|
|
431
|
-
} catch {}
|
|
432
|
-
}
|
|
433
|
-
return {
|
|
434
|
-
path,
|
|
435
|
-
get,
|
|
436
|
-
set,
|
|
437
|
-
clear
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
const authStore = createAuthStore();
|
|
441
|
-
function createStoredCredentials(input) {
|
|
442
|
-
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
443
|
-
const timestamp = now.toISOString();
|
|
444
|
-
const expiresAt = input.expiresAt ?? expiresAtFromSeconds(input.expiresIn, now);
|
|
445
|
-
return {
|
|
446
|
-
version: 1,
|
|
447
|
-
apiBaseUrl: input.apiBaseUrl,
|
|
448
|
-
accessToken: input.accessToken,
|
|
449
|
-
tokenType: input.tokenType ?? "Bearer",
|
|
450
|
-
...expiresAt === void 0 ? {} : { expiresAt },
|
|
451
|
-
...input.user === void 0 ? {} : { user: input.user },
|
|
452
|
-
createdAt: timestamp,
|
|
453
|
-
updatedAt: timestamp
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
function updateStoredCredentials(credentials, input) {
|
|
457
|
-
return {
|
|
458
|
-
...credentials,
|
|
459
|
-
accessToken: input.accessToken ?? credentials.accessToken,
|
|
460
|
-
tokenType: input.tokenType ?? credentials.tokenType,
|
|
461
|
-
...input.expiresAt === void 0 ? {} : { expiresAt: input.expiresAt },
|
|
462
|
-
...input.user === void 0 ? {} : { user: input.user },
|
|
463
|
-
updatedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString()
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
function expiresAtFromSeconds(expiresIn, now) {
|
|
467
|
-
return typeof expiresIn === "number" ? new Date(now.getTime() + expiresIn * 1e3).toISOString() : void 0;
|
|
468
|
-
}
|
|
469
|
-
function parseStoredCredentials(value) {
|
|
470
|
-
if (!isRecord$20(value)) return null;
|
|
471
|
-
if (value.version !== 1 || typeof value.apiBaseUrl !== "string" || typeof value.accessToken !== "string" || typeof value.tokenType !== "string" || typeof value.createdAt !== "string" || typeof value.updatedAt !== "string") return null;
|
|
472
|
-
if (value.expiresAt !== void 0 && typeof value.expiresAt !== "string") return null;
|
|
473
|
-
const user = parseStoredUser(value.user);
|
|
474
|
-
if (value.user !== void 0 && user === null) return null;
|
|
475
|
-
return {
|
|
476
|
-
version: 1,
|
|
477
|
-
apiBaseUrl: value.apiBaseUrl,
|
|
478
|
-
accessToken: value.accessToken,
|
|
479
|
-
tokenType: value.tokenType,
|
|
480
|
-
...value.expiresAt === void 0 ? {} : { expiresAt: value.expiresAt },
|
|
481
|
-
...user === void 0 || user === null ? {} : { user },
|
|
482
|
-
createdAt: value.createdAt,
|
|
483
|
-
updatedAt: value.updatedAt
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
function parseStoredUser(value) {
|
|
487
|
-
if (value === void 0) return;
|
|
488
|
-
if (!isRecord$20(value) || typeof value.id !== "string") return null;
|
|
489
|
-
if (value.email !== void 0 && value.email !== null && typeof value.email !== "string") return null;
|
|
490
|
-
if (value.name !== void 0 && value.name !== null && typeof value.name !== "string") return null;
|
|
491
|
-
return {
|
|
492
|
-
id: value.id,
|
|
493
|
-
...value.email === void 0 ? {} : { email: value.email },
|
|
494
|
-
...value.name === void 0 ? {} : { name: value.name }
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
function isRecord$20(value) {
|
|
498
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
499
|
-
}
|
|
500
|
-
//#endregion
|
|
501
1098
|
//#region src/run-dir.ts
|
|
502
1099
|
function createRunDir(repoPath, options = {}) {
|
|
503
1100
|
const workspaceKey = workspaceKeyForRepoPath(resolve(repoPath));
|
|
@@ -628,7 +1225,7 @@ function sanitizeWorkspaceName(value) {
|
|
|
628
1225
|
}
|
|
629
1226
|
function appendLineAtomically(filePath, line) {
|
|
630
1227
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
631
|
-
const file = openSync(filePath, constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY, 384);
|
|
1228
|
+
const file = openSync(filePath, constants$1.O_APPEND | constants$1.O_CREAT | constants$1.O_WRONLY, 384);
|
|
632
1229
|
try {
|
|
633
1230
|
writeFileSync(file, line, "utf8");
|
|
634
1231
|
fsyncSync(file);
|
|
@@ -858,7 +1455,7 @@ async function defaultExecFn(file, args, options) {
|
|
|
858
1455
|
};
|
|
859
1456
|
}
|
|
860
1457
|
async function checkAuthPresent(context) {
|
|
861
|
-
const credentials = await context.authStore
|
|
1458
|
+
const credentials = await resolveAuthCredentials({ store: context.authStore });
|
|
862
1459
|
if (credentials === null) return { result: {
|
|
863
1460
|
id: "auth.present",
|
|
864
1461
|
section: "identity",
|
|
@@ -876,15 +1473,38 @@ async function checkAuthPresent(context) {
|
|
|
876
1473
|
auth: {
|
|
877
1474
|
apiBaseUrl: credentials.apiBaseUrl,
|
|
878
1475
|
accessToken: credentials.accessToken,
|
|
1476
|
+
tokenType: credentials.tokenType,
|
|
879
1477
|
...credentials.user === void 0 ? {} : { user: credentials.user }
|
|
880
1478
|
}
|
|
881
1479
|
};
|
|
882
1480
|
}
|
|
883
1481
|
async function checkAuthValid(context, auth) {
|
|
1482
|
+
if (auth.tokenType === "QuireApiKey") try {
|
|
1483
|
+
return { result: {
|
|
1484
|
+
id: "auth.valid",
|
|
1485
|
+
section: "identity",
|
|
1486
|
+
severity: "pass",
|
|
1487
|
+
message: `API token valid for ${(await fetchModelSourceBrokerStatus({
|
|
1488
|
+
apiBaseUrl: auth.apiBaseUrl,
|
|
1489
|
+
accessToken: auth.accessToken,
|
|
1490
|
+
tokenType: auth.tokenType,
|
|
1491
|
+
fetchFn: context.fetchFn
|
|
1492
|
+
})).actor?.environmentName ?? "remote agent environment"}.`
|
|
1493
|
+
} };
|
|
1494
|
+
} catch (error) {
|
|
1495
|
+
return { result: {
|
|
1496
|
+
id: "auth.valid",
|
|
1497
|
+
section: "identity",
|
|
1498
|
+
severity: "fail",
|
|
1499
|
+
message: `Could not validate Quire API token: ${toMessage(error)}`,
|
|
1500
|
+
fix: { command: "Set QUIRE_API_TOKEN to an active token from Quire settings" }
|
|
1501
|
+
} };
|
|
1502
|
+
}
|
|
884
1503
|
try {
|
|
885
1504
|
const lookup = await fetchCurrentSession({
|
|
886
1505
|
apiBaseUrl: auth.apiBaseUrl,
|
|
887
1506
|
accessToken: auth.accessToken,
|
|
1507
|
+
tokenType: auth.tokenType,
|
|
888
1508
|
fetchFn: context.fetchFn
|
|
889
1509
|
});
|
|
890
1510
|
if (lookup.data === null) return { result: {
|
|
@@ -919,6 +1539,7 @@ async function checkAuthBroker(context, auth) {
|
|
|
919
1539
|
return brokerToCheckResult(await fetchModelSourceBrokerStatus({
|
|
920
1540
|
apiBaseUrl: auth.apiBaseUrl,
|
|
921
1541
|
accessToken: auth.accessToken,
|
|
1542
|
+
tokenType: auth.tokenType,
|
|
922
1543
|
fetchFn: context.fetchFn
|
|
923
1544
|
}));
|
|
924
1545
|
} catch (error) {
|
|
@@ -1174,7 +1795,7 @@ async function checkRunsRoot(context) {
|
|
|
1174
1795
|
recursive: true,
|
|
1175
1796
|
mode: 448
|
|
1176
1797
|
});
|
|
1177
|
-
await access(context.runsRoot, constants
|
|
1798
|
+
await access(context.runsRoot, constants.W_OK);
|
|
1178
1799
|
return {
|
|
1179
1800
|
id: "runs.rootWritable",
|
|
1180
1801
|
section: "runs",
|
|
@@ -7690,81 +8311,104 @@ var require_browser = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
7690
8311
|
};
|
|
7691
8312
|
}));
|
|
7692
8313
|
//#endregion
|
|
7693
|
-
//#region ../../node_modules/.pnpm/
|
|
7694
|
-
var
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
if (
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
8314
|
+
//#region ../../node_modules/.pnpm/supports-color@10.2.2/node_modules/supports-color/index.js
|
|
8315
|
+
var supports_color_exports = /* @__PURE__ */ __exportAll({
|
|
8316
|
+
createSupportsColor: () => createSupportsColor,
|
|
8317
|
+
default: () => supportsColor
|
|
8318
|
+
});
|
|
8319
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
|
|
8320
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
8321
|
+
const position = argv.indexOf(prefix + flag);
|
|
8322
|
+
const terminatorPosition = argv.indexOf("--");
|
|
8323
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
8324
|
+
}
|
|
8325
|
+
function envForceColor() {
|
|
8326
|
+
if (!("FORCE_COLOR" in env)) return;
|
|
8327
|
+
if (env.FORCE_COLOR === "true") return 1;
|
|
8328
|
+
if (env.FORCE_COLOR === "false") return 0;
|
|
8329
|
+
if (env.FORCE_COLOR.length === 0) return 1;
|
|
8330
|
+
const level = Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
8331
|
+
if (![
|
|
8332
|
+
0,
|
|
8333
|
+
1,
|
|
8334
|
+
2,
|
|
8335
|
+
3
|
|
8336
|
+
].includes(level)) return;
|
|
8337
|
+
return level;
|
|
8338
|
+
}
|
|
8339
|
+
function translateLevel(level) {
|
|
8340
|
+
if (level === 0) return false;
|
|
8341
|
+
return {
|
|
8342
|
+
level,
|
|
8343
|
+
hasBasic: true,
|
|
8344
|
+
has256: level >= 2,
|
|
8345
|
+
has16m: level >= 3
|
|
8346
|
+
};
|
|
8347
|
+
}
|
|
8348
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
8349
|
+
const noFlagForceColor = envForceColor();
|
|
8350
|
+
if (noFlagForceColor !== void 0) flagForceColor = noFlagForceColor;
|
|
8351
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
8352
|
+
if (forceColor === 0) return 0;
|
|
8353
|
+
if (sniffFlags) {
|
|
7726
8354
|
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) return 3;
|
|
7727
8355
|
if (hasFlag("color=256")) return 2;
|
|
7728
|
-
if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
|
|
7729
|
-
const min = forceColor || 0;
|
|
7730
|
-
if (env.TERM === "dumb") return min;
|
|
7731
|
-
if (process.platform === "win32") {
|
|
7732
|
-
const osRelease = os$1.release().split(".");
|
|
7733
|
-
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
7734
|
-
return 1;
|
|
7735
|
-
}
|
|
7736
|
-
if ("CI" in env) {
|
|
7737
|
-
if ([
|
|
7738
|
-
"TRAVIS",
|
|
7739
|
-
"CIRCLECI",
|
|
7740
|
-
"APPVEYOR",
|
|
7741
|
-
"GITLAB_CI",
|
|
7742
|
-
"GITHUB_ACTIONS",
|
|
7743
|
-
"BUILDKITE"
|
|
7744
|
-
].some((sign) => sign in env) || env.CI_NAME === "codeship") return 1;
|
|
7745
|
-
return min;
|
|
7746
|
-
}
|
|
7747
|
-
if ("TEAMCITY_VERSION" in env) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
7748
|
-
if (env.COLORTERM === "truecolor") return 3;
|
|
7749
|
-
if ("TERM_PROGRAM" in env) {
|
|
7750
|
-
const version = parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
7751
|
-
switch (env.TERM_PROGRAM) {
|
|
7752
|
-
case "iTerm.app": return version >= 3 ? 3 : 2;
|
|
7753
|
-
case "Apple_Terminal": return 2;
|
|
7754
|
-
}
|
|
7755
|
-
}
|
|
7756
|
-
if (/-256(color)?$/i.test(env.TERM)) return 2;
|
|
7757
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) return 1;
|
|
7758
|
-
if ("COLORTERM" in env) return 1;
|
|
7759
|
-
return min;
|
|
7760
8356
|
}
|
|
7761
|
-
|
|
7762
|
-
|
|
8357
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) return 1;
|
|
8358
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
|
|
8359
|
+
const min = forceColor || 0;
|
|
8360
|
+
if (env.TERM === "dumb") return min;
|
|
8361
|
+
if (process$1.platform === "win32") {
|
|
8362
|
+
const osRelease = os.release().split(".");
|
|
8363
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
8364
|
+
return 1;
|
|
8365
|
+
}
|
|
8366
|
+
if ("CI" in env) {
|
|
8367
|
+
if ([
|
|
8368
|
+
"GITHUB_ACTIONS",
|
|
8369
|
+
"GITEA_ACTIONS",
|
|
8370
|
+
"CIRCLECI"
|
|
8371
|
+
].some((key) => key in env)) return 3;
|
|
8372
|
+
if ([
|
|
8373
|
+
"TRAVIS",
|
|
8374
|
+
"APPVEYOR",
|
|
8375
|
+
"GITLAB_CI",
|
|
8376
|
+
"BUILDKITE",
|
|
8377
|
+
"DRONE"
|
|
8378
|
+
].some((sign) => sign in env) || env.CI_NAME === "codeship") return 1;
|
|
8379
|
+
return min;
|
|
7763
8380
|
}
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
8381
|
+
if ("TEAMCITY_VERSION" in env) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
8382
|
+
if (env.COLORTERM === "truecolor") return 3;
|
|
8383
|
+
if (env.TERM === "xterm-kitty") return 3;
|
|
8384
|
+
if (env.TERM === "xterm-ghostty") return 3;
|
|
8385
|
+
if (env.TERM === "wezterm") return 3;
|
|
8386
|
+
if ("TERM_PROGRAM" in env) {
|
|
8387
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
8388
|
+
switch (env.TERM_PROGRAM) {
|
|
8389
|
+
case "iTerm.app": return version >= 3 ? 3 : 2;
|
|
8390
|
+
case "Apple_Terminal": return 2;
|
|
8391
|
+
}
|
|
8392
|
+
}
|
|
8393
|
+
if (/-256(color)?$/i.test(env.TERM)) return 2;
|
|
8394
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) return 1;
|
|
8395
|
+
if ("COLORTERM" in env) return 1;
|
|
8396
|
+
return min;
|
|
8397
|
+
}
|
|
8398
|
+
function createSupportsColor(stream, options = {}) {
|
|
8399
|
+
return translateLevel(_supportsColor(stream, {
|
|
8400
|
+
streamIsTTY: stream && stream.isTTY,
|
|
8401
|
+
...options
|
|
8402
|
+
}));
|
|
8403
|
+
}
|
|
8404
|
+
var env, flagForceColor, supportsColor;
|
|
8405
|
+
var init_supports_color = __esmMin((() => {
|
|
8406
|
+
({env} = process$1);
|
|
8407
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) flagForceColor = 0;
|
|
8408
|
+
else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) flagForceColor = 1;
|
|
8409
|
+
supportsColor = {
|
|
8410
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
8411
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
7768
8412
|
};
|
|
7769
8413
|
}));
|
|
7770
8414
|
//#endregion
|
|
@@ -7773,7 +8417,7 @@ var require_node$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
7773
8417
|
/**
|
|
7774
8418
|
* Module dependencies.
|
|
7775
8419
|
*/
|
|
7776
|
-
const tty = __require("tty");
|
|
8420
|
+
const tty$1 = __require("tty");
|
|
7777
8421
|
const util$2 = __require("util");
|
|
7778
8422
|
/**
|
|
7779
8423
|
* This is the Node.js implementation of `debug()`.
|
|
@@ -7797,7 +8441,7 @@ var require_node$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
7797
8441
|
1
|
|
7798
8442
|
];
|
|
7799
8443
|
try {
|
|
7800
|
-
const supportsColor =
|
|
8444
|
+
const supportsColor = (init_supports_color(), __toCommonJS(supports_color_exports));
|
|
7801
8445
|
if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) exports.colors = [
|
|
7802
8446
|
20,
|
|
7803
8447
|
21,
|
|
@@ -7900,7 +8544,7 @@ var require_node$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
7900
8544
|
* Is stdout a TTY? Colored output is enabled when `true`.
|
|
7901
8545
|
*/
|
|
7902
8546
|
function useColors() {
|
|
7903
|
-
return "colors" in exports.inspectOpts ? Boolean(exports.inspectOpts.colors) : tty.isatty(process.stderr.fd);
|
|
8547
|
+
return "colors" in exports.inspectOpts ? Boolean(exports.inspectOpts.colors) : tty$1.isatty(process.stderr.fd);
|
|
7904
8548
|
}
|
|
7905
8549
|
/**
|
|
7906
8550
|
* Adds ANSI color escape codes if enabled.
|
|
@@ -31411,7 +32055,7 @@ function isENOENT(err) {
|
|
|
31411
32055
|
return e?.code === "ENOENT" || e?.cause?.code === "ENOENT";
|
|
31412
32056
|
}
|
|
31413
32057
|
function concurrencyLimit() {
|
|
31414
|
-
const cpu = os.cpus()?.length ?? 1;
|
|
32058
|
+
const cpu = os$1.cpus()?.length ?? 1;
|
|
31415
32059
|
return Math.min(4, Math.max(1, cpu - 1));
|
|
31416
32060
|
}
|
|
31417
32061
|
async function mapLimit(items, limit, fn) {
|
|
@@ -31563,7 +32207,7 @@ async function collectAdditionalFiles(additionalFiles) {
|
|
|
31563
32207
|
let xdelta3WasmReady = null;
|
|
31564
32208
|
async function loadXdelta3Wasm() {
|
|
31565
32209
|
if (!xdelta3WasmReady) xdelta3WasmReady = (async () => {
|
|
31566
|
-
const mod = await import("./dist-
|
|
32210
|
+
const mod = await import("./dist-CF5hqugO.mjs").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
|
|
31567
32211
|
await mod.init();
|
|
31568
32212
|
return mod;
|
|
31569
32213
|
})().catch((err) => {
|
|
@@ -31670,7 +32314,7 @@ async function syncFolderOnce(localFolderPath, opts, reason, attempt = 0) {
|
|
|
31670
32314
|
const basisPath = cacheGet(opts.basisCacheDir, f.path);
|
|
31671
32315
|
if (fs.existsSync(basisPath)) {
|
|
31672
32316
|
const basisSha = await sha256FileHex(basisPath);
|
|
31673
|
-
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "limulator-xdelta3-"));
|
|
32317
|
+
const tmpDir = await fs.promises.mkdtemp(path.join(os$1.tmpdir(), "limulator-xdelta3-"));
|
|
31674
32318
|
const patchPath = path.join(tmpDir, "patch.xdelta3");
|
|
31675
32319
|
const encodeStart = nowMs();
|
|
31676
32320
|
const patchSize = await encodeXdelta3Patch(basisPath, f.absPath, patchPath, maxPatchBytes);
|
|
@@ -32144,7 +32788,7 @@ var XcodeInstances = class extends XcodeInstances$1 {
|
|
|
32144
32788
|
async sync(localCodePath, opts) {
|
|
32145
32789
|
const resolvedPath = path.resolve(localCodePath);
|
|
32146
32790
|
const cacheKey = `limsync-cache-${path.basename(resolvedPath)}-${crypto.createHash("sha1").update(resolvedPath).digest("hex").slice(0, 8)}`;
|
|
32147
|
-
const basisCacheDir = opts?.basisCacheDir ?? path.join(os.tmpdir(), cacheKey);
|
|
32791
|
+
const basisCacheDir = opts?.basisCacheDir ?? path.join(os$1.tmpdir(), cacheKey);
|
|
32148
32792
|
const additionalFiles = opts?.additionalFiles?.map((file) => ({
|
|
32149
32793
|
localPath: file.localPath,
|
|
32150
32794
|
remotePath: file.remotePath.startsWith("~/") ? `${sandboxInfo.homeDir}/${file.remotePath.slice(2)}` : file.remotePath
|
|
@@ -38275,7 +38919,7 @@ async function createInstanceClient(options) {
|
|
|
38275
38919
|
if (!cachedDeviceInfo) throw new Error("Device info not available yet; wait for client connection to be established.");
|
|
38276
38920
|
const resolvedPath = path.resolve(localAppBundlePath);
|
|
38277
38921
|
const cacheKey = `limsync-cache-${path.basename(resolvedPath)}-${crypto.createHash("sha1").update(resolvedPath).digest("hex").slice(0, 8)}`;
|
|
38278
|
-
const basisCacheDir = opts?.basisCacheDir ?? path.join(os.tmpdir(), cacheKey);
|
|
38922
|
+
const basisCacheDir = opts?.basisCacheDir ?? path.join(os$1.tmpdir(), cacheKey);
|
|
38279
38923
|
const syncLog = (level, msg) => {
|
|
38280
38924
|
switch (level) {
|
|
38281
38925
|
case "debug":
|
|
@@ -39603,7 +40247,7 @@ async function findExecutable$1(name) {
|
|
|
39603
40247
|
for (const pathEntry of paths) {
|
|
39604
40248
|
const candidate = join(pathEntry, name);
|
|
39605
40249
|
try {
|
|
39606
|
-
await access(candidate, constants.X_OK);
|
|
40250
|
+
await access(candidate, constants$1.X_OK);
|
|
39607
40251
|
return candidate;
|
|
39608
40252
|
} catch {
|
|
39609
40253
|
continue;
|
|
@@ -40386,7 +41030,7 @@ async function findExecutable(name) {
|
|
|
40386
41030
|
for (const pathEntry of paths) {
|
|
40387
41031
|
const candidate = join(pathEntry, name);
|
|
40388
41032
|
try {
|
|
40389
|
-
await access(candidate, constants.X_OK);
|
|
41033
|
+
await access(candidate, constants$1.X_OK);
|
|
40390
41034
|
return candidate;
|
|
40391
41035
|
} catch {
|
|
40392
41036
|
continue;
|
|
@@ -42775,11 +43419,12 @@ function quoteBatchArg(value) {
|
|
|
42775
43419
|
}
|
|
42776
43420
|
//#endregion
|
|
42777
43421
|
//#region src/tools/browser.ts
|
|
43422
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
42778
43423
|
const BrowserToolInputSchema = Type.Object({
|
|
42779
43424
|
argv: Type.Array(Type.String(), { minItems: 1 }),
|
|
42780
43425
|
cwd: Type.Optional(Type.String({ minLength: 1 }))
|
|
42781
43426
|
}, { additionalProperties: false });
|
|
42782
|
-
function makeBrowserTool({ runDir, sessionId, cwd: defaultCwd, headed = false }) {
|
|
43427
|
+
function makeBrowserTool({ runDir, sessionId, cwd: defaultCwd, headed = false, agentBrowserExecutableResolver = resolveAgentBrowserExecutable }) {
|
|
42783
43428
|
return {
|
|
42784
43429
|
name: "agent-browser",
|
|
42785
43430
|
label: "agent-browser",
|
|
@@ -42791,6 +43436,7 @@ function makeBrowserTool({ runDir, sessionId, cwd: defaultCwd, headed = false })
|
|
|
42791
43436
|
sessionId,
|
|
42792
43437
|
defaultCwd,
|
|
42793
43438
|
headed,
|
|
43439
|
+
agentBrowserExecutableResolver,
|
|
42794
43440
|
input,
|
|
42795
43441
|
signal
|
|
42796
43442
|
});
|
|
@@ -42801,6 +43447,7 @@ function makeBrowserTool({ runDir, sessionId, cwd: defaultCwd, headed = false })
|
|
|
42801
43447
|
sessionId,
|
|
42802
43448
|
defaultCwd,
|
|
42803
43449
|
headed,
|
|
43450
|
+
agentBrowserExecutableResolver,
|
|
42804
43451
|
input: parseBrowserToolInput(params),
|
|
42805
43452
|
signal
|
|
42806
43453
|
});
|
|
@@ -42814,11 +43461,18 @@ function makeBrowserTool({ runDir, sessionId, cwd: defaultCwd, headed = false })
|
|
|
42814
43461
|
}
|
|
42815
43462
|
};
|
|
42816
43463
|
}
|
|
43464
|
+
function resolveAgentBrowserExecutable() {
|
|
43465
|
+
const packageJsonPath = requireFromHere.resolve("agent-browser/package.json");
|
|
43466
|
+
return {
|
|
43467
|
+
command: process.execPath,
|
|
43468
|
+
argsPrefix: [join(dirname(packageJsonPath), "bin", "agent-browser.js")]
|
|
43469
|
+
};
|
|
43470
|
+
}
|
|
42817
43471
|
function parseBrowserToolInput(input) {
|
|
42818
43472
|
if (!Value.Check(BrowserToolInputSchema, input)) throw new Error("Invalid agent-browser tool input");
|
|
42819
43473
|
return input;
|
|
42820
43474
|
}
|
|
42821
|
-
async function runBrowserCommand({ runDir, sessionId, defaultCwd, headed, input, signal }) {
|
|
43475
|
+
async function runBrowserCommand({ runDir, sessionId, defaultCwd, headed, agentBrowserExecutableResolver, input, signal }) {
|
|
42822
43476
|
const [executable, ...args] = input.argv;
|
|
42823
43477
|
if (executable !== "agent-browser") throw new Error(`Refusing to spawn non-agent-browser executable: ${executable}`);
|
|
42824
43478
|
const cwd = input.cwd ?? defaultCwd ?? process.cwd();
|
|
@@ -42844,12 +43498,26 @@ async function runBrowserCommand({ runDir, sessionId, defaultCwd, headed, input,
|
|
|
42844
43498
|
sessionId,
|
|
42845
43499
|
cwd,
|
|
42846
43500
|
headed,
|
|
43501
|
+
agentBrowserExecutableResolver,
|
|
42847
43502
|
signal
|
|
42848
43503
|
});
|
|
42849
43504
|
}
|
|
42850
|
-
function spawnAgentBrowser({ args, sessionId, cwd, signal }) {
|
|
43505
|
+
function spawnAgentBrowser({ args, sessionId, cwd, agentBrowserExecutableResolver, signal }) {
|
|
42851
43506
|
return new Promise((resolve) => {
|
|
42852
|
-
|
|
43507
|
+
let executable;
|
|
43508
|
+
try {
|
|
43509
|
+
executable = agentBrowserExecutableResolver();
|
|
43510
|
+
} catch (error) {
|
|
43511
|
+
resolve({
|
|
43512
|
+
ok: false,
|
|
43513
|
+
exitCode: null,
|
|
43514
|
+
stdout: "",
|
|
43515
|
+
stderr: `Unable to resolve bundled agent-browser: ${formatErrorMessage(error)}`
|
|
43516
|
+
});
|
|
43517
|
+
return;
|
|
43518
|
+
}
|
|
43519
|
+
const child = spawn(executable.command, [
|
|
43520
|
+
...executable.argsPrefix,
|
|
42853
43521
|
...args,
|
|
42854
43522
|
"--session",
|
|
42855
43523
|
sessionId
|
|
@@ -42900,7 +43568,10 @@ function spawnAgentBrowser({ args, sessionId, cwd, signal }) {
|
|
|
42900
43568
|
});
|
|
42901
43569
|
});
|
|
42902
43570
|
}
|
|
42903
|
-
|
|
43571
|
+
function formatErrorMessage(error) {
|
|
43572
|
+
return error instanceof Error ? error.message : String(error);
|
|
43573
|
+
}
|
|
43574
|
+
async function runPlannedBrowserCommands({ commands, runDir, sessionId, cwd, headed, agentBrowserExecutableResolver, signal }) {
|
|
42904
43575
|
const stdout = [];
|
|
42905
43576
|
const stderr = [];
|
|
42906
43577
|
for (const command of commands) {
|
|
@@ -42916,6 +43587,7 @@ async function runPlannedBrowserCommands({ commands, runDir, sessionId, cwd, hea
|
|
|
42916
43587
|
args,
|
|
42917
43588
|
sessionId,
|
|
42918
43589
|
cwd,
|
|
43590
|
+
agentBrowserExecutableResolver,
|
|
42919
43591
|
signal
|
|
42920
43592
|
});
|
|
42921
43593
|
stdout.push(result.stdout);
|
|
@@ -44378,423 +45050,6 @@ function truncateForLine(text) {
|
|
|
44378
45050
|
function truncateForFile(text) {
|
|
44379
45051
|
return text.length <= 4e3 ? text : `${text.slice(0, 3997)}...`;
|
|
44380
45052
|
}
|
|
44381
|
-
//#endregion
|
|
44382
|
-
//#region src/pipeline/quire-model-provider.ts
|
|
44383
|
-
const QUIRE_MODEL_PROVIDER = "quire";
|
|
44384
|
-
const QUIRE_MODEL_ID = "gpt-5.1";
|
|
44385
|
-
const PI_CODEX_MODEL_PROVIDER = "openai-codex";
|
|
44386
|
-
const PI_CODEX_MODEL_ID = "gpt-5.5";
|
|
44387
|
-
const QUIRE_MODEL_API = "quire-chat-completions";
|
|
44388
|
-
const QUIRE_RUNTIME_AUTH_ENV = "QUIRE_RUNTIME_AUTH_TOKEN";
|
|
44389
|
-
const QUIRE_MODEL_AUTH_PATH_ENV = "QUIRE_MODEL_AUTH_PATH";
|
|
44390
|
-
const openAiCompletionCompat = {
|
|
44391
|
-
supportsStore: false,
|
|
44392
|
-
supportsDeveloperRole: false,
|
|
44393
|
-
supportsReasoningEffort: true,
|
|
44394
|
-
supportsUsageInStreaming: false,
|
|
44395
|
-
maxTokensField: "max_completion_tokens",
|
|
44396
|
-
requiresToolResultName: false,
|
|
44397
|
-
requiresAssistantAfterToolResult: false,
|
|
44398
|
-
requiresThinkingAsText: false,
|
|
44399
|
-
requiresReasoningContentOnAssistantMessages: false,
|
|
44400
|
-
thinkingFormat: "openai",
|
|
44401
|
-
zaiToolStream: false,
|
|
44402
|
-
supportsStrictMode: true,
|
|
44403
|
-
sendSessionAffinityHeaders: false,
|
|
44404
|
-
supportsLongCacheRetention: true
|
|
44405
|
-
};
|
|
44406
|
-
async function createQuireModelSessionDependencies({ runId, store = authStore, fetchFn }) {
|
|
44407
|
-
const credentials = await readValidatedQuireCredentials({
|
|
44408
|
-
store,
|
|
44409
|
-
fetchFn
|
|
44410
|
-
});
|
|
44411
|
-
const authStorage = AuthStorage.inMemory();
|
|
44412
|
-
authStorage.setRuntimeApiKey(QUIRE_MODEL_PROVIDER, credentials.accessToken);
|
|
44413
|
-
const modelRegistry = ModelRegistry.inMemory(authStorage);
|
|
44414
|
-
modelRegistry.registerProvider(QUIRE_MODEL_PROVIDER, {
|
|
44415
|
-
name: "Quire Credits",
|
|
44416
|
-
baseUrl: credentials.apiBaseUrl,
|
|
44417
|
-
apiKey: QUIRE_RUNTIME_AUTH_ENV,
|
|
44418
|
-
api: QUIRE_MODEL_API,
|
|
44419
|
-
models: [quireModelDefinition()],
|
|
44420
|
-
streamSimple: createQuireCreditsStream({
|
|
44421
|
-
apiBaseUrl: credentials.apiBaseUrl,
|
|
44422
|
-
runId,
|
|
44423
|
-
fetchFn
|
|
44424
|
-
})
|
|
44425
|
-
});
|
|
44426
|
-
const model = modelRegistry.find(QUIRE_MODEL_PROVIDER, QUIRE_MODEL_ID);
|
|
44427
|
-
if (!model) throw new Error(`Quire model not found: ${QUIRE_MODEL_PROVIDER}/${QUIRE_MODEL_ID}`);
|
|
44428
|
-
return {
|
|
44429
|
-
authStorage,
|
|
44430
|
-
modelRegistry,
|
|
44431
|
-
model,
|
|
44432
|
-
source: "quire_credits"
|
|
44433
|
-
};
|
|
44434
|
-
}
|
|
44435
|
-
async function createInvestigationModelSessionDependencies({ runId, store = authStore, fetchFn, localAuthStorage }) {
|
|
44436
|
-
const localCodex = await createLocalCodexSessionDependencies(localAuthStorage);
|
|
44437
|
-
if (localCodex) return localCodex;
|
|
44438
|
-
return createQuireModelSessionDependencies({
|
|
44439
|
-
runId,
|
|
44440
|
-
store,
|
|
44441
|
-
fetchFn
|
|
44442
|
-
});
|
|
44443
|
-
}
|
|
44444
|
-
async function createLocalCodexSessionDependencies(localAuthStorage) {
|
|
44445
|
-
const authStorages = localAuthStorage === void 0 ? [AuthStorage.create(readQuireModelAuthPath()), AuthStorage.create()] : [localAuthStorage];
|
|
44446
|
-
for (const authStorage of authStorages) {
|
|
44447
|
-
const modelRegistry = ModelRegistry.create(authStorage);
|
|
44448
|
-
const model = modelRegistry.find(PI_CODEX_MODEL_PROVIDER, PI_CODEX_MODEL_ID);
|
|
44449
|
-
if (!model || !modelRegistry.hasConfiguredAuth(model)) continue;
|
|
44450
|
-
const auth = await modelRegistry.getApiKeyAndHeaders(model);
|
|
44451
|
-
if (!auth.ok || !auth.apiKey && !auth.headers) continue;
|
|
44452
|
-
return {
|
|
44453
|
-
authStorage,
|
|
44454
|
-
modelRegistry,
|
|
44455
|
-
model,
|
|
44456
|
-
source: "local_openai_codex"
|
|
44457
|
-
};
|
|
44458
|
-
}
|
|
44459
|
-
return null;
|
|
44460
|
-
}
|
|
44461
|
-
function readQuireModelAuthPath() {
|
|
44462
|
-
const envPath = process.env[QUIRE_MODEL_AUTH_PATH_ENV]?.trim();
|
|
44463
|
-
return envPath && envPath.length > 0 ? envPath : join(homedir(), ".quire", "model-auth.json");
|
|
44464
|
-
}
|
|
44465
|
-
function quireModelDefinition() {
|
|
44466
|
-
return {
|
|
44467
|
-
id: QUIRE_MODEL_ID,
|
|
44468
|
-
name: "Quire Credits GPT-5.1",
|
|
44469
|
-
api: QUIRE_MODEL_API,
|
|
44470
|
-
reasoning: true,
|
|
44471
|
-
thinkingLevelMap: {
|
|
44472
|
-
off: null,
|
|
44473
|
-
xhigh: "high"
|
|
44474
|
-
},
|
|
44475
|
-
input: ["text"],
|
|
44476
|
-
cost: {
|
|
44477
|
-
input: 1.25,
|
|
44478
|
-
output: 10,
|
|
44479
|
-
cacheRead: .125,
|
|
44480
|
-
cacheWrite: 0
|
|
44481
|
-
},
|
|
44482
|
-
contextWindow: 128e3,
|
|
44483
|
-
maxTokens: 32e3
|
|
44484
|
-
};
|
|
44485
|
-
}
|
|
44486
|
-
function createQuireCreditsStream(options) {
|
|
44487
|
-
return (model, context, streamOptions) => {
|
|
44488
|
-
const stream = createAssistantMessageEventStream();
|
|
44489
|
-
(async () => {
|
|
44490
|
-
const output = createEmptyAssistantMessage(model);
|
|
44491
|
-
try {
|
|
44492
|
-
const accessToken = streamOptions?.apiKey;
|
|
44493
|
-
if (!accessToken) throw new CliError$1("Not logged in. Run `quire login` before `quire investigate` so Quire Credits can be checked.", ExitCode.AuthFailure);
|
|
44494
|
-
stream.push({
|
|
44495
|
-
type: "start",
|
|
44496
|
-
partial: output
|
|
44497
|
-
});
|
|
44498
|
-
applyBrokerResponseToStream(stream, output, model, await requestBrokerChatCompletion({
|
|
44499
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
44500
|
-
accessToken,
|
|
44501
|
-
runId: options.runId,
|
|
44502
|
-
model,
|
|
44503
|
-
context,
|
|
44504
|
-
streamOptions,
|
|
44505
|
-
fetchFn: options.fetchFn
|
|
44506
|
-
}));
|
|
44507
|
-
} catch (error) {
|
|
44508
|
-
output.stopReason = streamOptions?.signal?.aborted ? "aborted" : "error";
|
|
44509
|
-
output.errorMessage = error instanceof Error ? error.message : String(error);
|
|
44510
|
-
stream.push({
|
|
44511
|
-
type: "error",
|
|
44512
|
-
reason: output.stopReason,
|
|
44513
|
-
error: output
|
|
44514
|
-
});
|
|
44515
|
-
stream.end();
|
|
44516
|
-
}
|
|
44517
|
-
})();
|
|
44518
|
-
return stream;
|
|
44519
|
-
};
|
|
44520
|
-
}
|
|
44521
|
-
async function readValidatedQuireCredentials(options) {
|
|
44522
|
-
const credentials = await options.store.get();
|
|
44523
|
-
if (!credentials) throw new CliError$1("Not logged in. Run `quire login` before `quire investigate` so Quire Credits can be checked.", ExitCode.AuthFailure);
|
|
44524
|
-
const sessionLookup = await fetchCurrentSession({
|
|
44525
|
-
apiBaseUrl: credentials.apiBaseUrl,
|
|
44526
|
-
accessToken: credentials.accessToken,
|
|
44527
|
-
fetchFn: options.fetchFn
|
|
44528
|
-
});
|
|
44529
|
-
if (!sessionLookup.data) {
|
|
44530
|
-
await options.store.clear();
|
|
44531
|
-
throw new CliError$1("Stored Quire credentials are no longer valid. Run `quire login`.", ExitCode.AuthFailure);
|
|
44532
|
-
}
|
|
44533
|
-
if (!sessionLookup.refreshedAccessToken) return credentials;
|
|
44534
|
-
const refreshedCredentials = updateStoredCredentials(credentials, {
|
|
44535
|
-
accessToken: sessionLookup.refreshedAccessToken,
|
|
44536
|
-
expiresAt: sessionLookup.data.session.expiresAt,
|
|
44537
|
-
user: sessionLookup.data.user
|
|
44538
|
-
});
|
|
44539
|
-
await options.store.set(refreshedCredentials);
|
|
44540
|
-
return refreshedCredentials;
|
|
44541
|
-
}
|
|
44542
|
-
async function requestBrokerChatCompletion(input) {
|
|
44543
|
-
const response = await (input.fetchFn ?? fetch)(new URL("/api/model-broker/chat-completions", input.apiBaseUrl).toString(), {
|
|
44544
|
-
method: "POST",
|
|
44545
|
-
headers: {
|
|
44546
|
-
Accept: "application/json",
|
|
44547
|
-
Authorization: `Bearer ${input.accessToken}`,
|
|
44548
|
-
"Content-Type": "application/json",
|
|
44549
|
-
"User-Agent": "quire-cli"
|
|
44550
|
-
},
|
|
44551
|
-
signal: input.streamOptions?.signal,
|
|
44552
|
-
body: JSON.stringify({
|
|
44553
|
-
model: input.model.id,
|
|
44554
|
-
messages: toBrokerMessages(input.model, input.context),
|
|
44555
|
-
runId: input.runId,
|
|
44556
|
-
stream: false,
|
|
44557
|
-
agentContext: {
|
|
44558
|
-
messages: [],
|
|
44559
|
-
tools: toBrokerTools(input.context.tools)
|
|
44560
|
-
},
|
|
44561
|
-
agentOptions: {
|
|
44562
|
-
reasoning: normalizeReasoning(input.streamOptions?.reasoning),
|
|
44563
|
-
sessionId: input.streamOptions?.sessionId ?? null
|
|
44564
|
-
}
|
|
44565
|
-
})
|
|
44566
|
-
});
|
|
44567
|
-
const body = await readJsonBody(response);
|
|
44568
|
-
if (!response.ok || body?.status !== "succeeded") throw brokerResponseError(response, body);
|
|
44569
|
-
const rawResponse = body.data?.response;
|
|
44570
|
-
if (!rawResponse || typeof rawResponse !== "object" || Array.isArray(rawResponse)) throw new Error("Quire model broker returned an invalid model response.");
|
|
44571
|
-
return rawResponse;
|
|
44572
|
-
}
|
|
44573
|
-
function toBrokerMessages(model, context) {
|
|
44574
|
-
return convertMessages(model, context, openAiCompletionCompat).map((message) => {
|
|
44575
|
-
const record = message;
|
|
44576
|
-
const role = normalizeRole(record.role);
|
|
44577
|
-
const toolCalls = parseBrokerToolCalls(record.tool_calls);
|
|
44578
|
-
return {
|
|
44579
|
-
role,
|
|
44580
|
-
content: normalizeMessageContent(record.content),
|
|
44581
|
-
...typeof record.name === "string" ? { name: record.name } : {},
|
|
44582
|
-
...typeof record.tool_call_id === "string" ? { tool_call_id: record.tool_call_id } : {},
|
|
44583
|
-
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
44584
|
-
};
|
|
44585
|
-
});
|
|
44586
|
-
}
|
|
44587
|
-
function toBrokerTools(tools) {
|
|
44588
|
-
return (tools ?? []).map((tool) => ({
|
|
44589
|
-
type: "function",
|
|
44590
|
-
function: {
|
|
44591
|
-
name: tool.name,
|
|
44592
|
-
description: tool.description,
|
|
44593
|
-
parameters: tool.parameters,
|
|
44594
|
-
strict: false
|
|
44595
|
-
}
|
|
44596
|
-
}));
|
|
44597
|
-
}
|
|
44598
|
-
function applyBrokerResponseToStream(stream, output, model, response) {
|
|
44599
|
-
output.responseId = typeof response.id === "string" ? response.id : void 0;
|
|
44600
|
-
output.responseModel = typeof response.model === "string" ? response.model : void 0;
|
|
44601
|
-
output.usage = readUsage(response.usage, model);
|
|
44602
|
-
const choice = response.choices?.[0];
|
|
44603
|
-
const message = choice?.message;
|
|
44604
|
-
const content = typeof message?.content === "string" ? message.content : "";
|
|
44605
|
-
if (content.length > 0) {
|
|
44606
|
-
const textBlock = {
|
|
44607
|
-
type: "text",
|
|
44608
|
-
text: content
|
|
44609
|
-
};
|
|
44610
|
-
output.content.push(textBlock);
|
|
44611
|
-
const contentIndex = output.content.length - 1;
|
|
44612
|
-
stream.push({
|
|
44613
|
-
type: "text_start",
|
|
44614
|
-
contentIndex,
|
|
44615
|
-
partial: output
|
|
44616
|
-
});
|
|
44617
|
-
stream.push({
|
|
44618
|
-
type: "text_delta",
|
|
44619
|
-
contentIndex,
|
|
44620
|
-
delta: content,
|
|
44621
|
-
partial: output
|
|
44622
|
-
});
|
|
44623
|
-
stream.push({
|
|
44624
|
-
type: "text_end",
|
|
44625
|
-
contentIndex,
|
|
44626
|
-
content,
|
|
44627
|
-
partial: output
|
|
44628
|
-
});
|
|
44629
|
-
}
|
|
44630
|
-
const toolCalls = parseBrokerToolCalls(message?.tool_calls);
|
|
44631
|
-
for (const toolCall of toolCalls) {
|
|
44632
|
-
const block = {
|
|
44633
|
-
type: "toolCall",
|
|
44634
|
-
id: toolCall.id,
|
|
44635
|
-
name: toolCall.function.name,
|
|
44636
|
-
arguments: parseToolCallArguments(toolCall.function.arguments)
|
|
44637
|
-
};
|
|
44638
|
-
output.content.push(block);
|
|
44639
|
-
const contentIndex = output.content.length - 1;
|
|
44640
|
-
stream.push({
|
|
44641
|
-
type: "toolcall_start",
|
|
44642
|
-
contentIndex,
|
|
44643
|
-
partial: output
|
|
44644
|
-
});
|
|
44645
|
-
stream.push({
|
|
44646
|
-
type: "toolcall_delta",
|
|
44647
|
-
contentIndex,
|
|
44648
|
-
delta: toolCall.function.arguments,
|
|
44649
|
-
partial: output
|
|
44650
|
-
});
|
|
44651
|
-
stream.push({
|
|
44652
|
-
type: "toolcall_end",
|
|
44653
|
-
contentIndex,
|
|
44654
|
-
toolCall: block,
|
|
44655
|
-
partial: output
|
|
44656
|
-
});
|
|
44657
|
-
}
|
|
44658
|
-
output.stopReason = mapStopReason(choice?.finish_reason, toolCalls.length > 0);
|
|
44659
|
-
stream.push({
|
|
44660
|
-
type: "done",
|
|
44661
|
-
reason: output.stopReason,
|
|
44662
|
-
message: output
|
|
44663
|
-
});
|
|
44664
|
-
stream.end();
|
|
44665
|
-
}
|
|
44666
|
-
function createEmptyAssistantMessage(model) {
|
|
44667
|
-
return {
|
|
44668
|
-
role: "assistant",
|
|
44669
|
-
content: [],
|
|
44670
|
-
api: model.api,
|
|
44671
|
-
provider: model.provider,
|
|
44672
|
-
model: model.id,
|
|
44673
|
-
usage: emptyUsage(),
|
|
44674
|
-
stopReason: "stop",
|
|
44675
|
-
timestamp: Date.now()
|
|
44676
|
-
};
|
|
44677
|
-
}
|
|
44678
|
-
function emptyUsage() {
|
|
44679
|
-
return {
|
|
44680
|
-
input: 0,
|
|
44681
|
-
output: 0,
|
|
44682
|
-
cacheRead: 0,
|
|
44683
|
-
cacheWrite: 0,
|
|
44684
|
-
totalTokens: 0,
|
|
44685
|
-
cost: {
|
|
44686
|
-
input: 0,
|
|
44687
|
-
output: 0,
|
|
44688
|
-
cacheRead: 0,
|
|
44689
|
-
cacheWrite: 0,
|
|
44690
|
-
total: 0
|
|
44691
|
-
}
|
|
44692
|
-
};
|
|
44693
|
-
}
|
|
44694
|
-
function readUsage(rawUsage, model) {
|
|
44695
|
-
const input = readNumber(rawUsage?.prompt_tokens ?? rawUsage?.promptTokens) ?? 0;
|
|
44696
|
-
const output = readNumber(rawUsage?.completion_tokens ?? rawUsage?.completionTokens) ?? 0;
|
|
44697
|
-
const usage = {
|
|
44698
|
-
input,
|
|
44699
|
-
output,
|
|
44700
|
-
cacheRead: 0,
|
|
44701
|
-
cacheWrite: 0,
|
|
44702
|
-
totalTokens: readNumber(rawUsage?.total_tokens ?? rawUsage?.totalTokens) ?? input + output,
|
|
44703
|
-
cost: {
|
|
44704
|
-
input: 0,
|
|
44705
|
-
output: 0,
|
|
44706
|
-
cacheRead: 0,
|
|
44707
|
-
cacheWrite: 0,
|
|
44708
|
-
total: 0
|
|
44709
|
-
}
|
|
44710
|
-
};
|
|
44711
|
-
calculateCost(model, usage);
|
|
44712
|
-
return usage;
|
|
44713
|
-
}
|
|
44714
|
-
function mapStopReason(finishReason, hasToolCalls) {
|
|
44715
|
-
if (finishReason === "length") return "length";
|
|
44716
|
-
if (hasToolCalls || finishReason === "tool_calls" || finishReason === "function_call") return "toolUse";
|
|
44717
|
-
return "stop";
|
|
44718
|
-
}
|
|
44719
|
-
function normalizeRole(value) {
|
|
44720
|
-
if (value === "developer") return "system";
|
|
44721
|
-
if (value === "system" || value === "user" || value === "assistant" || value === "tool") return value;
|
|
44722
|
-
throw new Error(`Unsupported broker message role: ${String(value)}`);
|
|
44723
|
-
}
|
|
44724
|
-
function normalizeMessageContent(value) {
|
|
44725
|
-
if (typeof value === "string") return value;
|
|
44726
|
-
if (value === null || value === void 0) return "";
|
|
44727
|
-
if (Array.isArray(value)) {
|
|
44728
|
-
const text = value.map((part) => {
|
|
44729
|
-
if (!part || typeof part !== "object" || Array.isArray(part)) return "";
|
|
44730
|
-
const record = part;
|
|
44731
|
-
return record.type === "text" && typeof record.text === "string" ? record.text : "[non-text content omitted]";
|
|
44732
|
-
}).filter((part) => part.length > 0).join("\n");
|
|
44733
|
-
return text.length > 0 ? text : "[non-text content omitted]";
|
|
44734
|
-
}
|
|
44735
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
44736
|
-
return "[non-text content omitted]";
|
|
44737
|
-
}
|
|
44738
|
-
function parseBrokerToolCalls(value) {
|
|
44739
|
-
if (!Array.isArray(value)) return [];
|
|
44740
|
-
return value.flatMap((toolCall, index) => {
|
|
44741
|
-
if (!toolCall || typeof toolCall !== "object" || Array.isArray(toolCall)) return [];
|
|
44742
|
-
const record = toolCall;
|
|
44743
|
-
const fn = record.function;
|
|
44744
|
-
if (!fn || typeof fn !== "object" || Array.isArray(fn)) return [];
|
|
44745
|
-
const functionRecord = fn;
|
|
44746
|
-
const name = typeof functionRecord.name === "string" ? functionRecord.name : "";
|
|
44747
|
-
if (!name) return [];
|
|
44748
|
-
return [{
|
|
44749
|
-
id: typeof record.id === "string" ? record.id : `call_${index}`,
|
|
44750
|
-
type: "function",
|
|
44751
|
-
function: {
|
|
44752
|
-
name,
|
|
44753
|
-
arguments: typeof functionRecord.arguments === "string" ? functionRecord.arguments : "{}"
|
|
44754
|
-
}
|
|
44755
|
-
}];
|
|
44756
|
-
});
|
|
44757
|
-
}
|
|
44758
|
-
function parseToolCallArguments(value) {
|
|
44759
|
-
try {
|
|
44760
|
-
const parsed = JSON.parse(value);
|
|
44761
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
44762
|
-
} catch {
|
|
44763
|
-
return {};
|
|
44764
|
-
}
|
|
44765
|
-
}
|
|
44766
|
-
async function readJsonBody(response) {
|
|
44767
|
-
const text = await response.text();
|
|
44768
|
-
if (!text) return null;
|
|
44769
|
-
try {
|
|
44770
|
-
return JSON.parse(text);
|
|
44771
|
-
} catch {
|
|
44772
|
-
return text;
|
|
44773
|
-
}
|
|
44774
|
-
}
|
|
44775
|
-
function brokerResponseError(response, body) {
|
|
44776
|
-
const code = body?.error?.code ?? `http_${response.status}`;
|
|
44777
|
-
const message = body?.error?.message ?? `Quire model broker request failed with HTTP ${response.status}`;
|
|
44778
|
-
const action = body?.error?.nextAction;
|
|
44779
|
-
const billingDetail = formatBrokerBillingDetail(body);
|
|
44780
|
-
return new Error([
|
|
44781
|
-
`Quire model broker request failed (${code}): ${message}`,
|
|
44782
|
-
billingDetail,
|
|
44783
|
-
action === void 0 ? void 0 : `Next action: ${action}.`
|
|
44784
|
-
].filter((part) => part !== void 0 && part.length > 0).join(" "));
|
|
44785
|
-
}
|
|
44786
|
-
function normalizeReasoning(reasoning) {
|
|
44787
|
-
return reasoning === "minimal" || reasoning === "low" || reasoning === "medium" || reasoning === "high" || reasoning === "xhigh" ? reasoning : void 0;
|
|
44788
|
-
}
|
|
44789
|
-
function readNumber(value) {
|
|
44790
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
44791
|
-
}
|
|
44792
|
-
function formatBrokerBillingDetail(body) {
|
|
44793
|
-
const requiredBalance = readNumber(body?.metadata?.wallet?.requiredBalance) ?? readNumber(body?.metadata?.billing?.wallet?.requiredBalance) ?? readNumber(body?.metadata?.billing?.wallet?.estimatedTotalTokens);
|
|
44794
|
-
const remainingBalance = readNumber(body?.metadata?.wallet?.balance?.remaining);
|
|
44795
|
-
if (requiredBalance === null && remainingBalance === null) return;
|
|
44796
|
-
return `Wallet: ${[requiredBalance === null ? void 0 : `required=${requiredBalance}`, remainingBalance === null ? void 0 : `remaining=${remainingBalance}`].filter((part) => part !== void 0).join(", ")}.`;
|
|
44797
|
-
}
|
|
44798
45053
|
const EXPLORE_THINKING_LEVEL = "xhigh";
|
|
44799
45054
|
const EXPLORE_CODE_TOOL_NAMES = [
|
|
44800
45055
|
"read",
|
|
@@ -45431,6 +45686,7 @@ function syncConfigFromCredentials(credentials, options = {}) {
|
|
|
45431
45686
|
return {
|
|
45432
45687
|
apiBaseUrl: credentials.apiBaseUrl,
|
|
45433
45688
|
accessToken: credentials.accessToken,
|
|
45689
|
+
tokenType: credentials.tokenType,
|
|
45434
45690
|
artifactMode: options.artifactMode ?? "evidence"
|
|
45435
45691
|
};
|
|
45436
45692
|
}
|
|
@@ -45574,7 +45830,7 @@ var InvestigationSyncSession = class {
|
|
|
45574
45830
|
headers: {
|
|
45575
45831
|
Accept: "application/json",
|
|
45576
45832
|
"Content-Type": "application/json",
|
|
45577
|
-
|
|
45833
|
+
...authHeaders(this.config),
|
|
45578
45834
|
"User-Agent": "quire-cli",
|
|
45579
45835
|
...Object.fromEntries(new Headers(init.headers).entries())
|
|
45580
45836
|
}
|
|
@@ -45612,6 +45868,7 @@ async function syncExistingRun(options) {
|
|
|
45612
45868
|
await new InvestigationSyncSession(options.runDir, {
|
|
45613
45869
|
apiBaseUrl: options.credentials.apiBaseUrl,
|
|
45614
45870
|
accessToken: options.credentials.accessToken,
|
|
45871
|
+
tokenType: options.credentials.tokenType,
|
|
45615
45872
|
artifactMode: options.artifactMode ?? "evidence",
|
|
45616
45873
|
fetchFn: options.fetchFn
|
|
45617
45874
|
}).syncFromDisk();
|
|
@@ -46172,7 +46429,7 @@ async function runInvestigationWorker(requestPath) {
|
|
|
46172
46429
|
pid: process.pid
|
|
46173
46430
|
});
|
|
46174
46431
|
try {
|
|
46175
|
-
const credentials = await authStore
|
|
46432
|
+
const credentials = await resolveAuthCredentials({ store: authStore });
|
|
46176
46433
|
const result = await runLocalInvestigation({
|
|
46177
46434
|
cwd: request.cwd,
|
|
46178
46435
|
query: request.query,
|
|
@@ -46503,7 +46760,7 @@ async function listRuns(options = {}) {
|
|
|
46503
46760
|
}
|
|
46504
46761
|
async function syncRun(run, options = {}) {
|
|
46505
46762
|
const stdout = options.io?.stdout ?? process.stdout;
|
|
46506
|
-
const credentials = await (options.store ?? authStore)
|
|
46763
|
+
const credentials = await resolveAuthCredentials({ store: options.store ?? authStore });
|
|
46507
46764
|
if (credentials === null) throw new CliError$1("Run `quire login` before syncing runs.", ExitCode.AuthFailure);
|
|
46508
46765
|
const status = readFreshRunStatus(resolveRunPath(run, options));
|
|
46509
46766
|
await syncExistingRun({
|
|
@@ -46629,7 +46886,7 @@ async function runInvestigate(options) {
|
|
|
46629
46886
|
const stdout = options.io?.stdout ?? process.stdout;
|
|
46630
46887
|
const stderr = options.io?.stderr ?? process.stderr;
|
|
46631
46888
|
const stdinText = options.stdin === true ? await readAll(options.input ?? process.stdin) : void 0;
|
|
46632
|
-
const credentials = await (options.store ?? authStore)
|
|
46889
|
+
const credentials = await resolveAuthCredentials({ store: options.store ?? authStore });
|
|
46633
46890
|
if (options.foreground === true) {
|
|
46634
46891
|
const result = await (options.runner ?? runLocalInvestigation)({
|
|
46635
46892
|
query: options.query,
|
|
@@ -46754,43 +47011,6 @@ function defaultSleep(ms) {
|
|
|
46754
47011
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
46755
47012
|
}
|
|
46756
47013
|
//#endregion
|
|
46757
|
-
//#region src/auth/open-browser.ts
|
|
46758
|
-
async function openBrowser(url) {
|
|
46759
|
-
const command = browserCommand(url);
|
|
46760
|
-
if (command === null) return false;
|
|
46761
|
-
return new Promise((resolve) => {
|
|
46762
|
-
const child = spawn(command.command, command.args, {
|
|
46763
|
-
detached: true,
|
|
46764
|
-
stdio: "ignore",
|
|
46765
|
-
shell: false
|
|
46766
|
-
});
|
|
46767
|
-
child.once("error", () => resolve(false));
|
|
46768
|
-
child.once("spawn", () => {
|
|
46769
|
-
child.unref();
|
|
46770
|
-
resolve(true);
|
|
46771
|
-
});
|
|
46772
|
-
});
|
|
46773
|
-
}
|
|
46774
|
-
function browserCommand(url) {
|
|
46775
|
-
if (process.platform === "darwin") return {
|
|
46776
|
-
command: "open",
|
|
46777
|
-
args: [url]
|
|
46778
|
-
};
|
|
46779
|
-
if (process.platform === "win32") return {
|
|
46780
|
-
command: "cmd",
|
|
46781
|
-
args: [
|
|
46782
|
-
"/c",
|
|
46783
|
-
"start",
|
|
46784
|
-
"",
|
|
46785
|
-
url
|
|
46786
|
-
]
|
|
46787
|
-
};
|
|
46788
|
-
return {
|
|
46789
|
-
command: "xdg-open",
|
|
46790
|
-
args: [url]
|
|
46791
|
-
};
|
|
46792
|
-
}
|
|
46793
|
-
//#endregion
|
|
46794
47014
|
//#region src/commands/login.ts
|
|
46795
47015
|
const loginCommand = defineCommand({
|
|
46796
47016
|
meta: {
|
|
@@ -46843,6 +47063,7 @@ async function runLogin(options) {
|
|
|
46843
47063
|
const sessionLookup = await (options.getSession?.(token.access_token) ?? fetchCurrentSession({
|
|
46844
47064
|
apiBaseUrl: options.apiBaseUrl,
|
|
46845
47065
|
accessToken: token.access_token,
|
|
47066
|
+
tokenType: token.token_type,
|
|
46846
47067
|
fetchFn: options.fetchFn
|
|
46847
47068
|
}));
|
|
46848
47069
|
const session = sessionLookup.data;
|
|
@@ -46946,14 +47167,38 @@ const whoamiCommand = defineCommand({
|
|
|
46946
47167
|
async function runWhoami(options) {
|
|
46947
47168
|
const store = options.store ?? authStore;
|
|
46948
47169
|
const stdout = options.io?.stdout ?? process.stdout;
|
|
46949
|
-
const credentials = await store
|
|
47170
|
+
const credentials = await resolveAuthCredentials({ store });
|
|
46950
47171
|
if (credentials === null) {
|
|
46951
47172
|
if (options.json === true) writeJson(stdout, { authenticated: false });
|
|
46952
47173
|
throw new CliError$1("Not logged in. Run `quire login`.", ExitCode.AuthFailure);
|
|
46953
47174
|
}
|
|
47175
|
+
if (credentials.tokenType === "QuireApiKey") {
|
|
47176
|
+
const modelSourceBroker = await readModelSourceBrokerStatus({
|
|
47177
|
+
accessToken: credentials.accessToken,
|
|
47178
|
+
tokenType: credentials.tokenType,
|
|
47179
|
+
apiBaseUrl: credentials.apiBaseUrl,
|
|
47180
|
+
fetchFn: options.fetchFn,
|
|
47181
|
+
getModelSourceBrokerStatus: options.getModelSourceBrokerStatus
|
|
47182
|
+
});
|
|
47183
|
+
const actor = modelSourceBroker?.actor ?? null;
|
|
47184
|
+
if (options.json === true) {
|
|
47185
|
+
writeJson(stdout, {
|
|
47186
|
+
authenticated: true,
|
|
47187
|
+
authMethod: "api_token",
|
|
47188
|
+
apiBaseUrl: credentials.apiBaseUrl,
|
|
47189
|
+
actor,
|
|
47190
|
+
modelSourceBroker
|
|
47191
|
+
});
|
|
47192
|
+
return;
|
|
47193
|
+
}
|
|
47194
|
+
writeLine(stdout, `Authenticated with API token for ${formatActor(actor)}.`);
|
|
47195
|
+
writeLine(stdout, formatModelSourceBrokerStatus(modelSourceBroker));
|
|
47196
|
+
return;
|
|
47197
|
+
}
|
|
46954
47198
|
const sessionLookup = await (options.getSession?.(credentials.accessToken) ?? fetchCurrentSession({
|
|
46955
47199
|
apiBaseUrl: credentials.apiBaseUrl,
|
|
46956
47200
|
accessToken: credentials.accessToken,
|
|
47201
|
+
tokenType: credentials.tokenType,
|
|
46957
47202
|
fetchFn: options.fetchFn
|
|
46958
47203
|
}));
|
|
46959
47204
|
const session = sessionLookup.data;
|
|
@@ -46969,6 +47214,7 @@ async function runWhoami(options) {
|
|
|
46969
47214
|
await store.set(refreshedCredentials);
|
|
46970
47215
|
const modelSourceBroker = await readModelSourceBrokerStatus({
|
|
46971
47216
|
accessToken: refreshedCredentials.accessToken,
|
|
47217
|
+
tokenType: refreshedCredentials.tokenType,
|
|
46972
47218
|
apiBaseUrl: refreshedCredentials.apiBaseUrl,
|
|
46973
47219
|
fetchFn: options.fetchFn,
|
|
46974
47220
|
getModelSourceBrokerStatus: options.getModelSourceBrokerStatus
|
|
@@ -46991,12 +47237,16 @@ async function readModelSourceBrokerStatus(options) {
|
|
|
46991
47237
|
return await (options.getModelSourceBrokerStatus?.(options.accessToken, options.apiBaseUrl) ?? fetchModelSourceBrokerStatus({
|
|
46992
47238
|
apiBaseUrl: options.apiBaseUrl,
|
|
46993
47239
|
accessToken: options.accessToken,
|
|
47240
|
+
tokenType: options.tokenType,
|
|
46994
47241
|
fetchFn: options.fetchFn
|
|
46995
47242
|
}));
|
|
46996
47243
|
} catch {
|
|
46997
47244
|
return null;
|
|
46998
47245
|
}
|
|
46999
47246
|
}
|
|
47247
|
+
function formatActor(actor) {
|
|
47248
|
+
return actor?.environmentName ?? actor?.triggerSource ?? "remote agent environment";
|
|
47249
|
+
}
|
|
47000
47250
|
function formatUser(user) {
|
|
47001
47251
|
if (user.name && user.email && user.name !== user.email) return `${user.name} <${user.email}>`;
|
|
47002
47252
|
return user.email ?? user.name ?? user.id;
|
|
@@ -47011,13 +47261,14 @@ function formatModelSourceBrokerStatus(status) {
|
|
|
47011
47261
|
}
|
|
47012
47262
|
//#endregion
|
|
47013
47263
|
//#region package.json
|
|
47014
|
-
var version$1 = "0.0.
|
|
47264
|
+
var version$1 = "0.0.3";
|
|
47015
47265
|
//#endregion
|
|
47016
47266
|
//#region src/cli.ts
|
|
47017
47267
|
const subCommands = {
|
|
47018
47268
|
login: loginCommand,
|
|
47019
47269
|
logout: logoutCommand,
|
|
47020
47270
|
whoami: whoamiCommand,
|
|
47271
|
+
connect: connectCommand,
|
|
47021
47272
|
doctor: doctorCommand,
|
|
47022
47273
|
env: envCommand,
|
|
47023
47274
|
investigate: investigateCommand,
|
|
@@ -47061,12 +47312,28 @@ function isHelpRequest(rawArgs) {
|
|
|
47061
47312
|
return rawArgs.some((arg) => arg === "--help" || arg === "-h");
|
|
47062
47313
|
}
|
|
47063
47314
|
async function renderHelp(rawArgs) {
|
|
47064
|
-
const
|
|
47065
|
-
|
|
47066
|
-
|
|
47315
|
+
const { command, parent } = resolveHelpCommand(rawArgs);
|
|
47316
|
+
return renderUsage(command, parent);
|
|
47317
|
+
}
|
|
47318
|
+
function resolveHelpCommand(rawArgs) {
|
|
47319
|
+
let command = cli;
|
|
47320
|
+
let parent;
|
|
47321
|
+
for (const arg of rawArgs) {
|
|
47322
|
+
if (arg.startsWith("-")) continue;
|
|
47323
|
+
const next = readSubCommand(command, arg);
|
|
47324
|
+
if (next === void 0) break;
|
|
47325
|
+
parent = command;
|
|
47326
|
+
command = next;
|
|
47327
|
+
}
|
|
47328
|
+
return parent === void 0 ? { command } : {
|
|
47329
|
+
command,
|
|
47330
|
+
parent
|
|
47331
|
+
};
|
|
47067
47332
|
}
|
|
47068
|
-
function
|
|
47069
|
-
|
|
47333
|
+
function readSubCommand(command, name) {
|
|
47334
|
+
const subCommandMap = command.subCommands;
|
|
47335
|
+
if (subCommandMap === void 0 || !Object.hasOwn(subCommandMap, name)) return;
|
|
47336
|
+
return subCommandMap[name];
|
|
47070
47337
|
}
|
|
47071
47338
|
async function runWorkerCommand(rawArgs) {
|
|
47072
47339
|
const requestFlagIndex = rawArgs.indexOf("--request");
|