perstack 0.0.76 → 0.0.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -53
- package/dist/bin/cli.js +290 -4289
- package/dist/bin/cli.js.map +1 -1
- package/package.json +7 -8
package/dist/bin/cli.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { writeFile,
|
|
4
|
-
import
|
|
5
|
-
import path10__default from 'path';
|
|
3
|
+
import { writeFile, readFile } from 'fs/promises';
|
|
4
|
+
import path2 from 'path';
|
|
6
5
|
import { createApiClient } from '@perstack/api-client';
|
|
7
|
-
import {
|
|
8
|
-
import { collectToolDefinitionsForExpert } from '@perstack/runtime';
|
|
6
|
+
import { parseWithFriendlyError, runCommandInputSchema, validateEventFilter, createFilteredEventListener, startCommandInputSchema, defaultMaxRetries, defaultTimeout, defaultPerstackApiBaseUrl, checkpointSchema, perstackConfigSchema, expertSchema } from '@perstack/core';
|
|
7
|
+
import { collectToolDefinitionsForExpert, findLockfile, loadLockfile, run, runtimeVersion } from '@perstack/runtime';
|
|
9
8
|
import TOML from 'smol-toml';
|
|
10
9
|
import dotenv from 'dotenv';
|
|
11
|
-
import * as fs from 'fs';
|
|
12
10
|
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
11
|
+
import { createInitialJob, retrieveJob, storeJob, defaultRetrieveCheckpoint, defaultStoreEvent, defaultStoreCheckpoint, getAllRuns, getEventContents, getCheckpointsByJobId, getAllJobs, getCheckpointPath, getRunIdsByJobId } from '@perstack/filesystem-storage';
|
|
12
|
+
import { createId } from '@paralleldrive/cuid2';
|
|
15
13
|
import { render, useApp, useInput, Box, Text } from 'ink';
|
|
16
14
|
import { createContext, useMemo, useReducer, useState, useEffect, useCallback, useRef, useInsertionEffect, useContext } from 'react';
|
|
17
15
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -20,7 +18,7 @@ import { useRun } from '@perstack/react';
|
|
|
20
18
|
// package.json
|
|
21
19
|
var package_default = {
|
|
22
20
|
name: "perstack",
|
|
23
|
-
version: "0.0.
|
|
21
|
+
version: "0.0.78",
|
|
24
22
|
description: "PerStack CLI"};
|
|
25
23
|
function getEnv(envPath) {
|
|
26
24
|
const env = Object.fromEntries(
|
|
@@ -71,23 +69,23 @@ async function findPerstackConfigString(configPath) {
|
|
|
71
69
|
return await fetchRemoteConfig(configPath);
|
|
72
70
|
}
|
|
73
71
|
try {
|
|
74
|
-
const tomlString = await readFile(
|
|
72
|
+
const tomlString = await readFile(path2.resolve(process.cwd(), configPath), "utf-8");
|
|
75
73
|
return tomlString;
|
|
76
74
|
} catch {
|
|
77
75
|
throw new Error(`Given config path "${configPath}" is not found`);
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
|
-
return await findPerstackConfigStringRecursively(
|
|
78
|
+
return await findPerstackConfigStringRecursively(path2.resolve(process.cwd()));
|
|
81
79
|
}
|
|
82
80
|
async function findPerstackConfigStringRecursively(cwd) {
|
|
83
81
|
try {
|
|
84
|
-
const tomlString = await readFile(
|
|
82
|
+
const tomlString = await readFile(path2.resolve(cwd, "perstack.toml"), "utf-8");
|
|
85
83
|
return tomlString;
|
|
86
84
|
} catch {
|
|
87
|
-
if (cwd ===
|
|
85
|
+
if (cwd === path2.parse(cwd).root) {
|
|
88
86
|
return null;
|
|
89
87
|
}
|
|
90
|
-
return await findPerstackConfigStringRecursively(
|
|
88
|
+
return await findPerstackConfigStringRecursively(path2.dirname(cwd));
|
|
91
89
|
}
|
|
92
90
|
}
|
|
93
91
|
async function parsePerstackConfig(config) {
|
|
@@ -98,20 +96,20 @@ async function parsePerstackConfig(config) {
|
|
|
98
96
|
// src/install.ts
|
|
99
97
|
async function findConfigPath(configPath) {
|
|
100
98
|
if (configPath) {
|
|
101
|
-
return
|
|
99
|
+
return path2.resolve(process.cwd(), configPath);
|
|
102
100
|
}
|
|
103
101
|
return await findConfigPathRecursively(process.cwd());
|
|
104
102
|
}
|
|
105
103
|
async function findConfigPathRecursively(cwd) {
|
|
106
|
-
const configPath =
|
|
104
|
+
const configPath = path2.resolve(cwd, "perstack.toml");
|
|
107
105
|
try {
|
|
108
106
|
await readFile(configPath);
|
|
109
107
|
return configPath;
|
|
110
108
|
} catch {
|
|
111
|
-
if (cwd ===
|
|
109
|
+
if (cwd === path2.parse(cwd).root) {
|
|
112
110
|
throw new Error("perstack.toml not found. Create one or specify --config path.");
|
|
113
111
|
}
|
|
114
|
-
return await findConfigPathRecursively(
|
|
112
|
+
return await findConfigPathRecursively(path2.dirname(cwd));
|
|
115
113
|
}
|
|
116
114
|
}
|
|
117
115
|
function toRuntimeExpert(key, expert) {
|
|
@@ -290,10 +288,10 @@ var installCommand = new Command().command("install").description("Generate pers
|
|
|
290
288
|
const lockfile = {
|
|
291
289
|
version: "1",
|
|
292
290
|
generatedAt: Date.now(),
|
|
293
|
-
configPath:
|
|
291
|
+
configPath: path2.basename(configPath),
|
|
294
292
|
experts: lockfileExperts
|
|
295
293
|
};
|
|
296
|
-
const lockfilePath =
|
|
294
|
+
const lockfilePath = path2.join(path2.dirname(configPath), "perstack.lock");
|
|
297
295
|
const lockfileContent = generateLockfileToml(lockfile);
|
|
298
296
|
await writeFile(lockfilePath, lockfileContent, "utf-8");
|
|
299
297
|
console.log(`Generated ${lockfilePath}`);
|
|
@@ -306,327 +304,6 @@ var installCommand = new Command().command("install").description("Generate pers
|
|
|
306
304
|
process.exit(1);
|
|
307
305
|
}
|
|
308
306
|
});
|
|
309
|
-
function getJobsDir() {
|
|
310
|
-
return `${process.cwd()}/perstack/jobs`;
|
|
311
|
-
}
|
|
312
|
-
function getJobDir(jobId) {
|
|
313
|
-
return `${getJobsDir()}/${jobId}`;
|
|
314
|
-
}
|
|
315
|
-
function getAllJobs() {
|
|
316
|
-
const jobsDir = getJobsDir();
|
|
317
|
-
if (!existsSync(jobsDir)) {
|
|
318
|
-
return [];
|
|
319
|
-
}
|
|
320
|
-
const jobDirNames = readdirSync(jobsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
|
|
321
|
-
if (jobDirNames.length === 0) {
|
|
322
|
-
return [];
|
|
323
|
-
}
|
|
324
|
-
const jobs = [];
|
|
325
|
-
for (const jobDirName of jobDirNames) {
|
|
326
|
-
const jobPath = path10__default.resolve(jobsDir, jobDirName, "job.json");
|
|
327
|
-
if (!existsSync(jobPath)) {
|
|
328
|
-
continue;
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
const content = readFileSync(jobPath, "utf-8");
|
|
332
|
-
jobs.push(jobSchema.parse(JSON.parse(content)));
|
|
333
|
-
} catch {
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return jobs.sort((a, b) => b.startedAt - a.startedAt);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// ../../packages/storages/filesystem/src/checkpoint.ts
|
|
340
|
-
function getCheckpointDir(jobId) {
|
|
341
|
-
return `${getJobDir(jobId)}/checkpoints`;
|
|
342
|
-
}
|
|
343
|
-
function getCheckpointPath(jobId, checkpointId) {
|
|
344
|
-
return `${getCheckpointDir(jobId)}/${checkpointId}.json`;
|
|
345
|
-
}
|
|
346
|
-
async function defaultRetrieveCheckpoint(jobId, checkpointId) {
|
|
347
|
-
const checkpointPath = getCheckpointPath(jobId, checkpointId);
|
|
348
|
-
if (!existsSync(checkpointPath)) {
|
|
349
|
-
throw new Error(`checkpoint not found: ${checkpointId}`);
|
|
350
|
-
}
|
|
351
|
-
const checkpoint = await readFile(checkpointPath, "utf8");
|
|
352
|
-
return checkpointSchema.parse(JSON.parse(checkpoint));
|
|
353
|
-
}
|
|
354
|
-
async function defaultStoreCheckpoint(checkpoint) {
|
|
355
|
-
const { id, jobId } = checkpoint;
|
|
356
|
-
const checkpointDir = getCheckpointDir(jobId);
|
|
357
|
-
await mkdir(checkpointDir, { recursive: true });
|
|
358
|
-
await writeFile(getCheckpointPath(jobId, id), JSON.stringify(checkpoint));
|
|
359
|
-
}
|
|
360
|
-
function getCheckpointsByJobId(jobId) {
|
|
361
|
-
const checkpointDir = getCheckpointDir(jobId);
|
|
362
|
-
if (!existsSync(checkpointDir)) {
|
|
363
|
-
return [];
|
|
364
|
-
}
|
|
365
|
-
const files = readdirSync(checkpointDir).filter((file) => file.endsWith(".json"));
|
|
366
|
-
const checkpoints = [];
|
|
367
|
-
for (const file of files) {
|
|
368
|
-
try {
|
|
369
|
-
const content = readFileSync(path10__default.resolve(checkpointDir, file), "utf-8");
|
|
370
|
-
checkpoints.push(checkpointSchema.parse(JSON.parse(content)));
|
|
371
|
-
} catch {
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
return checkpoints.sort((a, b) => a.stepNumber - b.stepNumber);
|
|
375
|
-
}
|
|
376
|
-
function defaultGetRunDir(jobId, runId) {
|
|
377
|
-
return `${process.cwd()}/perstack/jobs/${jobId}/runs/${runId}`;
|
|
378
|
-
}
|
|
379
|
-
function getAllRuns() {
|
|
380
|
-
const jobsDir = getJobsDir();
|
|
381
|
-
if (!existsSync(jobsDir)) {
|
|
382
|
-
return [];
|
|
383
|
-
}
|
|
384
|
-
const jobDirNames = readdirSync(jobsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
|
|
385
|
-
if (jobDirNames.length === 0) {
|
|
386
|
-
return [];
|
|
387
|
-
}
|
|
388
|
-
const runs = [];
|
|
389
|
-
for (const jobDirName of jobDirNames) {
|
|
390
|
-
const runsDir = path10__default.resolve(jobsDir, jobDirName, "runs");
|
|
391
|
-
if (!existsSync(runsDir)) {
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
const runDirNames = readdirSync(runsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
|
|
395
|
-
for (const runDirName of runDirNames) {
|
|
396
|
-
const runSettingPath = path10__default.resolve(runsDir, runDirName, "run-setting.json");
|
|
397
|
-
if (!existsSync(runSettingPath)) {
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
400
|
-
try {
|
|
401
|
-
const content = readFileSync(runSettingPath, "utf-8");
|
|
402
|
-
runs.push(runSettingSchema.parse(JSON.parse(content)));
|
|
403
|
-
} catch {
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return runs.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// ../../packages/storages/filesystem/src/event.ts
|
|
411
|
-
async function defaultStoreEvent(event) {
|
|
412
|
-
const { timestamp, jobId, runId, stepNumber, type } = event;
|
|
413
|
-
const runDir = defaultGetRunDir(jobId, runId);
|
|
414
|
-
const eventPath = `${runDir}/event-${timestamp}-${stepNumber}-${type}.json`;
|
|
415
|
-
await mkdir(runDir, { recursive: true });
|
|
416
|
-
await writeFile(eventPath, JSON.stringify(event));
|
|
417
|
-
}
|
|
418
|
-
function getEventContents(jobId, runId, maxStepNumber) {
|
|
419
|
-
const runDir = defaultGetRunDir(jobId, runId);
|
|
420
|
-
if (!existsSync(runDir)) {
|
|
421
|
-
return [];
|
|
422
|
-
}
|
|
423
|
-
const eventFiles = readdirSync(runDir).filter((file) => file.startsWith("event-")).map((file) => {
|
|
424
|
-
const [_, timestamp, step, type] = file.split(".")[0].split("-");
|
|
425
|
-
return { file, timestamp: Number(timestamp), stepNumber: Number(step), type };
|
|
426
|
-
}).filter((e) => maxStepNumber === void 0 || e.stepNumber <= maxStepNumber).sort((a, b) => a.timestamp - b.timestamp);
|
|
427
|
-
const events = [];
|
|
428
|
-
for (const { file } of eventFiles) {
|
|
429
|
-
try {
|
|
430
|
-
const content = readFileSync(path10__default.resolve(runDir, file), "utf-8");
|
|
431
|
-
events.push(JSON.parse(content));
|
|
432
|
-
} catch {
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
return events;
|
|
436
|
-
}
|
|
437
|
-
function getRunIdsByJobId(jobId) {
|
|
438
|
-
const runsDir = path10__default.resolve(getJobDir(jobId), "runs");
|
|
439
|
-
if (!existsSync(runsDir)) {
|
|
440
|
-
return [];
|
|
441
|
-
}
|
|
442
|
-
return readdirSync(runsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
|
|
443
|
-
}
|
|
444
|
-
var FileSystemStorage = class {
|
|
445
|
-
basePath;
|
|
446
|
-
constructor(config = {}) {
|
|
447
|
-
this.basePath = config.basePath ?? `${process.cwd()}/perstack`;
|
|
448
|
-
}
|
|
449
|
-
getJobsDir() {
|
|
450
|
-
return `${this.basePath}/jobs`;
|
|
451
|
-
}
|
|
452
|
-
getJobDir(jobId) {
|
|
453
|
-
return `${this.getJobsDir()}/${jobId}`;
|
|
454
|
-
}
|
|
455
|
-
getCheckpointDir(jobId) {
|
|
456
|
-
return `${this.getJobDir(jobId)}/checkpoints`;
|
|
457
|
-
}
|
|
458
|
-
getCheckpointPath(jobId, checkpointId) {
|
|
459
|
-
return `${this.getCheckpointDir(jobId)}/${checkpointId}.json`;
|
|
460
|
-
}
|
|
461
|
-
getRunDir(jobId, runId) {
|
|
462
|
-
return `${this.getJobDir(jobId)}/runs/${runId}`;
|
|
463
|
-
}
|
|
464
|
-
async storeCheckpoint(checkpoint) {
|
|
465
|
-
const { id, jobId } = checkpoint;
|
|
466
|
-
const checkpointDir = this.getCheckpointDir(jobId);
|
|
467
|
-
await mkdir(checkpointDir, { recursive: true });
|
|
468
|
-
await writeFile(this.getCheckpointPath(jobId, id), JSON.stringify(checkpoint));
|
|
469
|
-
}
|
|
470
|
-
async retrieveCheckpoint(jobId, checkpointId) {
|
|
471
|
-
const checkpointPath = this.getCheckpointPath(jobId, checkpointId);
|
|
472
|
-
if (!existsSync(checkpointPath)) {
|
|
473
|
-
throw new Error(`checkpoint not found: ${checkpointId}`);
|
|
474
|
-
}
|
|
475
|
-
const checkpoint = await readFile(checkpointPath, "utf8");
|
|
476
|
-
return checkpointSchema.parse(JSON.parse(checkpoint));
|
|
477
|
-
}
|
|
478
|
-
async getCheckpointsByJobId(jobId) {
|
|
479
|
-
const checkpointDir = this.getCheckpointDir(jobId);
|
|
480
|
-
if (!existsSync(checkpointDir)) {
|
|
481
|
-
return [];
|
|
482
|
-
}
|
|
483
|
-
const files = readdirSync(checkpointDir).filter((file) => file.endsWith(".json"));
|
|
484
|
-
const checkpoints = [];
|
|
485
|
-
for (const file of files) {
|
|
486
|
-
try {
|
|
487
|
-
const content = readFileSync(path10__default.resolve(checkpointDir, file), "utf-8");
|
|
488
|
-
checkpoints.push(checkpointSchema.parse(JSON.parse(content)));
|
|
489
|
-
} catch {
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
return checkpoints.sort((a, b) => a.stepNumber - b.stepNumber);
|
|
493
|
-
}
|
|
494
|
-
async storeEvent(event) {
|
|
495
|
-
const { timestamp, jobId, runId, stepNumber, type } = event;
|
|
496
|
-
const runDir = this.getRunDir(jobId, runId);
|
|
497
|
-
const eventPath = `${runDir}/event-${timestamp}-${stepNumber}-${type}.json`;
|
|
498
|
-
await mkdir(runDir, { recursive: true });
|
|
499
|
-
await writeFile(eventPath, JSON.stringify(event));
|
|
500
|
-
}
|
|
501
|
-
async getEventsByRun(jobId, runId) {
|
|
502
|
-
const runDir = this.getRunDir(jobId, runId);
|
|
503
|
-
if (!existsSync(runDir)) {
|
|
504
|
-
return [];
|
|
505
|
-
}
|
|
506
|
-
return readdirSync(runDir).filter((file) => file.startsWith("event-")).map((file) => {
|
|
507
|
-
const parts = file.split(".")[0].split("-");
|
|
508
|
-
const timestamp = Number(parts[1]);
|
|
509
|
-
const stepNumber = Number(parts[2]);
|
|
510
|
-
return {
|
|
511
|
-
timestamp,
|
|
512
|
-
stepNumber,
|
|
513
|
-
type: parts.slice(3).join("-")
|
|
514
|
-
};
|
|
515
|
-
}).filter((e) => !Number.isNaN(e.timestamp) && !Number.isNaN(e.stepNumber)).sort((a, b) => a.stepNumber - b.stepNumber);
|
|
516
|
-
}
|
|
517
|
-
async getEventContents(jobId, runId, maxStep) {
|
|
518
|
-
const runDir = this.getRunDir(jobId, runId);
|
|
519
|
-
if (!existsSync(runDir)) {
|
|
520
|
-
return [];
|
|
521
|
-
}
|
|
522
|
-
const eventFiles = readdirSync(runDir).filter((file) => file.startsWith("event-")).map((file) => {
|
|
523
|
-
const parts = file.split(".")[0].split("-");
|
|
524
|
-
const timestamp = Number(parts[1]);
|
|
525
|
-
const stepNumber = Number(parts[2]);
|
|
526
|
-
return {
|
|
527
|
-
file,
|
|
528
|
-
timestamp,
|
|
529
|
-
stepNumber,
|
|
530
|
-
type: parts.slice(3).join("-")
|
|
531
|
-
};
|
|
532
|
-
}).filter(
|
|
533
|
-
(e) => !Number.isNaN(e.timestamp) && !Number.isNaN(e.stepNumber) && (maxStep === void 0 || e.stepNumber <= maxStep)
|
|
534
|
-
).sort((a, b) => a.timestamp - b.timestamp);
|
|
535
|
-
const events = [];
|
|
536
|
-
for (const { file } of eventFiles) {
|
|
537
|
-
try {
|
|
538
|
-
const content = readFileSync(path10__default.resolve(runDir, file), "utf-8");
|
|
539
|
-
events.push(JSON.parse(content));
|
|
540
|
-
} catch {
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
return events;
|
|
544
|
-
}
|
|
545
|
-
async storeJob(job) {
|
|
546
|
-
const jobDir = this.getJobDir(job.id);
|
|
547
|
-
if (!existsSync(jobDir)) {
|
|
548
|
-
await mkdir(jobDir, { recursive: true });
|
|
549
|
-
}
|
|
550
|
-
const jobPath = path10__default.resolve(jobDir, "job.json");
|
|
551
|
-
await writeFile(jobPath, JSON.stringify(job, null, 2));
|
|
552
|
-
}
|
|
553
|
-
async retrieveJob(jobId) {
|
|
554
|
-
const jobDir = this.getJobDir(jobId);
|
|
555
|
-
const jobPath = path10__default.resolve(jobDir, "job.json");
|
|
556
|
-
if (!existsSync(jobPath)) {
|
|
557
|
-
return void 0;
|
|
558
|
-
}
|
|
559
|
-
const content = readFileSync(jobPath, "utf-8");
|
|
560
|
-
return jobSchema.parse(JSON.parse(content));
|
|
561
|
-
}
|
|
562
|
-
async getAllJobs() {
|
|
563
|
-
const jobsDir = this.getJobsDir();
|
|
564
|
-
if (!existsSync(jobsDir)) {
|
|
565
|
-
return [];
|
|
566
|
-
}
|
|
567
|
-
const jobDirNames = readdirSync(jobsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
|
|
568
|
-
if (jobDirNames.length === 0) {
|
|
569
|
-
return [];
|
|
570
|
-
}
|
|
571
|
-
const jobs = [];
|
|
572
|
-
for (const jobDirName of jobDirNames) {
|
|
573
|
-
const jobPath = path10__default.resolve(jobsDir, jobDirName, "job.json");
|
|
574
|
-
if (!existsSync(jobPath)) {
|
|
575
|
-
continue;
|
|
576
|
-
}
|
|
577
|
-
try {
|
|
578
|
-
const content = readFileSync(jobPath, "utf-8");
|
|
579
|
-
jobs.push(jobSchema.parse(JSON.parse(content)));
|
|
580
|
-
} catch {
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
return jobs.sort((a, b) => b.startedAt - a.startedAt);
|
|
584
|
-
}
|
|
585
|
-
async storeRunSetting(setting) {
|
|
586
|
-
const runDir = this.getRunDir(setting.jobId, setting.runId);
|
|
587
|
-
const runSettingPath = path10__default.resolve(runDir, "run-setting.json");
|
|
588
|
-
if (existsSync(runSettingPath)) {
|
|
589
|
-
const existingSetting = runSettingSchema.parse(
|
|
590
|
-
JSON.parse(readFileSync(runSettingPath, "utf-8"))
|
|
591
|
-
);
|
|
592
|
-
existingSetting.updatedAt = Date.now();
|
|
593
|
-
await writeFile(runSettingPath, JSON.stringify(existingSetting), "utf-8");
|
|
594
|
-
} else {
|
|
595
|
-
await mkdir(runDir, { recursive: true });
|
|
596
|
-
await writeFile(runSettingPath, JSON.stringify(setting), "utf-8");
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
async getAllRuns() {
|
|
600
|
-
const jobsDir = this.getJobsDir();
|
|
601
|
-
if (!existsSync(jobsDir)) {
|
|
602
|
-
return [];
|
|
603
|
-
}
|
|
604
|
-
const jobDirNames = readdirSync(jobsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
|
|
605
|
-
if (jobDirNames.length === 0) {
|
|
606
|
-
return [];
|
|
607
|
-
}
|
|
608
|
-
const runs = [];
|
|
609
|
-
for (const jobDirName of jobDirNames) {
|
|
610
|
-
const runsDir = path10__default.resolve(jobsDir, jobDirName, "runs");
|
|
611
|
-
if (!existsSync(runsDir)) {
|
|
612
|
-
continue;
|
|
613
|
-
}
|
|
614
|
-
const runDirNames = readdirSync(runsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
|
|
615
|
-
for (const runDirName of runDirNames) {
|
|
616
|
-
const runSettingPath = path10__default.resolve(runsDir, runDirName, "run-setting.json");
|
|
617
|
-
if (!existsSync(runSettingPath)) {
|
|
618
|
-
continue;
|
|
619
|
-
}
|
|
620
|
-
try {
|
|
621
|
-
const content = readFileSync(runSettingPath, "utf-8");
|
|
622
|
-
runs.push(runSettingSchema.parse(JSON.parse(content)));
|
|
623
|
-
} catch {
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
return runs.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
628
|
-
}
|
|
629
|
-
};
|
|
630
307
|
function createLogDataFetcher(storage) {
|
|
631
308
|
return {
|
|
632
309
|
async getJob(jobId) {
|
|
@@ -687,23 +364,23 @@ function createLogDataFetcher(storage) {
|
|
|
687
364
|
}
|
|
688
365
|
function getJobDirMtime(basePath, jobId) {
|
|
689
366
|
try {
|
|
690
|
-
const jobDir =
|
|
367
|
+
const jobDir = path2.join(basePath, "jobs", jobId);
|
|
691
368
|
const stats = statSync(jobDir);
|
|
692
369
|
return stats.mtimeMs;
|
|
693
370
|
} catch {
|
|
694
371
|
return Date.now();
|
|
695
372
|
}
|
|
696
373
|
}
|
|
697
|
-
function createStorageAdapter(
|
|
374
|
+
function createStorageAdapter(basePath) {
|
|
698
375
|
return {
|
|
699
|
-
getAllJobs: () =>
|
|
700
|
-
retrieveJob: (jobId) =>
|
|
701
|
-
getCheckpointsByJobId: (jobId) =>
|
|
702
|
-
retrieveCheckpoint: (jobId, checkpointId) =>
|
|
703
|
-
getEventContents: (jobId, runId, maxStep) =>
|
|
704
|
-
getAllRuns: () =>
|
|
376
|
+
getAllJobs: async () => getAllJobs(),
|
|
377
|
+
retrieveJob: async (jobId) => retrieveJob(jobId),
|
|
378
|
+
getCheckpointsByJobId: async (jobId) => getCheckpointsByJobId(jobId),
|
|
379
|
+
retrieveCheckpoint: async (jobId, checkpointId) => defaultRetrieveCheckpoint(jobId, checkpointId),
|
|
380
|
+
getEventContents: async (jobId, runId, maxStep) => getEventContents(jobId, runId, maxStep),
|
|
381
|
+
getAllRuns: async () => getAllRuns(),
|
|
705
382
|
getJobIds: () => {
|
|
706
|
-
const jobsDir =
|
|
383
|
+
const jobsDir = path2.join(basePath, "jobs");
|
|
707
384
|
if (!existsSync(jobsDir)) return [];
|
|
708
385
|
return readdirSync(jobsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
709
386
|
},
|
|
@@ -713,7 +390,11 @@ function createStorageAdapter(storage, basePath) {
|
|
|
713
390
|
|
|
714
391
|
// src/lib/log/filter.ts
|
|
715
392
|
var ERROR_EVENT_TYPES = /* @__PURE__ */ new Set(["stopRunByError", "retry"]);
|
|
716
|
-
var TOOL_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
393
|
+
var TOOL_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
394
|
+
"callTools",
|
|
395
|
+
"resolveToolResults",
|
|
396
|
+
"stopRunByInteractiveTool"
|
|
397
|
+
]);
|
|
717
398
|
var DELEGATION_EVENT_TYPES = /* @__PURE__ */ new Set(["stopRunByDelegate"]);
|
|
718
399
|
function parseStepFilter(step) {
|
|
719
400
|
const trimmed = step.trim();
|
|
@@ -763,18 +444,18 @@ function parseFilterExpression(expression) {
|
|
|
763
444
|
const value = parseValue(trimmedValue);
|
|
764
445
|
return { field, operator, value };
|
|
765
446
|
}
|
|
766
|
-
function parseFieldPath(
|
|
447
|
+
function parseFieldPath(path4) {
|
|
767
448
|
const parts = [];
|
|
768
449
|
let current = "";
|
|
769
450
|
let i = 0;
|
|
770
|
-
while (i <
|
|
771
|
-
if (
|
|
451
|
+
while (i < path4.length) {
|
|
452
|
+
if (path4[i] === ".") {
|
|
772
453
|
if (current) {
|
|
773
454
|
parts.push(current);
|
|
774
455
|
current = "";
|
|
775
456
|
}
|
|
776
457
|
i++;
|
|
777
|
-
} else if (
|
|
458
|
+
} else if (path4[i] === "[" && path4[i + 1] === "]") {
|
|
778
459
|
if (current) {
|
|
779
460
|
parts.push(current);
|
|
780
461
|
current = "";
|
|
@@ -782,7 +463,7 @@ function parseFieldPath(path11) {
|
|
|
782
463
|
parts.push("*");
|
|
783
464
|
i += 2;
|
|
784
465
|
} else {
|
|
785
|
-
current +=
|
|
466
|
+
current += path4[i];
|
|
786
467
|
i++;
|
|
787
468
|
}
|
|
788
469
|
}
|
|
@@ -817,10 +498,10 @@ function evaluateCondition(event, condition) {
|
|
|
817
498
|
}
|
|
818
499
|
return compareValues(actualValue, operator, value);
|
|
819
500
|
}
|
|
820
|
-
function getFieldValue(obj,
|
|
501
|
+
function getFieldValue(obj, path4) {
|
|
821
502
|
let current = obj;
|
|
822
|
-
for (let i = 0; i <
|
|
823
|
-
const segment =
|
|
503
|
+
for (let i = 0; i < path4.length; i++) {
|
|
504
|
+
const segment = path4[i];
|
|
824
505
|
if (current === null || current === void 0) {
|
|
825
506
|
return void 0;
|
|
826
507
|
}
|
|
@@ -828,7 +509,7 @@ function getFieldValue(obj, path11) {
|
|
|
828
509
|
if (!Array.isArray(current)) {
|
|
829
510
|
return void 0;
|
|
830
511
|
}
|
|
831
|
-
const remainingPath =
|
|
512
|
+
const remainingPath = path4.slice(i + 1);
|
|
832
513
|
if (remainingPath.length === 0) {
|
|
833
514
|
return current;
|
|
834
515
|
}
|
|
@@ -929,9 +610,6 @@ function addContextEvents(allEvents, matchedEvents, contextSize) {
|
|
|
929
610
|
}
|
|
930
611
|
|
|
931
612
|
// src/lib/log/formatter.ts
|
|
932
|
-
var ERROR_EVENT_TYPES2 = /* @__PURE__ */ new Set(["stopRunByError", "retry"]);
|
|
933
|
-
var TOOL_EVENT_TYPES2 = /* @__PURE__ */ new Set(["callTools", "resolveToolResults", "stopRunByInteractiveTool"]);
|
|
934
|
-
var DELEGATION_EVENT_TYPES2 = /* @__PURE__ */ new Set(["stopRunByDelegate"]);
|
|
935
613
|
function createSummary(events) {
|
|
936
614
|
if (events.length === 0) {
|
|
937
615
|
return {
|
|
@@ -944,9 +622,9 @@ function createSummary(events) {
|
|
|
944
622
|
const stepNumbers = events.map((e) => e.stepNumber);
|
|
945
623
|
return {
|
|
946
624
|
totalEvents: events.length,
|
|
947
|
-
errorCount: events.filter((e) =>
|
|
948
|
-
toolCallCount: events.filter((e) =>
|
|
949
|
-
delegationCount: events.filter((e) =>
|
|
625
|
+
errorCount: events.filter((e) => ERROR_EVENT_TYPES.has(e.type)).length,
|
|
626
|
+
toolCallCount: events.filter((e) => TOOL_EVENT_TYPES.has(e.type)).length,
|
|
627
|
+
delegationCount: events.filter((e) => DELEGATION_EVENT_TYPES.has(e.type)).length,
|
|
950
628
|
stepRange: { min: Math.min(...stepNumbers), max: Math.max(...stepNumbers) }
|
|
951
629
|
};
|
|
952
630
|
}
|
|
@@ -962,9 +640,6 @@ function formatJson(output, options) {
|
|
|
962
640
|
if (output.checkpoints && output.checkpoints.length > 0) {
|
|
963
641
|
data.checkpoints = output.checkpoints;
|
|
964
642
|
}
|
|
965
|
-
if (output.runs && output.runs.length > 0) {
|
|
966
|
-
data.runs = output.runs;
|
|
967
|
-
}
|
|
968
643
|
if (output.isLatestJob) {
|
|
969
644
|
data.isLatestJob = true;
|
|
970
645
|
}
|
|
@@ -1175,8 +850,7 @@ var logCommand = new Command().command("log").description("View execution histor
|
|
|
1175
850
|
).option("--messages", "Show message history for checkpoint").option("--summary", "Show summarized view").action(async (options) => {
|
|
1176
851
|
try {
|
|
1177
852
|
const storagePath = process.env.PERSTACK_STORAGE_PATH ?? `${process.cwd()}/perstack`;
|
|
1178
|
-
const
|
|
1179
|
-
const adapter = createStorageAdapter(storage, storagePath);
|
|
853
|
+
const adapter = createStorageAdapter(storagePath);
|
|
1180
854
|
const fetcher = createLogDataFetcher(adapter);
|
|
1181
855
|
const filterOptions = buildFilterOptions(options);
|
|
1182
856
|
const formatterOptions = buildFormatterOptions(options);
|
|
@@ -1428,3818 +1102,173 @@ function getProviderConfig(provider, env, providerTable) {
|
|
|
1428
1102
|
headers: setting.headers
|
|
1429
1103
|
};
|
|
1430
1104
|
}
|
|
1431
|
-
case "deepseek": {
|
|
1432
|
-
const apiKey = env.DEEPSEEK_API_KEY;
|
|
1433
|
-
if (!apiKey) throw new Error("DEEPSEEK_API_KEY is not set");
|
|
1434
|
-
return {
|
|
1435
|
-
providerName: "deepseek",
|
|
1436
|
-
apiKey,
|
|
1437
|
-
baseUrl: setting.baseUrl ?? env.DEEPSEEK_BASE_URL,
|
|
1438
|
-
headers: setting.headers
|
|
1439
|
-
};
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
function getAllJobs2() {
|
|
1444
|
-
return getAllJobs();
|
|
1445
|
-
}
|
|
1446
|
-
function getAllRuns2() {
|
|
1447
|
-
return getAllRuns();
|
|
1448
|
-
}
|
|
1449
|
-
function getMostRecentRun() {
|
|
1450
|
-
const runs = getAllRuns2();
|
|
1451
|
-
if (runs.length === 0) {
|
|
1452
|
-
throw new Error("No runs found");
|
|
1453
|
-
}
|
|
1454
|
-
return runs[0];
|
|
1455
|
-
}
|
|
1456
|
-
function getCheckpointsByJobId2(jobId) {
|
|
1457
|
-
return getCheckpointsByJobId(jobId);
|
|
1458
|
-
}
|
|
1459
|
-
function getMostRecentCheckpoint(jobId) {
|
|
1460
|
-
const targetJobId = jobId ?? getMostRecentRun().jobId;
|
|
1461
|
-
const checkpoints = getCheckpointsByJobId2(targetJobId);
|
|
1462
|
-
if (checkpoints.length === 0) {
|
|
1463
|
-
throw new Error(`No checkpoints found for job ${targetJobId}`);
|
|
1464
|
-
}
|
|
1465
|
-
return checkpoints[checkpoints.length - 1];
|
|
1466
|
-
}
|
|
1467
|
-
function getRecentExperts(limit) {
|
|
1468
|
-
const runs = getAllRuns2();
|
|
1469
|
-
const expertMap = /* @__PURE__ */ new Map();
|
|
1470
|
-
for (const setting of runs) {
|
|
1471
|
-
const expertKey = setting.expertKey;
|
|
1472
|
-
if (!expertMap.has(expertKey) || expertMap.get(expertKey).lastUsed < setting.updatedAt) {
|
|
1473
|
-
expertMap.set(expertKey, {
|
|
1474
|
-
key: expertKey,
|
|
1475
|
-
name: expertKey,
|
|
1476
|
-
lastUsed: setting.updatedAt
|
|
1477
|
-
});
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
return Array.from(expertMap.values()).sort((a, b) => b.lastUsed - a.lastUsed).slice(0, limit);
|
|
1481
|
-
}
|
|
1482
|
-
function getCheckpointById(jobId, checkpointId) {
|
|
1483
|
-
const checkpointPath = getCheckpointPath(jobId, checkpointId);
|
|
1484
|
-
if (!existsSync(checkpointPath)) {
|
|
1485
|
-
throw new Error(`Checkpoint ${checkpointId} not found in job ${jobId}`);
|
|
1486
|
-
}
|
|
1487
|
-
const checkpoint = readFileSync(checkpointPath, "utf-8");
|
|
1488
|
-
return checkpointSchema.parse(JSON.parse(checkpoint));
|
|
1489
|
-
}
|
|
1490
|
-
function getCheckpointsWithDetails(jobId) {
|
|
1491
|
-
return getCheckpointsByJobId2(jobId).map((cp) => ({
|
|
1492
|
-
id: cp.id,
|
|
1493
|
-
runId: cp.runId,
|
|
1494
|
-
stepNumber: cp.stepNumber,
|
|
1495
|
-
contextWindowUsage: cp.contextWindowUsage ?? 0
|
|
1496
|
-
})).sort((a, b) => b.stepNumber - a.stepNumber);
|
|
1497
|
-
}
|
|
1498
|
-
function getAllEventContentsForJob(jobId, maxStepNumber) {
|
|
1499
|
-
const runIds = getRunIdsByJobId(jobId);
|
|
1500
|
-
const allEvents = [];
|
|
1501
|
-
for (const runId of runIds) {
|
|
1502
|
-
const events = getEventContents(jobId, runId, maxStepNumber);
|
|
1503
|
-
allEvents.push(...events);
|
|
1504
|
-
}
|
|
1505
|
-
return allEvents.sort((a, b) => a.timestamp - b.timestamp);
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
// src/lib/context.ts
|
|
1509
|
-
var defaultProvider = "anthropic";
|
|
1510
|
-
var defaultModel = "claude-sonnet-4-5";
|
|
1511
|
-
async function resolveRunContext(input) {
|
|
1512
|
-
const perstackConfig = await getPerstackConfig(input.configPath);
|
|
1513
|
-
let checkpoint;
|
|
1514
|
-
if (input.resumeFrom) {
|
|
1515
|
-
if (!input.continueJob) {
|
|
1516
|
-
throw new Error("--resume-from requires --continue-job");
|
|
1517
|
-
}
|
|
1518
|
-
checkpoint = getCheckpointById(input.continueJob, input.resumeFrom);
|
|
1519
|
-
} else if (input.continueJob) {
|
|
1520
|
-
checkpoint = getMostRecentCheckpoint(input.continueJob);
|
|
1521
|
-
} else if (input.continue) {
|
|
1522
|
-
checkpoint = getMostRecentCheckpoint();
|
|
1523
|
-
}
|
|
1524
|
-
if ((input.continue || input.continueJob || input.resumeFrom) && !checkpoint) {
|
|
1525
|
-
throw new Error("No checkpoint found");
|
|
1526
|
-
}
|
|
1527
|
-
if (checkpoint && input.expertKey && checkpoint.expert.key !== input.expertKey) {
|
|
1528
|
-
throw new Error(
|
|
1529
|
-
`Checkpoint expert key ${checkpoint.expert.key} does not match input expert key ${input.expertKey}`
|
|
1530
|
-
);
|
|
1531
|
-
}
|
|
1532
|
-
const envPath = input.envPath && input.envPath.length > 0 ? input.envPath : perstackConfig.envPath ?? [".env", ".env.local"];
|
|
1533
|
-
const env = getEnv(envPath);
|
|
1534
|
-
const provider = input.provider ?? perstackConfig.provider?.providerName ?? defaultProvider;
|
|
1535
|
-
const model = input.model ?? perstackConfig.model ?? defaultModel;
|
|
1536
|
-
const providerConfig = getProviderConfig(provider, env, perstackConfig.provider);
|
|
1537
|
-
const experts = Object.fromEntries(
|
|
1538
|
-
Object.entries(perstackConfig.experts ?? {}).map(([name, expert]) => {
|
|
1539
|
-
return [
|
|
1540
|
-
name,
|
|
1541
|
-
{
|
|
1542
|
-
name,
|
|
1543
|
-
version: expert.version ?? "1.0.0",
|
|
1544
|
-
description: expert.description,
|
|
1545
|
-
instruction: expert.instruction,
|
|
1546
|
-
skills: expert.skills,
|
|
1547
|
-
delegates: expert.delegates,
|
|
1548
|
-
tags: expert.tags
|
|
1549
|
-
}
|
|
1550
|
-
];
|
|
1551
|
-
})
|
|
1552
|
-
);
|
|
1553
|
-
return {
|
|
1554
|
-
perstackConfig,
|
|
1555
|
-
checkpoint,
|
|
1556
|
-
env,
|
|
1557
|
-
providerConfig,
|
|
1558
|
-
model,
|
|
1559
|
-
experts
|
|
1560
|
-
};
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
// src/lib/interactive.ts
|
|
1564
|
-
function parseInteractiveToolCallResult(query, checkpoint) {
|
|
1565
|
-
const lastMessage = checkpoint.messages[checkpoint.messages.length - 1];
|
|
1566
|
-
if (lastMessage.type !== "expertMessage") {
|
|
1567
|
-
throw new Error("Last message is not a expert message");
|
|
1568
|
-
}
|
|
1569
|
-
const content = lastMessage.contents.find((c) => c.type === "toolCallPart");
|
|
1570
|
-
if (!content || content.type !== "toolCallPart") {
|
|
1571
|
-
throw new Error("Last message content is not a tool call part");
|
|
1572
|
-
}
|
|
1573
|
-
const toolCallId = content.toolCallId;
|
|
1574
|
-
const toolName = content.toolName;
|
|
1575
|
-
const pendingToolCall = checkpoint.pendingToolCalls?.find((tc) => tc.id === toolCallId);
|
|
1576
|
-
const skillName = pendingToolCall?.skillName ?? "";
|
|
1577
|
-
return {
|
|
1578
|
-
interactiveToolCallResult: {
|
|
1579
|
-
toolCallId,
|
|
1580
|
-
toolName,
|
|
1581
|
-
skillName,
|
|
1582
|
-
text: query
|
|
1583
|
-
}
|
|
1584
|
-
};
|
|
1585
|
-
}
|
|
1586
|
-
function parseInteractiveToolCallResultJson(query) {
|
|
1587
|
-
try {
|
|
1588
|
-
const parsed = JSON.parse(query);
|
|
1589
|
-
if (typeof parsed === "object" && parsed !== null && "toolCallId" in parsed && "toolName" in parsed && "skillName" in parsed && "text" in parsed) {
|
|
1590
|
-
return {
|
|
1591
|
-
interactiveToolCallResult: parsed
|
|
1592
|
-
};
|
|
1593
|
-
}
|
|
1594
|
-
return null;
|
|
1595
|
-
} catch {
|
|
1596
|
-
return null;
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
// ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/_u64.js
|
|
1601
|
-
var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
1602
|
-
var _32n = /* @__PURE__ */ BigInt(32);
|
|
1603
|
-
function fromBig(n, le = false) {
|
|
1604
|
-
if (le)
|
|
1605
|
-
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
1606
|
-
return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
|
|
1607
|
-
}
|
|
1608
|
-
function split(lst, le = false) {
|
|
1609
|
-
const len = lst.length;
|
|
1610
|
-
let Ah = new Uint32Array(len);
|
|
1611
|
-
let Al = new Uint32Array(len);
|
|
1612
|
-
for (let i = 0; i < len; i++) {
|
|
1613
|
-
const { h, l } = fromBig(lst[i], le);
|
|
1614
|
-
[Ah[i], Al[i]] = [h, l];
|
|
1615
|
-
}
|
|
1616
|
-
return [Ah, Al];
|
|
1617
|
-
}
|
|
1618
|
-
var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
|
|
1619
|
-
var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
|
|
1620
|
-
var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
|
|
1621
|
-
var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
|
|
1622
|
-
|
|
1623
|
-
// ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/utils.js
|
|
1624
|
-
function isBytes(a) {
|
|
1625
|
-
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
1626
|
-
}
|
|
1627
|
-
function anumber(n, title = "") {
|
|
1628
|
-
if (!Number.isSafeInteger(n) || n < 0) {
|
|
1629
|
-
const prefix = title && `"${title}" `;
|
|
1630
|
-
throw new Error(`${prefix}expected integer >= 0, got ${n}`);
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
function abytes(value, length, title = "") {
|
|
1634
|
-
const bytes = isBytes(value);
|
|
1635
|
-
const len = value?.length;
|
|
1636
|
-
const needsLen = length !== void 0;
|
|
1637
|
-
if (!bytes || needsLen) {
|
|
1638
|
-
const prefix = title && `"${title}" `;
|
|
1639
|
-
const ofLen = "";
|
|
1640
|
-
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
1641
|
-
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
1642
|
-
}
|
|
1643
|
-
return value;
|
|
1644
|
-
}
|
|
1645
|
-
function aexists(instance, checkFinished = true) {
|
|
1646
|
-
if (instance.destroyed)
|
|
1647
|
-
throw new Error("Hash instance has been destroyed");
|
|
1648
|
-
if (checkFinished && instance.finished)
|
|
1649
|
-
throw new Error("Hash#digest() has already been called");
|
|
1650
|
-
}
|
|
1651
|
-
function aoutput(out, instance) {
|
|
1652
|
-
abytes(out, void 0, "digestInto() output");
|
|
1653
|
-
const min = instance.outputLen;
|
|
1654
|
-
if (out.length < min) {
|
|
1655
|
-
throw new Error('"digestInto() output" expected to be of length >=' + min);
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
function u32(arr) {
|
|
1659
|
-
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
1660
|
-
}
|
|
1661
|
-
function clean(...arrays) {
|
|
1662
|
-
for (let i = 0; i < arrays.length; i++) {
|
|
1663
|
-
arrays[i].fill(0);
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
1667
|
-
function byteSwap(word) {
|
|
1668
|
-
return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
|
|
1669
|
-
}
|
|
1670
|
-
function byteSwap32(arr) {
|
|
1671
|
-
for (let i = 0; i < arr.length; i++) {
|
|
1672
|
-
arr[i] = byteSwap(arr[i]);
|
|
1673
|
-
}
|
|
1674
|
-
return arr;
|
|
1675
|
-
}
|
|
1676
|
-
var swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
1677
|
-
function createHasher(hashCons, info = {}) {
|
|
1678
|
-
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
1679
|
-
const tmp = hashCons(void 0);
|
|
1680
|
-
hashC.outputLen = tmp.outputLen;
|
|
1681
|
-
hashC.blockLen = tmp.blockLen;
|
|
1682
|
-
hashC.create = (opts) => hashCons(opts);
|
|
1683
|
-
Object.assign(hashC, info);
|
|
1684
|
-
return Object.freeze(hashC);
|
|
1685
|
-
}
|
|
1686
|
-
var oidNist = (suffix) => ({
|
|
1687
|
-
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
|
|
1688
|
-
});
|
|
1689
|
-
|
|
1690
|
-
// ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/sha3.js
|
|
1691
|
-
var _0n = BigInt(0);
|
|
1692
|
-
var _1n = BigInt(1);
|
|
1693
|
-
var _2n = BigInt(2);
|
|
1694
|
-
var _7n = BigInt(7);
|
|
1695
|
-
var _256n = BigInt(256);
|
|
1696
|
-
var _0x71n = BigInt(113);
|
|
1697
|
-
var SHA3_PI = [];
|
|
1698
|
-
var SHA3_ROTL = [];
|
|
1699
|
-
var _SHA3_IOTA = [];
|
|
1700
|
-
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
|
|
1701
|
-
[x, y] = [y, (2 * x + 3 * y) % 5];
|
|
1702
|
-
SHA3_PI.push(2 * (5 * y + x));
|
|
1703
|
-
SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
|
|
1704
|
-
let t = _0n;
|
|
1705
|
-
for (let j = 0; j < 7; j++) {
|
|
1706
|
-
R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
|
|
1707
|
-
if (R & _2n)
|
|
1708
|
-
t ^= _1n << (_1n << BigInt(j)) - _1n;
|
|
1709
|
-
}
|
|
1710
|
-
_SHA3_IOTA.push(t);
|
|
1711
|
-
}
|
|
1712
|
-
var IOTAS = split(_SHA3_IOTA, true);
|
|
1713
|
-
var SHA3_IOTA_H = IOTAS[0];
|
|
1714
|
-
var SHA3_IOTA_L = IOTAS[1];
|
|
1715
|
-
var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
|
|
1716
|
-
var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
|
|
1717
|
-
function keccakP(s, rounds = 24) {
|
|
1718
|
-
const B = new Uint32Array(5 * 2);
|
|
1719
|
-
for (let round = 24 - rounds; round < 24; round++) {
|
|
1720
|
-
for (let x = 0; x < 10; x++)
|
|
1721
|
-
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
|
1722
|
-
for (let x = 0; x < 10; x += 2) {
|
|
1723
|
-
const idx1 = (x + 8) % 10;
|
|
1724
|
-
const idx0 = (x + 2) % 10;
|
|
1725
|
-
const B0 = B[idx0];
|
|
1726
|
-
const B1 = B[idx0 + 1];
|
|
1727
|
-
const Th = rotlH(B0, B1, 1) ^ B[idx1];
|
|
1728
|
-
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
|
|
1729
|
-
for (let y = 0; y < 50; y += 10) {
|
|
1730
|
-
s[x + y] ^= Th;
|
|
1731
|
-
s[x + y + 1] ^= Tl;
|
|
1732
|
-
}
|
|
1733
|
-
}
|
|
1734
|
-
let curH = s[2];
|
|
1735
|
-
let curL = s[3];
|
|
1736
|
-
for (let t = 0; t < 24; t++) {
|
|
1737
|
-
const shift = SHA3_ROTL[t];
|
|
1738
|
-
const Th = rotlH(curH, curL, shift);
|
|
1739
|
-
const Tl = rotlL(curH, curL, shift);
|
|
1740
|
-
const PI = SHA3_PI[t];
|
|
1741
|
-
curH = s[PI];
|
|
1742
|
-
curL = s[PI + 1];
|
|
1743
|
-
s[PI] = Th;
|
|
1744
|
-
s[PI + 1] = Tl;
|
|
1745
|
-
}
|
|
1746
|
-
for (let y = 0; y < 50; y += 10) {
|
|
1747
|
-
for (let x = 0; x < 10; x++)
|
|
1748
|
-
B[x] = s[y + x];
|
|
1749
|
-
for (let x = 0; x < 10; x++)
|
|
1750
|
-
s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
|
1751
|
-
}
|
|
1752
|
-
s[0] ^= SHA3_IOTA_H[round];
|
|
1753
|
-
s[1] ^= SHA3_IOTA_L[round];
|
|
1754
|
-
}
|
|
1755
|
-
clean(B);
|
|
1756
|
-
}
|
|
1757
|
-
var Keccak = class _Keccak {
|
|
1758
|
-
state;
|
|
1759
|
-
pos = 0;
|
|
1760
|
-
posOut = 0;
|
|
1761
|
-
finished = false;
|
|
1762
|
-
state32;
|
|
1763
|
-
destroyed = false;
|
|
1764
|
-
blockLen;
|
|
1765
|
-
suffix;
|
|
1766
|
-
outputLen;
|
|
1767
|
-
enableXOF = false;
|
|
1768
|
-
rounds;
|
|
1769
|
-
// NOTE: we accept arguments in bytes instead of bits here.
|
|
1770
|
-
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
|
1771
|
-
this.blockLen = blockLen;
|
|
1772
|
-
this.suffix = suffix;
|
|
1773
|
-
this.outputLen = outputLen;
|
|
1774
|
-
this.enableXOF = enableXOF;
|
|
1775
|
-
this.rounds = rounds;
|
|
1776
|
-
anumber(outputLen, "outputLen");
|
|
1777
|
-
if (!(0 < blockLen && blockLen < 200))
|
|
1778
|
-
throw new Error("only keccak-f1600 function is supported");
|
|
1779
|
-
this.state = new Uint8Array(200);
|
|
1780
|
-
this.state32 = u32(this.state);
|
|
1781
|
-
}
|
|
1782
|
-
clone() {
|
|
1783
|
-
return this._cloneInto();
|
|
1784
|
-
}
|
|
1785
|
-
keccak() {
|
|
1786
|
-
swap32IfBE(this.state32);
|
|
1787
|
-
keccakP(this.state32, this.rounds);
|
|
1788
|
-
swap32IfBE(this.state32);
|
|
1789
|
-
this.posOut = 0;
|
|
1790
|
-
this.pos = 0;
|
|
1791
|
-
}
|
|
1792
|
-
update(data) {
|
|
1793
|
-
aexists(this);
|
|
1794
|
-
abytes(data);
|
|
1795
|
-
const { blockLen, state } = this;
|
|
1796
|
-
const len = data.length;
|
|
1797
|
-
for (let pos = 0; pos < len; ) {
|
|
1798
|
-
const take = Math.min(blockLen - this.pos, len - pos);
|
|
1799
|
-
for (let i = 0; i < take; i++)
|
|
1800
|
-
state[this.pos++] ^= data[pos++];
|
|
1801
|
-
if (this.pos === blockLen)
|
|
1802
|
-
this.keccak();
|
|
1803
|
-
}
|
|
1804
|
-
return this;
|
|
1805
|
-
}
|
|
1806
|
-
finish() {
|
|
1807
|
-
if (this.finished)
|
|
1808
|
-
return;
|
|
1809
|
-
this.finished = true;
|
|
1810
|
-
const { state, suffix, pos, blockLen } = this;
|
|
1811
|
-
state[pos] ^= suffix;
|
|
1812
|
-
if ((suffix & 128) !== 0 && pos === blockLen - 1)
|
|
1813
|
-
this.keccak();
|
|
1814
|
-
state[blockLen - 1] ^= 128;
|
|
1815
|
-
this.keccak();
|
|
1816
|
-
}
|
|
1817
|
-
writeInto(out) {
|
|
1818
|
-
aexists(this, false);
|
|
1819
|
-
abytes(out);
|
|
1820
|
-
this.finish();
|
|
1821
|
-
const bufferOut = this.state;
|
|
1822
|
-
const { blockLen } = this;
|
|
1823
|
-
for (let pos = 0, len = out.length; pos < len; ) {
|
|
1824
|
-
if (this.posOut >= blockLen)
|
|
1825
|
-
this.keccak();
|
|
1826
|
-
const take = Math.min(blockLen - this.posOut, len - pos);
|
|
1827
|
-
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
|
1828
|
-
this.posOut += take;
|
|
1829
|
-
pos += take;
|
|
1830
|
-
}
|
|
1831
|
-
return out;
|
|
1832
|
-
}
|
|
1833
|
-
xofInto(out) {
|
|
1834
|
-
if (!this.enableXOF)
|
|
1835
|
-
throw new Error("XOF is not possible for this instance");
|
|
1836
|
-
return this.writeInto(out);
|
|
1837
|
-
}
|
|
1838
|
-
xof(bytes) {
|
|
1839
|
-
anumber(bytes);
|
|
1840
|
-
return this.xofInto(new Uint8Array(bytes));
|
|
1841
|
-
}
|
|
1842
|
-
digestInto(out) {
|
|
1843
|
-
aoutput(out, this);
|
|
1844
|
-
if (this.finished)
|
|
1845
|
-
throw new Error("digest() was already called");
|
|
1846
|
-
this.writeInto(out);
|
|
1847
|
-
this.destroy();
|
|
1848
|
-
return out;
|
|
1849
|
-
}
|
|
1850
|
-
digest() {
|
|
1851
|
-
return this.digestInto(new Uint8Array(this.outputLen));
|
|
1852
|
-
}
|
|
1853
|
-
destroy() {
|
|
1854
|
-
this.destroyed = true;
|
|
1855
|
-
clean(this.state);
|
|
1856
|
-
}
|
|
1857
|
-
_cloneInto(to) {
|
|
1858
|
-
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
|
1859
|
-
to ||= new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds);
|
|
1860
|
-
to.state32.set(this.state32);
|
|
1861
|
-
to.pos = this.pos;
|
|
1862
|
-
to.posOut = this.posOut;
|
|
1863
|
-
to.finished = this.finished;
|
|
1864
|
-
to.rounds = rounds;
|
|
1865
|
-
to.suffix = suffix;
|
|
1866
|
-
to.outputLen = outputLen;
|
|
1867
|
-
to.enableXOF = enableXOF;
|
|
1868
|
-
to.destroyed = this.destroyed;
|
|
1869
|
-
return to;
|
|
1870
|
-
}
|
|
1871
|
-
};
|
|
1872
|
-
var genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);
|
|
1873
|
-
var sha3_512 = /* @__PURE__ */ genKeccak(
|
|
1874
|
-
6,
|
|
1875
|
-
72,
|
|
1876
|
-
64,
|
|
1877
|
-
/* @__PURE__ */ oidNist(10)
|
|
1878
|
-
);
|
|
1879
|
-
|
|
1880
|
-
// ../../node_modules/.pnpm/bignumber.js@9.3.1/node_modules/bignumber.js/bignumber.mjs
|
|
1881
|
-
var isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
1882
|
-
var mathceil = Math.ceil;
|
|
1883
|
-
var mathfloor = Math.floor;
|
|
1884
|
-
var bignumberError = "[BigNumber Error] ";
|
|
1885
|
-
var tooManyDigits = bignumberError + "Number primitive has more than 15 significant digits: ";
|
|
1886
|
-
var BASE = 1e14;
|
|
1887
|
-
var LOG_BASE = 14;
|
|
1888
|
-
var MAX_SAFE_INTEGER = 9007199254740991;
|
|
1889
|
-
var POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13];
|
|
1890
|
-
var SQRT_BASE = 1e7;
|
|
1891
|
-
var MAX = 1e9;
|
|
1892
|
-
function clone(configObject) {
|
|
1893
|
-
var div, convertBase, parseNumeric, P = BigNumber2.prototype = { constructor: BigNumber2, toString: null, valueOf: null }, ONE = new BigNumber2(1), DECIMAL_PLACES = 20, ROUNDING_MODE = 4, TO_EXP_NEG = -7, TO_EXP_POS = 21, MIN_EXP = -1e7, MAX_EXP = 1e7, CRYPTO = false, MODULO_MODE = 1, POW_PRECISION = 0, FORMAT = {
|
|
1894
|
-
prefix: "",
|
|
1895
|
-
groupSize: 3,
|
|
1896
|
-
secondaryGroupSize: 0,
|
|
1897
|
-
groupSeparator: ",",
|
|
1898
|
-
decimalSeparator: ".",
|
|
1899
|
-
fractionGroupSize: 0,
|
|
1900
|
-
fractionGroupSeparator: "\xA0",
|
|
1901
|
-
// non-breaking space
|
|
1902
|
-
suffix: ""
|
|
1903
|
-
}, ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz", alphabetHasNormalDecimalDigits = true;
|
|
1904
|
-
function BigNumber2(v, b) {
|
|
1905
|
-
var alphabet2, c, caseChanged, e, i, isNum, len, str, x = this;
|
|
1906
|
-
if (!(x instanceof BigNumber2)) return new BigNumber2(v, b);
|
|
1907
|
-
if (b == null) {
|
|
1908
|
-
if (v && v._isBigNumber === true) {
|
|
1909
|
-
x.s = v.s;
|
|
1910
|
-
if (!v.c || v.e > MAX_EXP) {
|
|
1911
|
-
x.c = x.e = null;
|
|
1912
|
-
} else if (v.e < MIN_EXP) {
|
|
1913
|
-
x.c = [x.e = 0];
|
|
1914
|
-
} else {
|
|
1915
|
-
x.e = v.e;
|
|
1916
|
-
x.c = v.c.slice();
|
|
1917
|
-
}
|
|
1918
|
-
return;
|
|
1919
|
-
}
|
|
1920
|
-
if ((isNum = typeof v == "number") && v * 0 == 0) {
|
|
1921
|
-
x.s = 1 / v < 0 ? (v = -v, -1) : 1;
|
|
1922
|
-
if (v === ~~v) {
|
|
1923
|
-
for (e = 0, i = v; i >= 10; i /= 10, e++) ;
|
|
1924
|
-
if (e > MAX_EXP) {
|
|
1925
|
-
x.c = x.e = null;
|
|
1926
|
-
} else {
|
|
1927
|
-
x.e = e;
|
|
1928
|
-
x.c = [v];
|
|
1929
|
-
}
|
|
1930
|
-
return;
|
|
1931
|
-
}
|
|
1932
|
-
str = String(v);
|
|
1933
|
-
} else {
|
|
1934
|
-
if (!isNumeric.test(str = String(v))) return parseNumeric(x, str, isNum);
|
|
1935
|
-
x.s = str.charCodeAt(0) == 45 ? (str = str.slice(1), -1) : 1;
|
|
1936
|
-
}
|
|
1937
|
-
if ((e = str.indexOf(".")) > -1) str = str.replace(".", "");
|
|
1938
|
-
if ((i = str.search(/e/i)) > 0) {
|
|
1939
|
-
if (e < 0) e = i;
|
|
1940
|
-
e += +str.slice(i + 1);
|
|
1941
|
-
str = str.substring(0, i);
|
|
1942
|
-
} else if (e < 0) {
|
|
1943
|
-
e = str.length;
|
|
1944
|
-
}
|
|
1945
|
-
} else {
|
|
1946
|
-
intCheck(b, 2, ALPHABET.length, "Base");
|
|
1947
|
-
if (b == 10 && alphabetHasNormalDecimalDigits) {
|
|
1948
|
-
x = new BigNumber2(v);
|
|
1949
|
-
return round(x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE);
|
|
1950
|
-
}
|
|
1951
|
-
str = String(v);
|
|
1952
|
-
if (isNum = typeof v == "number") {
|
|
1953
|
-
if (v * 0 != 0) return parseNumeric(x, str, isNum, b);
|
|
1954
|
-
x.s = 1 / v < 0 ? (str = str.slice(1), -1) : 1;
|
|
1955
|
-
if (BigNumber2.DEBUG && str.replace(/^0\.0*|\./, "").length > 15) {
|
|
1956
|
-
throw Error(tooManyDigits + v);
|
|
1957
|
-
}
|
|
1958
|
-
} else {
|
|
1959
|
-
x.s = str.charCodeAt(0) === 45 ? (str = str.slice(1), -1) : 1;
|
|
1960
|
-
}
|
|
1961
|
-
alphabet2 = ALPHABET.slice(0, b);
|
|
1962
|
-
e = i = 0;
|
|
1963
|
-
for (len = str.length; i < len; i++) {
|
|
1964
|
-
if (alphabet2.indexOf(c = str.charAt(i)) < 0) {
|
|
1965
|
-
if (c == ".") {
|
|
1966
|
-
if (i > e) {
|
|
1967
|
-
e = len;
|
|
1968
|
-
continue;
|
|
1969
|
-
}
|
|
1970
|
-
} else if (!caseChanged) {
|
|
1971
|
-
if (str == str.toUpperCase() && (str = str.toLowerCase()) || str == str.toLowerCase() && (str = str.toUpperCase())) {
|
|
1972
|
-
caseChanged = true;
|
|
1973
|
-
i = -1;
|
|
1974
|
-
e = 0;
|
|
1975
|
-
continue;
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
return parseNumeric(x, String(v), isNum, b);
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
|
-
isNum = false;
|
|
1982
|
-
str = convertBase(str, b, 10, x.s);
|
|
1983
|
-
if ((e = str.indexOf(".")) > -1) str = str.replace(".", "");
|
|
1984
|
-
else e = str.length;
|
|
1985
|
-
}
|
|
1986
|
-
for (i = 0; str.charCodeAt(i) === 48; i++) ;
|
|
1987
|
-
for (len = str.length; str.charCodeAt(--len) === 48; ) ;
|
|
1988
|
-
if (str = str.slice(i, ++len)) {
|
|
1989
|
-
len -= i;
|
|
1990
|
-
if (isNum && BigNumber2.DEBUG && len > 15 && (v > MAX_SAFE_INTEGER || v !== mathfloor(v))) {
|
|
1991
|
-
throw Error(tooManyDigits + x.s * v);
|
|
1992
|
-
}
|
|
1993
|
-
if ((e = e - i - 1) > MAX_EXP) {
|
|
1994
|
-
x.c = x.e = null;
|
|
1995
|
-
} else if (e < MIN_EXP) {
|
|
1996
|
-
x.c = [x.e = 0];
|
|
1997
|
-
} else {
|
|
1998
|
-
x.e = e;
|
|
1999
|
-
x.c = [];
|
|
2000
|
-
i = (e + 1) % LOG_BASE;
|
|
2001
|
-
if (e < 0) i += LOG_BASE;
|
|
2002
|
-
if (i < len) {
|
|
2003
|
-
if (i) x.c.push(+str.slice(0, i));
|
|
2004
|
-
for (len -= LOG_BASE; i < len; ) {
|
|
2005
|
-
x.c.push(+str.slice(i, i += LOG_BASE));
|
|
2006
|
-
}
|
|
2007
|
-
i = LOG_BASE - (str = str.slice(i)).length;
|
|
2008
|
-
} else {
|
|
2009
|
-
i -= len;
|
|
2010
|
-
}
|
|
2011
|
-
for (; i--; str += "0") ;
|
|
2012
|
-
x.c.push(+str);
|
|
2013
|
-
}
|
|
2014
|
-
} else {
|
|
2015
|
-
x.c = [x.e = 0];
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
2018
|
-
BigNumber2.clone = clone;
|
|
2019
|
-
BigNumber2.ROUND_UP = 0;
|
|
2020
|
-
BigNumber2.ROUND_DOWN = 1;
|
|
2021
|
-
BigNumber2.ROUND_CEIL = 2;
|
|
2022
|
-
BigNumber2.ROUND_FLOOR = 3;
|
|
2023
|
-
BigNumber2.ROUND_HALF_UP = 4;
|
|
2024
|
-
BigNumber2.ROUND_HALF_DOWN = 5;
|
|
2025
|
-
BigNumber2.ROUND_HALF_EVEN = 6;
|
|
2026
|
-
BigNumber2.ROUND_HALF_CEIL = 7;
|
|
2027
|
-
BigNumber2.ROUND_HALF_FLOOR = 8;
|
|
2028
|
-
BigNumber2.EUCLID = 9;
|
|
2029
|
-
BigNumber2.config = BigNumber2.set = function(obj) {
|
|
2030
|
-
var p, v;
|
|
2031
|
-
if (obj != null) {
|
|
2032
|
-
if (typeof obj == "object") {
|
|
2033
|
-
if (obj.hasOwnProperty(p = "DECIMAL_PLACES")) {
|
|
2034
|
-
v = obj[p];
|
|
2035
|
-
intCheck(v, 0, MAX, p);
|
|
2036
|
-
DECIMAL_PLACES = v;
|
|
2037
|
-
}
|
|
2038
|
-
if (obj.hasOwnProperty(p = "ROUNDING_MODE")) {
|
|
2039
|
-
v = obj[p];
|
|
2040
|
-
intCheck(v, 0, 8, p);
|
|
2041
|
-
ROUNDING_MODE = v;
|
|
2042
|
-
}
|
|
2043
|
-
if (obj.hasOwnProperty(p = "EXPONENTIAL_AT")) {
|
|
2044
|
-
v = obj[p];
|
|
2045
|
-
if (v && v.pop) {
|
|
2046
|
-
intCheck(v[0], -MAX, 0, p);
|
|
2047
|
-
intCheck(v[1], 0, MAX, p);
|
|
2048
|
-
TO_EXP_NEG = v[0];
|
|
2049
|
-
TO_EXP_POS = v[1];
|
|
2050
|
-
} else {
|
|
2051
|
-
intCheck(v, -MAX, MAX, p);
|
|
2052
|
-
TO_EXP_NEG = -(TO_EXP_POS = v < 0 ? -v : v);
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
if (obj.hasOwnProperty(p = "RANGE")) {
|
|
2056
|
-
v = obj[p];
|
|
2057
|
-
if (v && v.pop) {
|
|
2058
|
-
intCheck(v[0], -MAX, -1, p);
|
|
2059
|
-
intCheck(v[1], 1, MAX, p);
|
|
2060
|
-
MIN_EXP = v[0];
|
|
2061
|
-
MAX_EXP = v[1];
|
|
2062
|
-
} else {
|
|
2063
|
-
intCheck(v, -MAX, MAX, p);
|
|
2064
|
-
if (v) {
|
|
2065
|
-
MIN_EXP = -(MAX_EXP = v < 0 ? -v : v);
|
|
2066
|
-
} else {
|
|
2067
|
-
throw Error(bignumberError + p + " cannot be zero: " + v);
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
if (obj.hasOwnProperty(p = "CRYPTO")) {
|
|
2072
|
-
v = obj[p];
|
|
2073
|
-
if (v === !!v) {
|
|
2074
|
-
if (v) {
|
|
2075
|
-
if (typeof crypto != "undefined" && crypto && (crypto.getRandomValues || crypto.randomBytes)) {
|
|
2076
|
-
CRYPTO = v;
|
|
2077
|
-
} else {
|
|
2078
|
-
CRYPTO = !v;
|
|
2079
|
-
throw Error(bignumberError + "crypto unavailable");
|
|
2080
|
-
}
|
|
2081
|
-
} else {
|
|
2082
|
-
CRYPTO = v;
|
|
2083
|
-
}
|
|
2084
|
-
} else {
|
|
2085
|
-
throw Error(bignumberError + p + " not true or false: " + v);
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
if (obj.hasOwnProperty(p = "MODULO_MODE")) {
|
|
2089
|
-
v = obj[p];
|
|
2090
|
-
intCheck(v, 0, 9, p);
|
|
2091
|
-
MODULO_MODE = v;
|
|
2092
|
-
}
|
|
2093
|
-
if (obj.hasOwnProperty(p = "POW_PRECISION")) {
|
|
2094
|
-
v = obj[p];
|
|
2095
|
-
intCheck(v, 0, MAX, p);
|
|
2096
|
-
POW_PRECISION = v;
|
|
2097
|
-
}
|
|
2098
|
-
if (obj.hasOwnProperty(p = "FORMAT")) {
|
|
2099
|
-
v = obj[p];
|
|
2100
|
-
if (typeof v == "object") FORMAT = v;
|
|
2101
|
-
else throw Error(bignumberError + p + " not an object: " + v);
|
|
2102
|
-
}
|
|
2103
|
-
if (obj.hasOwnProperty(p = "ALPHABET")) {
|
|
2104
|
-
v = obj[p];
|
|
2105
|
-
if (typeof v == "string" && !/^.?$|[+\-.\s]|(.).*\1/.test(v)) {
|
|
2106
|
-
alphabetHasNormalDecimalDigits = v.slice(0, 10) == "0123456789";
|
|
2107
|
-
ALPHABET = v;
|
|
2108
|
-
} else {
|
|
2109
|
-
throw Error(bignumberError + p + " invalid: " + v);
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
} else {
|
|
2113
|
-
throw Error(bignumberError + "Object expected: " + obj);
|
|
2114
|
-
}
|
|
2115
|
-
}
|
|
2116
|
-
return {
|
|
2117
|
-
DECIMAL_PLACES,
|
|
2118
|
-
ROUNDING_MODE,
|
|
2119
|
-
EXPONENTIAL_AT: [TO_EXP_NEG, TO_EXP_POS],
|
|
2120
|
-
RANGE: [MIN_EXP, MAX_EXP],
|
|
2121
|
-
CRYPTO,
|
|
2122
|
-
MODULO_MODE,
|
|
2123
|
-
POW_PRECISION,
|
|
2124
|
-
FORMAT,
|
|
2125
|
-
ALPHABET
|
|
2126
|
-
};
|
|
2127
|
-
};
|
|
2128
|
-
BigNumber2.isBigNumber = function(v) {
|
|
2129
|
-
if (!v || v._isBigNumber !== true) return false;
|
|
2130
|
-
if (!BigNumber2.DEBUG) return true;
|
|
2131
|
-
var i, n, c = v.c, e = v.e, s = v.s;
|
|
2132
|
-
out: if ({}.toString.call(c) == "[object Array]") {
|
|
2133
|
-
if ((s === 1 || s === -1) && e >= -MAX && e <= MAX && e === mathfloor(e)) {
|
|
2134
|
-
if (c[0] === 0) {
|
|
2135
|
-
if (e === 0 && c.length === 1) return true;
|
|
2136
|
-
break out;
|
|
2137
|
-
}
|
|
2138
|
-
i = (e + 1) % LOG_BASE;
|
|
2139
|
-
if (i < 1) i += LOG_BASE;
|
|
2140
|
-
if (String(c[0]).length == i) {
|
|
2141
|
-
for (i = 0; i < c.length; i++) {
|
|
2142
|
-
n = c[i];
|
|
2143
|
-
if (n < 0 || n >= BASE || n !== mathfloor(n)) break out;
|
|
2144
|
-
}
|
|
2145
|
-
if (n !== 0) return true;
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
} else if (c === null && e === null && (s === null || s === 1 || s === -1)) {
|
|
2149
|
-
return true;
|
|
2150
|
-
}
|
|
2151
|
-
throw Error(bignumberError + "Invalid BigNumber: " + v);
|
|
2152
|
-
};
|
|
2153
|
-
BigNumber2.maximum = BigNumber2.max = function() {
|
|
2154
|
-
return maxOrMin(arguments, -1);
|
|
2155
|
-
};
|
|
2156
|
-
BigNumber2.minimum = BigNumber2.min = function() {
|
|
2157
|
-
return maxOrMin(arguments, 1);
|
|
2158
|
-
};
|
|
2159
|
-
BigNumber2.random = (function() {
|
|
2160
|
-
var pow2_53 = 9007199254740992;
|
|
2161
|
-
var random53bitInt = Math.random() * pow2_53 & 2097151 ? function() {
|
|
2162
|
-
return mathfloor(Math.random() * pow2_53);
|
|
2163
|
-
} : function() {
|
|
2164
|
-
return (Math.random() * 1073741824 | 0) * 8388608 + (Math.random() * 8388608 | 0);
|
|
2165
|
-
};
|
|
2166
|
-
return function(dp) {
|
|
2167
|
-
var a, b, e, k, v, i = 0, c = [], rand = new BigNumber2(ONE);
|
|
2168
|
-
if (dp == null) dp = DECIMAL_PLACES;
|
|
2169
|
-
else intCheck(dp, 0, MAX);
|
|
2170
|
-
k = mathceil(dp / LOG_BASE);
|
|
2171
|
-
if (CRYPTO) {
|
|
2172
|
-
if (crypto.getRandomValues) {
|
|
2173
|
-
a = crypto.getRandomValues(new Uint32Array(k *= 2));
|
|
2174
|
-
for (; i < k; ) {
|
|
2175
|
-
v = a[i] * 131072 + (a[i + 1] >>> 11);
|
|
2176
|
-
if (v >= 9e15) {
|
|
2177
|
-
b = crypto.getRandomValues(new Uint32Array(2));
|
|
2178
|
-
a[i] = b[0];
|
|
2179
|
-
a[i + 1] = b[1];
|
|
2180
|
-
} else {
|
|
2181
|
-
c.push(v % 1e14);
|
|
2182
|
-
i += 2;
|
|
2183
|
-
}
|
|
2184
|
-
}
|
|
2185
|
-
i = k / 2;
|
|
2186
|
-
} else if (crypto.randomBytes) {
|
|
2187
|
-
a = crypto.randomBytes(k *= 7);
|
|
2188
|
-
for (; i < k; ) {
|
|
2189
|
-
v = (a[i] & 31) * 281474976710656 + a[i + 1] * 1099511627776 + a[i + 2] * 4294967296 + a[i + 3] * 16777216 + (a[i + 4] << 16) + (a[i + 5] << 8) + a[i + 6];
|
|
2190
|
-
if (v >= 9e15) {
|
|
2191
|
-
crypto.randomBytes(7).copy(a, i);
|
|
2192
|
-
} else {
|
|
2193
|
-
c.push(v % 1e14);
|
|
2194
|
-
i += 7;
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
i = k / 7;
|
|
2198
|
-
} else {
|
|
2199
|
-
CRYPTO = false;
|
|
2200
|
-
throw Error(bignumberError + "crypto unavailable");
|
|
2201
|
-
}
|
|
2202
|
-
}
|
|
2203
|
-
if (!CRYPTO) {
|
|
2204
|
-
for (; i < k; ) {
|
|
2205
|
-
v = random53bitInt();
|
|
2206
|
-
if (v < 9e15) c[i++] = v % 1e14;
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
k = c[--i];
|
|
2210
|
-
dp %= LOG_BASE;
|
|
2211
|
-
if (k && dp) {
|
|
2212
|
-
v = POWS_TEN[LOG_BASE - dp];
|
|
2213
|
-
c[i] = mathfloor(k / v) * v;
|
|
2214
|
-
}
|
|
2215
|
-
for (; c[i] === 0; c.pop(), i--) ;
|
|
2216
|
-
if (i < 0) {
|
|
2217
|
-
c = [e = 0];
|
|
2218
|
-
} else {
|
|
2219
|
-
for (e = -1; c[0] === 0; c.splice(0, 1), e -= LOG_BASE) ;
|
|
2220
|
-
for (i = 1, v = c[0]; v >= 10; v /= 10, i++) ;
|
|
2221
|
-
if (i < LOG_BASE) e -= LOG_BASE - i;
|
|
2222
|
-
}
|
|
2223
|
-
rand.e = e;
|
|
2224
|
-
rand.c = c;
|
|
2225
|
-
return rand;
|
|
2226
|
-
};
|
|
2227
|
-
})();
|
|
2228
|
-
BigNumber2.sum = function() {
|
|
2229
|
-
var i = 1, args = arguments, sum = new BigNumber2(args[0]);
|
|
2230
|
-
for (; i < args.length; ) sum = sum.plus(args[i++]);
|
|
2231
|
-
return sum;
|
|
2232
|
-
};
|
|
2233
|
-
convertBase = /* @__PURE__ */ (function() {
|
|
2234
|
-
var decimal = "0123456789";
|
|
2235
|
-
function toBaseOut(str, baseIn, baseOut, alphabet2) {
|
|
2236
|
-
var j, arr = [0], arrL, i = 0, len = str.length;
|
|
2237
|
-
for (; i < len; ) {
|
|
2238
|
-
for (arrL = arr.length; arrL--; arr[arrL] *= baseIn) ;
|
|
2239
|
-
arr[0] += alphabet2.indexOf(str.charAt(i++));
|
|
2240
|
-
for (j = 0; j < arr.length; j++) {
|
|
2241
|
-
if (arr[j] > baseOut - 1) {
|
|
2242
|
-
if (arr[j + 1] == null) arr[j + 1] = 0;
|
|
2243
|
-
arr[j + 1] += arr[j] / baseOut | 0;
|
|
2244
|
-
arr[j] %= baseOut;
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
return arr.reverse();
|
|
2249
|
-
}
|
|
2250
|
-
return function(str, baseIn, baseOut, sign, callerIsToString) {
|
|
2251
|
-
var alphabet2, d, e, k, r, x, xc, y, i = str.indexOf("."), dp = DECIMAL_PLACES, rm = ROUNDING_MODE;
|
|
2252
|
-
if (i >= 0) {
|
|
2253
|
-
k = POW_PRECISION;
|
|
2254
|
-
POW_PRECISION = 0;
|
|
2255
|
-
str = str.replace(".", "");
|
|
2256
|
-
y = new BigNumber2(baseIn);
|
|
2257
|
-
x = y.pow(str.length - i);
|
|
2258
|
-
POW_PRECISION = k;
|
|
2259
|
-
y.c = toBaseOut(
|
|
2260
|
-
toFixedPoint(coeffToString(x.c), x.e, "0"),
|
|
2261
|
-
10,
|
|
2262
|
-
baseOut,
|
|
2263
|
-
decimal
|
|
2264
|
-
);
|
|
2265
|
-
y.e = y.c.length;
|
|
2266
|
-
}
|
|
2267
|
-
xc = toBaseOut(str, baseIn, baseOut, callerIsToString ? (alphabet2 = ALPHABET, decimal) : (alphabet2 = decimal, ALPHABET));
|
|
2268
|
-
e = k = xc.length;
|
|
2269
|
-
for (; xc[--k] == 0; xc.pop()) ;
|
|
2270
|
-
if (!xc[0]) return alphabet2.charAt(0);
|
|
2271
|
-
if (i < 0) {
|
|
2272
|
-
--e;
|
|
2273
|
-
} else {
|
|
2274
|
-
x.c = xc;
|
|
2275
|
-
x.e = e;
|
|
2276
|
-
x.s = sign;
|
|
2277
|
-
x = div(x, y, dp, rm, baseOut);
|
|
2278
|
-
xc = x.c;
|
|
2279
|
-
r = x.r;
|
|
2280
|
-
e = x.e;
|
|
2281
|
-
}
|
|
2282
|
-
d = e + dp + 1;
|
|
2283
|
-
i = xc[d];
|
|
2284
|
-
k = baseOut / 2;
|
|
2285
|
-
r = r || d < 0 || xc[d + 1] != null;
|
|
2286
|
-
r = rm < 4 ? (i != null || r) && (rm == 0 || rm == (x.s < 0 ? 3 : 2)) : i > k || i == k && (rm == 4 || r || rm == 6 && xc[d - 1] & 1 || rm == (x.s < 0 ? 8 : 7));
|
|
2287
|
-
if (d < 1 || !xc[0]) {
|
|
2288
|
-
str = r ? toFixedPoint(alphabet2.charAt(1), -dp, alphabet2.charAt(0)) : alphabet2.charAt(0);
|
|
2289
|
-
} else {
|
|
2290
|
-
xc.length = d;
|
|
2291
|
-
if (r) {
|
|
2292
|
-
for (--baseOut; ++xc[--d] > baseOut; ) {
|
|
2293
|
-
xc[d] = 0;
|
|
2294
|
-
if (!d) {
|
|
2295
|
-
++e;
|
|
2296
|
-
xc = [1].concat(xc);
|
|
2297
|
-
}
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
for (k = xc.length; !xc[--k]; ) ;
|
|
2301
|
-
for (i = 0, str = ""; i <= k; str += alphabet2.charAt(xc[i++])) ;
|
|
2302
|
-
str = toFixedPoint(str, e, alphabet2.charAt(0));
|
|
2303
|
-
}
|
|
2304
|
-
return str;
|
|
2305
|
-
};
|
|
2306
|
-
})();
|
|
2307
|
-
div = /* @__PURE__ */ (function() {
|
|
2308
|
-
function multiply(x, k, base) {
|
|
2309
|
-
var m, temp, xlo, xhi, carry = 0, i = x.length, klo = k % SQRT_BASE, khi = k / SQRT_BASE | 0;
|
|
2310
|
-
for (x = x.slice(); i--; ) {
|
|
2311
|
-
xlo = x[i] % SQRT_BASE;
|
|
2312
|
-
xhi = x[i] / SQRT_BASE | 0;
|
|
2313
|
-
m = khi * xlo + xhi * klo;
|
|
2314
|
-
temp = klo * xlo + m % SQRT_BASE * SQRT_BASE + carry;
|
|
2315
|
-
carry = (temp / base | 0) + (m / SQRT_BASE | 0) + khi * xhi;
|
|
2316
|
-
x[i] = temp % base;
|
|
2317
|
-
}
|
|
2318
|
-
if (carry) x = [carry].concat(x);
|
|
2319
|
-
return x;
|
|
2320
|
-
}
|
|
2321
|
-
function compare2(a, b, aL, bL) {
|
|
2322
|
-
var i, cmp;
|
|
2323
|
-
if (aL != bL) {
|
|
2324
|
-
cmp = aL > bL ? 1 : -1;
|
|
2325
|
-
} else {
|
|
2326
|
-
for (i = cmp = 0; i < aL; i++) {
|
|
2327
|
-
if (a[i] != b[i]) {
|
|
2328
|
-
cmp = a[i] > b[i] ? 1 : -1;
|
|
2329
|
-
break;
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
return cmp;
|
|
2334
|
-
}
|
|
2335
|
-
function subtract(a, b, aL, base) {
|
|
2336
|
-
var i = 0;
|
|
2337
|
-
for (; aL--; ) {
|
|
2338
|
-
a[aL] -= i;
|
|
2339
|
-
i = a[aL] < b[aL] ? 1 : 0;
|
|
2340
|
-
a[aL] = i * base + a[aL] - b[aL];
|
|
2341
|
-
}
|
|
2342
|
-
for (; !a[0] && a.length > 1; a.splice(0, 1)) ;
|
|
2343
|
-
}
|
|
2344
|
-
return function(x, y, dp, rm, base) {
|
|
2345
|
-
var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0, yL, yz, s = x.s == y.s ? 1 : -1, xc = x.c, yc = y.c;
|
|
2346
|
-
if (!xc || !xc[0] || !yc || !yc[0]) {
|
|
2347
|
-
return new BigNumber2(
|
|
2348
|
-
// Return NaN if either NaN, or both Infinity or 0.
|
|
2349
|
-
!x.s || !y.s || (xc ? yc && xc[0] == yc[0] : !yc) ? NaN : (
|
|
2350
|
-
// Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0.
|
|
2351
|
-
xc && xc[0] == 0 || !yc ? s * 0 : s / 0
|
|
2352
|
-
)
|
|
2353
|
-
);
|
|
2354
|
-
}
|
|
2355
|
-
q = new BigNumber2(s);
|
|
2356
|
-
qc = q.c = [];
|
|
2357
|
-
e = x.e - y.e;
|
|
2358
|
-
s = dp + e + 1;
|
|
2359
|
-
if (!base) {
|
|
2360
|
-
base = BASE;
|
|
2361
|
-
e = bitFloor(x.e / LOG_BASE) - bitFloor(y.e / LOG_BASE);
|
|
2362
|
-
s = s / LOG_BASE | 0;
|
|
2363
|
-
}
|
|
2364
|
-
for (i = 0; yc[i] == (xc[i] || 0); i++) ;
|
|
2365
|
-
if (yc[i] > (xc[i] || 0)) e--;
|
|
2366
|
-
if (s < 0) {
|
|
2367
|
-
qc.push(1);
|
|
2368
|
-
more = true;
|
|
2369
|
-
} else {
|
|
2370
|
-
xL = xc.length;
|
|
2371
|
-
yL = yc.length;
|
|
2372
|
-
i = 0;
|
|
2373
|
-
s += 2;
|
|
2374
|
-
n = mathfloor(base / (yc[0] + 1));
|
|
2375
|
-
if (n > 1) {
|
|
2376
|
-
yc = multiply(yc, n, base);
|
|
2377
|
-
xc = multiply(xc, n, base);
|
|
2378
|
-
yL = yc.length;
|
|
2379
|
-
xL = xc.length;
|
|
2380
|
-
}
|
|
2381
|
-
xi = yL;
|
|
2382
|
-
rem = xc.slice(0, yL);
|
|
2383
|
-
remL = rem.length;
|
|
2384
|
-
for (; remL < yL; rem[remL++] = 0) ;
|
|
2385
|
-
yz = yc.slice();
|
|
2386
|
-
yz = [0].concat(yz);
|
|
2387
|
-
yc0 = yc[0];
|
|
2388
|
-
if (yc[1] >= base / 2) yc0++;
|
|
2389
|
-
do {
|
|
2390
|
-
n = 0;
|
|
2391
|
-
cmp = compare2(yc, rem, yL, remL);
|
|
2392
|
-
if (cmp < 0) {
|
|
2393
|
-
rem0 = rem[0];
|
|
2394
|
-
if (yL != remL) rem0 = rem0 * base + (rem[1] || 0);
|
|
2395
|
-
n = mathfloor(rem0 / yc0);
|
|
2396
|
-
if (n > 1) {
|
|
2397
|
-
if (n >= base) n = base - 1;
|
|
2398
|
-
prod = multiply(yc, n, base);
|
|
2399
|
-
prodL = prod.length;
|
|
2400
|
-
remL = rem.length;
|
|
2401
|
-
while (compare2(prod, rem, prodL, remL) == 1) {
|
|
2402
|
-
n--;
|
|
2403
|
-
subtract(prod, yL < prodL ? yz : yc, prodL, base);
|
|
2404
|
-
prodL = prod.length;
|
|
2405
|
-
cmp = 1;
|
|
2406
|
-
}
|
|
2407
|
-
} else {
|
|
2408
|
-
if (n == 0) {
|
|
2409
|
-
cmp = n = 1;
|
|
2410
|
-
}
|
|
2411
|
-
prod = yc.slice();
|
|
2412
|
-
prodL = prod.length;
|
|
2413
|
-
}
|
|
2414
|
-
if (prodL < remL) prod = [0].concat(prod);
|
|
2415
|
-
subtract(rem, prod, remL, base);
|
|
2416
|
-
remL = rem.length;
|
|
2417
|
-
if (cmp == -1) {
|
|
2418
|
-
while (compare2(yc, rem, yL, remL) < 1) {
|
|
2419
|
-
n++;
|
|
2420
|
-
subtract(rem, yL < remL ? yz : yc, remL, base);
|
|
2421
|
-
remL = rem.length;
|
|
2422
|
-
}
|
|
2423
|
-
}
|
|
2424
|
-
} else if (cmp === 0) {
|
|
2425
|
-
n++;
|
|
2426
|
-
rem = [0];
|
|
2427
|
-
}
|
|
2428
|
-
qc[i++] = n;
|
|
2429
|
-
if (rem[0]) {
|
|
2430
|
-
rem[remL++] = xc[xi] || 0;
|
|
2431
|
-
} else {
|
|
2432
|
-
rem = [xc[xi]];
|
|
2433
|
-
remL = 1;
|
|
2434
|
-
}
|
|
2435
|
-
} while ((xi++ < xL || rem[0] != null) && s--);
|
|
2436
|
-
more = rem[0] != null;
|
|
2437
|
-
if (!qc[0]) qc.splice(0, 1);
|
|
2438
|
-
}
|
|
2439
|
-
if (base == BASE) {
|
|
2440
|
-
for (i = 1, s = qc[0]; s >= 10; s /= 10, i++) ;
|
|
2441
|
-
round(q, dp + (q.e = i + e * LOG_BASE - 1) + 1, rm, more);
|
|
2442
|
-
} else {
|
|
2443
|
-
q.e = e;
|
|
2444
|
-
q.r = +more;
|
|
2445
|
-
}
|
|
2446
|
-
return q;
|
|
2447
|
-
};
|
|
2448
|
-
})();
|
|
2449
|
-
function format(n, i, rm, id) {
|
|
2450
|
-
var c0, e, ne, len, str;
|
|
2451
|
-
if (rm == null) rm = ROUNDING_MODE;
|
|
2452
|
-
else intCheck(rm, 0, 8);
|
|
2453
|
-
if (!n.c) return n.toString();
|
|
2454
|
-
c0 = n.c[0];
|
|
2455
|
-
ne = n.e;
|
|
2456
|
-
if (i == null) {
|
|
2457
|
-
str = coeffToString(n.c);
|
|
2458
|
-
str = id == 1 || id == 2 && (ne <= TO_EXP_NEG || ne >= TO_EXP_POS) ? toExponential(str, ne) : toFixedPoint(str, ne, "0");
|
|
2459
|
-
} else {
|
|
2460
|
-
n = round(new BigNumber2(n), i, rm);
|
|
2461
|
-
e = n.e;
|
|
2462
|
-
str = coeffToString(n.c);
|
|
2463
|
-
len = str.length;
|
|
2464
|
-
if (id == 1 || id == 2 && (i <= e || e <= TO_EXP_NEG)) {
|
|
2465
|
-
for (; len < i; str += "0", len++) ;
|
|
2466
|
-
str = toExponential(str, e);
|
|
2467
|
-
} else {
|
|
2468
|
-
i -= ne + (id === 2 && e > ne);
|
|
2469
|
-
str = toFixedPoint(str, e, "0");
|
|
2470
|
-
if (e + 1 > len) {
|
|
2471
|
-
if (--i > 0) for (str += "."; i--; str += "0") ;
|
|
2472
|
-
} else {
|
|
2473
|
-
i += e - len;
|
|
2474
|
-
if (i > 0) {
|
|
2475
|
-
if (e + 1 == len) str += ".";
|
|
2476
|
-
for (; i--; str += "0") ;
|
|
2477
|
-
}
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
|
-
return n.s < 0 && c0 ? "-" + str : str;
|
|
2482
|
-
}
|
|
2483
|
-
function maxOrMin(args, n) {
|
|
2484
|
-
var k, y, i = 1, x = new BigNumber2(args[0]);
|
|
2485
|
-
for (; i < args.length; i++) {
|
|
2486
|
-
y = new BigNumber2(args[i]);
|
|
2487
|
-
if (!y.s || (k = compare(x, y)) === n || k === 0 && x.s === n) {
|
|
2488
|
-
x = y;
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
return x;
|
|
2492
|
-
}
|
|
2493
|
-
function normalise(n, c, e) {
|
|
2494
|
-
var i = 1, j = c.length;
|
|
2495
|
-
for (; !c[--j]; c.pop()) ;
|
|
2496
|
-
for (j = c[0]; j >= 10; j /= 10, i++) ;
|
|
2497
|
-
if ((e = i + e * LOG_BASE - 1) > MAX_EXP) {
|
|
2498
|
-
n.c = n.e = null;
|
|
2499
|
-
} else if (e < MIN_EXP) {
|
|
2500
|
-
n.c = [n.e = 0];
|
|
2501
|
-
} else {
|
|
2502
|
-
n.e = e;
|
|
2503
|
-
n.c = c;
|
|
2504
|
-
}
|
|
2505
|
-
return n;
|
|
2506
|
-
}
|
|
2507
|
-
parseNumeric = /* @__PURE__ */ (function() {
|
|
2508
|
-
var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, dotAfter = /^([^.]+)\.$/, dotBefore = /^\.([^.]+)$/, isInfinityOrNaN = /^-?(Infinity|NaN)$/, whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g;
|
|
2509
|
-
return function(x, str, isNum, b) {
|
|
2510
|
-
var base, s = isNum ? str : str.replace(whitespaceOrPlus, "");
|
|
2511
|
-
if (isInfinityOrNaN.test(s)) {
|
|
2512
|
-
x.s = isNaN(s) ? null : s < 0 ? -1 : 1;
|
|
2513
|
-
} else {
|
|
2514
|
-
if (!isNum) {
|
|
2515
|
-
s = s.replace(basePrefix, function(m, p1, p2) {
|
|
2516
|
-
base = (p2 = p2.toLowerCase()) == "x" ? 16 : p2 == "b" ? 2 : 8;
|
|
2517
|
-
return !b || b == base ? p1 : m;
|
|
2518
|
-
});
|
|
2519
|
-
if (b) {
|
|
2520
|
-
base = b;
|
|
2521
|
-
s = s.replace(dotAfter, "$1").replace(dotBefore, "0.$1");
|
|
2522
|
-
}
|
|
2523
|
-
if (str != s) return new BigNumber2(s, base);
|
|
2524
|
-
}
|
|
2525
|
-
if (BigNumber2.DEBUG) {
|
|
2526
|
-
throw Error(bignumberError + "Not a" + (b ? " base " + b : "") + " number: " + str);
|
|
2527
|
-
}
|
|
2528
|
-
x.s = null;
|
|
2529
|
-
}
|
|
2530
|
-
x.c = x.e = null;
|
|
2531
|
-
};
|
|
2532
|
-
})();
|
|
2533
|
-
function round(x, sd, rm, r) {
|
|
2534
|
-
var d, i, j, k, n, ni, rd, xc = x.c, pows10 = POWS_TEN;
|
|
2535
|
-
if (xc) {
|
|
2536
|
-
out: {
|
|
2537
|
-
for (d = 1, k = xc[0]; k >= 10; k /= 10, d++) ;
|
|
2538
|
-
i = sd - d;
|
|
2539
|
-
if (i < 0) {
|
|
2540
|
-
i += LOG_BASE;
|
|
2541
|
-
j = sd;
|
|
2542
|
-
n = xc[ni = 0];
|
|
2543
|
-
rd = mathfloor(n / pows10[d - j - 1] % 10);
|
|
2544
|
-
} else {
|
|
2545
|
-
ni = mathceil((i + 1) / LOG_BASE);
|
|
2546
|
-
if (ni >= xc.length) {
|
|
2547
|
-
if (r) {
|
|
2548
|
-
for (; xc.length <= ni; xc.push(0)) ;
|
|
2549
|
-
n = rd = 0;
|
|
2550
|
-
d = 1;
|
|
2551
|
-
i %= LOG_BASE;
|
|
2552
|
-
j = i - LOG_BASE + 1;
|
|
2553
|
-
} else {
|
|
2554
|
-
break out;
|
|
2555
|
-
}
|
|
2556
|
-
} else {
|
|
2557
|
-
n = k = xc[ni];
|
|
2558
|
-
for (d = 1; k >= 10; k /= 10, d++) ;
|
|
2559
|
-
i %= LOG_BASE;
|
|
2560
|
-
j = i - LOG_BASE + d;
|
|
2561
|
-
rd = j < 0 ? 0 : mathfloor(n / pows10[d - j - 1] % 10);
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
r = r || sd < 0 || // Are there any non-zero digits after the rounding digit?
|
|
2565
|
-
// The expression n % pows10[d - j - 1] returns all digits of n to the right
|
|
2566
|
-
// of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714.
|
|
2567
|
-
xc[ni + 1] != null || (j < 0 ? n : n % pows10[d - j - 1]);
|
|
2568
|
-
r = rm < 4 ? (rd || r) && (rm == 0 || rm == (x.s < 0 ? 3 : 2)) : rd > 5 || rd == 5 && (rm == 4 || r || rm == 6 && // Check whether the digit to the left of the rounding digit is odd.
|
|
2569
|
-
(i > 0 ? j > 0 ? n / pows10[d - j] : 0 : xc[ni - 1]) % 10 & 1 || rm == (x.s < 0 ? 8 : 7));
|
|
2570
|
-
if (sd < 1 || !xc[0]) {
|
|
2571
|
-
xc.length = 0;
|
|
2572
|
-
if (r) {
|
|
2573
|
-
sd -= x.e + 1;
|
|
2574
|
-
xc[0] = pows10[(LOG_BASE - sd % LOG_BASE) % LOG_BASE];
|
|
2575
|
-
x.e = -sd || 0;
|
|
2576
|
-
} else {
|
|
2577
|
-
xc[0] = x.e = 0;
|
|
2578
|
-
}
|
|
2579
|
-
return x;
|
|
2580
|
-
}
|
|
2581
|
-
if (i == 0) {
|
|
2582
|
-
xc.length = ni;
|
|
2583
|
-
k = 1;
|
|
2584
|
-
ni--;
|
|
2585
|
-
} else {
|
|
2586
|
-
xc.length = ni + 1;
|
|
2587
|
-
k = pows10[LOG_BASE - i];
|
|
2588
|
-
xc[ni] = j > 0 ? mathfloor(n / pows10[d - j] % pows10[j]) * k : 0;
|
|
2589
|
-
}
|
|
2590
|
-
if (r) {
|
|
2591
|
-
for (; ; ) {
|
|
2592
|
-
if (ni == 0) {
|
|
2593
|
-
for (i = 1, j = xc[0]; j >= 10; j /= 10, i++) ;
|
|
2594
|
-
j = xc[0] += k;
|
|
2595
|
-
for (k = 1; j >= 10; j /= 10, k++) ;
|
|
2596
|
-
if (i != k) {
|
|
2597
|
-
x.e++;
|
|
2598
|
-
if (xc[0] == BASE) xc[0] = 1;
|
|
2599
|
-
}
|
|
2600
|
-
break;
|
|
2601
|
-
} else {
|
|
2602
|
-
xc[ni] += k;
|
|
2603
|
-
if (xc[ni] != BASE) break;
|
|
2604
|
-
xc[ni--] = 0;
|
|
2605
|
-
k = 1;
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
for (i = xc.length; xc[--i] === 0; xc.pop()) ;
|
|
2610
|
-
}
|
|
2611
|
-
if (x.e > MAX_EXP) {
|
|
2612
|
-
x.c = x.e = null;
|
|
2613
|
-
} else if (x.e < MIN_EXP) {
|
|
2614
|
-
x.c = [x.e = 0];
|
|
2615
|
-
}
|
|
2616
|
-
}
|
|
2617
|
-
return x;
|
|
2618
|
-
}
|
|
2619
|
-
function valueOf(n) {
|
|
2620
|
-
var str, e = n.e;
|
|
2621
|
-
if (e === null) return n.toString();
|
|
2622
|
-
str = coeffToString(n.c);
|
|
2623
|
-
str = e <= TO_EXP_NEG || e >= TO_EXP_POS ? toExponential(str, e) : toFixedPoint(str, e, "0");
|
|
2624
|
-
return n.s < 0 ? "-" + str : str;
|
|
2625
|
-
}
|
|
2626
|
-
P.absoluteValue = P.abs = function() {
|
|
2627
|
-
var x = new BigNumber2(this);
|
|
2628
|
-
if (x.s < 0) x.s = 1;
|
|
2629
|
-
return x;
|
|
2630
|
-
};
|
|
2631
|
-
P.comparedTo = function(y, b) {
|
|
2632
|
-
return compare(this, new BigNumber2(y, b));
|
|
2633
|
-
};
|
|
2634
|
-
P.decimalPlaces = P.dp = function(dp, rm) {
|
|
2635
|
-
var c, n, v, x = this;
|
|
2636
|
-
if (dp != null) {
|
|
2637
|
-
intCheck(dp, 0, MAX);
|
|
2638
|
-
if (rm == null) rm = ROUNDING_MODE;
|
|
2639
|
-
else intCheck(rm, 0, 8);
|
|
2640
|
-
return round(new BigNumber2(x), dp + x.e + 1, rm);
|
|
2641
|
-
}
|
|
2642
|
-
if (!(c = x.c)) return null;
|
|
2643
|
-
n = ((v = c.length - 1) - bitFloor(this.e / LOG_BASE)) * LOG_BASE;
|
|
2644
|
-
if (v = c[v]) for (; v % 10 == 0; v /= 10, n--) ;
|
|
2645
|
-
if (n < 0) n = 0;
|
|
2646
|
-
return n;
|
|
2647
|
-
};
|
|
2648
|
-
P.dividedBy = P.div = function(y, b) {
|
|
2649
|
-
return div(this, new BigNumber2(y, b), DECIMAL_PLACES, ROUNDING_MODE);
|
|
2650
|
-
};
|
|
2651
|
-
P.dividedToIntegerBy = P.idiv = function(y, b) {
|
|
2652
|
-
return div(this, new BigNumber2(y, b), 0, 1);
|
|
2653
|
-
};
|
|
2654
|
-
P.exponentiatedBy = P.pow = function(n, m) {
|
|
2655
|
-
var half, isModExp, i, k, more, nIsBig, nIsNeg, nIsOdd, y, x = this;
|
|
2656
|
-
n = new BigNumber2(n);
|
|
2657
|
-
if (n.c && !n.isInteger()) {
|
|
2658
|
-
throw Error(bignumberError + "Exponent not an integer: " + valueOf(n));
|
|
2659
|
-
}
|
|
2660
|
-
if (m != null) m = new BigNumber2(m);
|
|
2661
|
-
nIsBig = n.e > 14;
|
|
2662
|
-
if (!x.c || !x.c[0] || x.c[0] == 1 && !x.e && x.c.length == 1 || !n.c || !n.c[0]) {
|
|
2663
|
-
y = new BigNumber2(Math.pow(+valueOf(x), nIsBig ? n.s * (2 - isOdd(n)) : +valueOf(n)));
|
|
2664
|
-
return m ? y.mod(m) : y;
|
|
2665
|
-
}
|
|
2666
|
-
nIsNeg = n.s < 0;
|
|
2667
|
-
if (m) {
|
|
2668
|
-
if (m.c ? !m.c[0] : !m.s) return new BigNumber2(NaN);
|
|
2669
|
-
isModExp = !nIsNeg && x.isInteger() && m.isInteger();
|
|
2670
|
-
if (isModExp) x = x.mod(m);
|
|
2671
|
-
} else if (n.e > 9 && (x.e > 0 || x.e < -1 || (x.e == 0 ? x.c[0] > 1 || nIsBig && x.c[1] >= 24e7 : x.c[0] < 8e13 || nIsBig && x.c[0] <= 9999975e7))) {
|
|
2672
|
-
k = x.s < 0 && isOdd(n) ? -0 : 0;
|
|
2673
|
-
if (x.e > -1) k = 1 / k;
|
|
2674
|
-
return new BigNumber2(nIsNeg ? 1 / k : k);
|
|
2675
|
-
} else if (POW_PRECISION) {
|
|
2676
|
-
k = mathceil(POW_PRECISION / LOG_BASE + 2);
|
|
2677
|
-
}
|
|
2678
|
-
if (nIsBig) {
|
|
2679
|
-
half = new BigNumber2(0.5);
|
|
2680
|
-
if (nIsNeg) n.s = 1;
|
|
2681
|
-
nIsOdd = isOdd(n);
|
|
2682
|
-
} else {
|
|
2683
|
-
i = Math.abs(+valueOf(n));
|
|
2684
|
-
nIsOdd = i % 2;
|
|
2685
|
-
}
|
|
2686
|
-
y = new BigNumber2(ONE);
|
|
2687
|
-
for (; ; ) {
|
|
2688
|
-
if (nIsOdd) {
|
|
2689
|
-
y = y.times(x);
|
|
2690
|
-
if (!y.c) break;
|
|
2691
|
-
if (k) {
|
|
2692
|
-
if (y.c.length > k) y.c.length = k;
|
|
2693
|
-
} else if (isModExp) {
|
|
2694
|
-
y = y.mod(m);
|
|
2695
|
-
}
|
|
2696
|
-
}
|
|
2697
|
-
if (i) {
|
|
2698
|
-
i = mathfloor(i / 2);
|
|
2699
|
-
if (i === 0) break;
|
|
2700
|
-
nIsOdd = i % 2;
|
|
2701
|
-
} else {
|
|
2702
|
-
n = n.times(half);
|
|
2703
|
-
round(n, n.e + 1, 1);
|
|
2704
|
-
if (n.e > 14) {
|
|
2705
|
-
nIsOdd = isOdd(n);
|
|
2706
|
-
} else {
|
|
2707
|
-
i = +valueOf(n);
|
|
2708
|
-
if (i === 0) break;
|
|
2709
|
-
nIsOdd = i % 2;
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
x = x.times(x);
|
|
2713
|
-
if (k) {
|
|
2714
|
-
if (x.c && x.c.length > k) x.c.length = k;
|
|
2715
|
-
} else if (isModExp) {
|
|
2716
|
-
x = x.mod(m);
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
if (isModExp) return y;
|
|
2720
|
-
if (nIsNeg) y = ONE.div(y);
|
|
2721
|
-
return m ? y.mod(m) : k ? round(y, POW_PRECISION, ROUNDING_MODE, more) : y;
|
|
2722
|
-
};
|
|
2723
|
-
P.integerValue = function(rm) {
|
|
2724
|
-
var n = new BigNumber2(this);
|
|
2725
|
-
if (rm == null) rm = ROUNDING_MODE;
|
|
2726
|
-
else intCheck(rm, 0, 8);
|
|
2727
|
-
return round(n, n.e + 1, rm);
|
|
2728
|
-
};
|
|
2729
|
-
P.isEqualTo = P.eq = function(y, b) {
|
|
2730
|
-
return compare(this, new BigNumber2(y, b)) === 0;
|
|
2731
|
-
};
|
|
2732
|
-
P.isFinite = function() {
|
|
2733
|
-
return !!this.c;
|
|
2734
|
-
};
|
|
2735
|
-
P.isGreaterThan = P.gt = function(y, b) {
|
|
2736
|
-
return compare(this, new BigNumber2(y, b)) > 0;
|
|
2737
|
-
};
|
|
2738
|
-
P.isGreaterThanOrEqualTo = P.gte = function(y, b) {
|
|
2739
|
-
return (b = compare(this, new BigNumber2(y, b))) === 1 || b === 0;
|
|
2740
|
-
};
|
|
2741
|
-
P.isInteger = function() {
|
|
2742
|
-
return !!this.c && bitFloor(this.e / LOG_BASE) > this.c.length - 2;
|
|
2743
|
-
};
|
|
2744
|
-
P.isLessThan = P.lt = function(y, b) {
|
|
2745
|
-
return compare(this, new BigNumber2(y, b)) < 0;
|
|
2746
|
-
};
|
|
2747
|
-
P.isLessThanOrEqualTo = P.lte = function(y, b) {
|
|
2748
|
-
return (b = compare(this, new BigNumber2(y, b))) === -1 || b === 0;
|
|
2749
|
-
};
|
|
2750
|
-
P.isNaN = function() {
|
|
2751
|
-
return !this.s;
|
|
2752
|
-
};
|
|
2753
|
-
P.isNegative = function() {
|
|
2754
|
-
return this.s < 0;
|
|
2755
|
-
};
|
|
2756
|
-
P.isPositive = function() {
|
|
2757
|
-
return this.s > 0;
|
|
2758
|
-
};
|
|
2759
|
-
P.isZero = function() {
|
|
2760
|
-
return !!this.c && this.c[0] == 0;
|
|
2761
|
-
};
|
|
2762
|
-
P.minus = function(y, b) {
|
|
2763
|
-
var i, j, t, xLTy, x = this, a = x.s;
|
|
2764
|
-
y = new BigNumber2(y, b);
|
|
2765
|
-
b = y.s;
|
|
2766
|
-
if (!a || !b) return new BigNumber2(NaN);
|
|
2767
|
-
if (a != b) {
|
|
2768
|
-
y.s = -b;
|
|
2769
|
-
return x.plus(y);
|
|
2770
|
-
}
|
|
2771
|
-
var xe = x.e / LOG_BASE, ye = y.e / LOG_BASE, xc = x.c, yc = y.c;
|
|
2772
|
-
if (!xe || !ye) {
|
|
2773
|
-
if (!xc || !yc) return xc ? (y.s = -b, y) : new BigNumber2(yc ? x : NaN);
|
|
2774
|
-
if (!xc[0] || !yc[0]) {
|
|
2775
|
-
return yc[0] ? (y.s = -b, y) : new BigNumber2(xc[0] ? x : (
|
|
2776
|
-
// IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity
|
|
2777
|
-
ROUNDING_MODE == 3 ? -0 : 0
|
|
2778
|
-
));
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
xe = bitFloor(xe);
|
|
2782
|
-
ye = bitFloor(ye);
|
|
2783
|
-
xc = xc.slice();
|
|
2784
|
-
if (a = xe - ye) {
|
|
2785
|
-
if (xLTy = a < 0) {
|
|
2786
|
-
a = -a;
|
|
2787
|
-
t = xc;
|
|
2788
|
-
} else {
|
|
2789
|
-
ye = xe;
|
|
2790
|
-
t = yc;
|
|
2791
|
-
}
|
|
2792
|
-
t.reverse();
|
|
2793
|
-
for (b = a; b--; t.push(0)) ;
|
|
2794
|
-
t.reverse();
|
|
2795
|
-
} else {
|
|
2796
|
-
j = (xLTy = (a = xc.length) < (b = yc.length)) ? a : b;
|
|
2797
|
-
for (a = b = 0; b < j; b++) {
|
|
2798
|
-
if (xc[b] != yc[b]) {
|
|
2799
|
-
xLTy = xc[b] < yc[b];
|
|
2800
|
-
break;
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
if (xLTy) {
|
|
2805
|
-
t = xc;
|
|
2806
|
-
xc = yc;
|
|
2807
|
-
yc = t;
|
|
2808
|
-
y.s = -y.s;
|
|
2809
|
-
}
|
|
2810
|
-
b = (j = yc.length) - (i = xc.length);
|
|
2811
|
-
if (b > 0) for (; b--; xc[i++] = 0) ;
|
|
2812
|
-
b = BASE - 1;
|
|
2813
|
-
for (; j > a; ) {
|
|
2814
|
-
if (xc[--j] < yc[j]) {
|
|
2815
|
-
for (i = j; i && !xc[--i]; xc[i] = b) ;
|
|
2816
|
-
--xc[i];
|
|
2817
|
-
xc[j] += BASE;
|
|
2818
|
-
}
|
|
2819
|
-
xc[j] -= yc[j];
|
|
2820
|
-
}
|
|
2821
|
-
for (; xc[0] == 0; xc.splice(0, 1), --ye) ;
|
|
2822
|
-
if (!xc[0]) {
|
|
2823
|
-
y.s = ROUNDING_MODE == 3 ? -1 : 1;
|
|
2824
|
-
y.c = [y.e = 0];
|
|
2825
|
-
return y;
|
|
2826
|
-
}
|
|
2827
|
-
return normalise(y, xc, ye);
|
|
2828
|
-
};
|
|
2829
|
-
P.modulo = P.mod = function(y, b) {
|
|
2830
|
-
var q, s, x = this;
|
|
2831
|
-
y = new BigNumber2(y, b);
|
|
2832
|
-
if (!x.c || !y.s || y.c && !y.c[0]) {
|
|
2833
|
-
return new BigNumber2(NaN);
|
|
2834
|
-
} else if (!y.c || x.c && !x.c[0]) {
|
|
2835
|
-
return new BigNumber2(x);
|
|
2836
|
-
}
|
|
2837
|
-
if (MODULO_MODE == 9) {
|
|
2838
|
-
s = y.s;
|
|
2839
|
-
y.s = 1;
|
|
2840
|
-
q = div(x, y, 0, 3);
|
|
2841
|
-
y.s = s;
|
|
2842
|
-
q.s *= s;
|
|
2843
|
-
} else {
|
|
2844
|
-
q = div(x, y, 0, MODULO_MODE);
|
|
2845
|
-
}
|
|
2846
|
-
y = x.minus(q.times(y));
|
|
2847
|
-
if (!y.c[0] && MODULO_MODE == 1) y.s = x.s;
|
|
2848
|
-
return y;
|
|
2849
|
-
};
|
|
2850
|
-
P.multipliedBy = P.times = function(y, b) {
|
|
2851
|
-
var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc, base, sqrtBase, x = this, xc = x.c, yc = (y = new BigNumber2(y, b)).c;
|
|
2852
|
-
if (!xc || !yc || !xc[0] || !yc[0]) {
|
|
2853
|
-
if (!x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc) {
|
|
2854
|
-
y.c = y.e = y.s = null;
|
|
2855
|
-
} else {
|
|
2856
|
-
y.s *= x.s;
|
|
2857
|
-
if (!xc || !yc) {
|
|
2858
|
-
y.c = y.e = null;
|
|
2859
|
-
} else {
|
|
2860
|
-
y.c = [0];
|
|
2861
|
-
y.e = 0;
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
return y;
|
|
2865
|
-
}
|
|
2866
|
-
e = bitFloor(x.e / LOG_BASE) + bitFloor(y.e / LOG_BASE);
|
|
2867
|
-
y.s *= x.s;
|
|
2868
|
-
xcL = xc.length;
|
|
2869
|
-
ycL = yc.length;
|
|
2870
|
-
if (xcL < ycL) {
|
|
2871
|
-
zc = xc;
|
|
2872
|
-
xc = yc;
|
|
2873
|
-
yc = zc;
|
|
2874
|
-
i = xcL;
|
|
2875
|
-
xcL = ycL;
|
|
2876
|
-
ycL = i;
|
|
2877
|
-
}
|
|
2878
|
-
for (i = xcL + ycL, zc = []; i--; zc.push(0)) ;
|
|
2879
|
-
base = BASE;
|
|
2880
|
-
sqrtBase = SQRT_BASE;
|
|
2881
|
-
for (i = ycL; --i >= 0; ) {
|
|
2882
|
-
c = 0;
|
|
2883
|
-
ylo = yc[i] % sqrtBase;
|
|
2884
|
-
yhi = yc[i] / sqrtBase | 0;
|
|
2885
|
-
for (k = xcL, j = i + k; j > i; ) {
|
|
2886
|
-
xlo = xc[--k] % sqrtBase;
|
|
2887
|
-
xhi = xc[k] / sqrtBase | 0;
|
|
2888
|
-
m = yhi * xlo + xhi * ylo;
|
|
2889
|
-
xlo = ylo * xlo + m % sqrtBase * sqrtBase + zc[j] + c;
|
|
2890
|
-
c = (xlo / base | 0) + (m / sqrtBase | 0) + yhi * xhi;
|
|
2891
|
-
zc[j--] = xlo % base;
|
|
2892
|
-
}
|
|
2893
|
-
zc[j] = c;
|
|
2894
|
-
}
|
|
2895
|
-
if (c) {
|
|
2896
|
-
++e;
|
|
2897
|
-
} else {
|
|
2898
|
-
zc.splice(0, 1);
|
|
2899
|
-
}
|
|
2900
|
-
return normalise(y, zc, e);
|
|
2901
|
-
};
|
|
2902
|
-
P.negated = function() {
|
|
2903
|
-
var x = new BigNumber2(this);
|
|
2904
|
-
x.s = -x.s || null;
|
|
2905
|
-
return x;
|
|
2906
|
-
};
|
|
2907
|
-
P.plus = function(y, b) {
|
|
2908
|
-
var t, x = this, a = x.s;
|
|
2909
|
-
y = new BigNumber2(y, b);
|
|
2910
|
-
b = y.s;
|
|
2911
|
-
if (!a || !b) return new BigNumber2(NaN);
|
|
2912
|
-
if (a != b) {
|
|
2913
|
-
y.s = -b;
|
|
2914
|
-
return x.minus(y);
|
|
2915
|
-
}
|
|
2916
|
-
var xe = x.e / LOG_BASE, ye = y.e / LOG_BASE, xc = x.c, yc = y.c;
|
|
2917
|
-
if (!xe || !ye) {
|
|
2918
|
-
if (!xc || !yc) return new BigNumber2(a / 0);
|
|
2919
|
-
if (!xc[0] || !yc[0]) return yc[0] ? y : new BigNumber2(xc[0] ? x : a * 0);
|
|
2920
|
-
}
|
|
2921
|
-
xe = bitFloor(xe);
|
|
2922
|
-
ye = bitFloor(ye);
|
|
2923
|
-
xc = xc.slice();
|
|
2924
|
-
if (a = xe - ye) {
|
|
2925
|
-
if (a > 0) {
|
|
2926
|
-
ye = xe;
|
|
2927
|
-
t = yc;
|
|
2928
|
-
} else {
|
|
2929
|
-
a = -a;
|
|
2930
|
-
t = xc;
|
|
2931
|
-
}
|
|
2932
|
-
t.reverse();
|
|
2933
|
-
for (; a--; t.push(0)) ;
|
|
2934
|
-
t.reverse();
|
|
2935
|
-
}
|
|
2936
|
-
a = xc.length;
|
|
2937
|
-
b = yc.length;
|
|
2938
|
-
if (a - b < 0) {
|
|
2939
|
-
t = yc;
|
|
2940
|
-
yc = xc;
|
|
2941
|
-
xc = t;
|
|
2942
|
-
b = a;
|
|
2943
|
-
}
|
|
2944
|
-
for (a = 0; b; ) {
|
|
2945
|
-
a = (xc[--b] = xc[b] + yc[b] + a) / BASE | 0;
|
|
2946
|
-
xc[b] = BASE === xc[b] ? 0 : xc[b] % BASE;
|
|
2947
|
-
}
|
|
2948
|
-
if (a) {
|
|
2949
|
-
xc = [a].concat(xc);
|
|
2950
|
-
++ye;
|
|
2951
|
-
}
|
|
2952
|
-
return normalise(y, xc, ye);
|
|
2953
|
-
};
|
|
2954
|
-
P.precision = P.sd = function(sd, rm) {
|
|
2955
|
-
var c, n, v, x = this;
|
|
2956
|
-
if (sd != null && sd !== !!sd) {
|
|
2957
|
-
intCheck(sd, 1, MAX);
|
|
2958
|
-
if (rm == null) rm = ROUNDING_MODE;
|
|
2959
|
-
else intCheck(rm, 0, 8);
|
|
2960
|
-
return round(new BigNumber2(x), sd, rm);
|
|
2961
|
-
}
|
|
2962
|
-
if (!(c = x.c)) return null;
|
|
2963
|
-
v = c.length - 1;
|
|
2964
|
-
n = v * LOG_BASE + 1;
|
|
2965
|
-
if (v = c[v]) {
|
|
2966
|
-
for (; v % 10 == 0; v /= 10, n--) ;
|
|
2967
|
-
for (v = c[0]; v >= 10; v /= 10, n++) ;
|
|
2968
|
-
}
|
|
2969
|
-
if (sd && x.e + 1 > n) n = x.e + 1;
|
|
2970
|
-
return n;
|
|
2971
|
-
};
|
|
2972
|
-
P.shiftedBy = function(k) {
|
|
2973
|
-
intCheck(k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER);
|
|
2974
|
-
return this.times("1e" + k);
|
|
2975
|
-
};
|
|
2976
|
-
P.squareRoot = P.sqrt = function() {
|
|
2977
|
-
var m, n, r, rep, t, x = this, c = x.c, s = x.s, e = x.e, dp = DECIMAL_PLACES + 4, half = new BigNumber2("0.5");
|
|
2978
|
-
if (s !== 1 || !c || !c[0]) {
|
|
2979
|
-
return new BigNumber2(!s || s < 0 && (!c || c[0]) ? NaN : c ? x : 1 / 0);
|
|
2980
|
-
}
|
|
2981
|
-
s = Math.sqrt(+valueOf(x));
|
|
2982
|
-
if (s == 0 || s == 1 / 0) {
|
|
2983
|
-
n = coeffToString(c);
|
|
2984
|
-
if ((n.length + e) % 2 == 0) n += "0";
|
|
2985
|
-
s = Math.sqrt(+n);
|
|
2986
|
-
e = bitFloor((e + 1) / 2) - (e < 0 || e % 2);
|
|
2987
|
-
if (s == 1 / 0) {
|
|
2988
|
-
n = "5e" + e;
|
|
2989
|
-
} else {
|
|
2990
|
-
n = s.toExponential();
|
|
2991
|
-
n = n.slice(0, n.indexOf("e") + 1) + e;
|
|
2992
|
-
}
|
|
2993
|
-
r = new BigNumber2(n);
|
|
2994
|
-
} else {
|
|
2995
|
-
r = new BigNumber2(s + "");
|
|
2996
|
-
}
|
|
2997
|
-
if (r.c[0]) {
|
|
2998
|
-
e = r.e;
|
|
2999
|
-
s = e + dp;
|
|
3000
|
-
if (s < 3) s = 0;
|
|
3001
|
-
for (; ; ) {
|
|
3002
|
-
t = r;
|
|
3003
|
-
r = half.times(t.plus(div(x, t, dp, 1)));
|
|
3004
|
-
if (coeffToString(t.c).slice(0, s) === (n = coeffToString(r.c)).slice(0, s)) {
|
|
3005
|
-
if (r.e < e) --s;
|
|
3006
|
-
n = n.slice(s - 3, s + 1);
|
|
3007
|
-
if (n == "9999" || !rep && n == "4999") {
|
|
3008
|
-
if (!rep) {
|
|
3009
|
-
round(t, t.e + DECIMAL_PLACES + 2, 0);
|
|
3010
|
-
if (t.times(t).eq(x)) {
|
|
3011
|
-
r = t;
|
|
3012
|
-
break;
|
|
3013
|
-
}
|
|
3014
|
-
}
|
|
3015
|
-
dp += 4;
|
|
3016
|
-
s += 4;
|
|
3017
|
-
rep = 1;
|
|
3018
|
-
} else {
|
|
3019
|
-
if (!+n || !+n.slice(1) && n.charAt(0) == "5") {
|
|
3020
|
-
round(r, r.e + DECIMAL_PLACES + 2, 1);
|
|
3021
|
-
m = !r.times(r).eq(x);
|
|
3022
|
-
}
|
|
3023
|
-
break;
|
|
3024
|
-
}
|
|
3025
|
-
}
|
|
3026
|
-
}
|
|
3027
|
-
}
|
|
3028
|
-
return round(r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m);
|
|
3029
|
-
};
|
|
3030
|
-
P.toExponential = function(dp, rm) {
|
|
3031
|
-
if (dp != null) {
|
|
3032
|
-
intCheck(dp, 0, MAX);
|
|
3033
|
-
dp++;
|
|
3034
|
-
}
|
|
3035
|
-
return format(this, dp, rm, 1);
|
|
3036
|
-
};
|
|
3037
|
-
P.toFixed = function(dp, rm) {
|
|
3038
|
-
if (dp != null) {
|
|
3039
|
-
intCheck(dp, 0, MAX);
|
|
3040
|
-
dp = dp + this.e + 1;
|
|
3041
|
-
}
|
|
3042
|
-
return format(this, dp, rm);
|
|
3043
|
-
};
|
|
3044
|
-
P.toFormat = function(dp, rm, format2) {
|
|
3045
|
-
var str, x = this;
|
|
3046
|
-
if (format2 == null) {
|
|
3047
|
-
if (dp != null && rm && typeof rm == "object") {
|
|
3048
|
-
format2 = rm;
|
|
3049
|
-
rm = null;
|
|
3050
|
-
} else if (dp && typeof dp == "object") {
|
|
3051
|
-
format2 = dp;
|
|
3052
|
-
dp = rm = null;
|
|
3053
|
-
} else {
|
|
3054
|
-
format2 = FORMAT;
|
|
3055
|
-
}
|
|
3056
|
-
} else if (typeof format2 != "object") {
|
|
3057
|
-
throw Error(bignumberError + "Argument not an object: " + format2);
|
|
3058
|
-
}
|
|
3059
|
-
str = x.toFixed(dp, rm);
|
|
3060
|
-
if (x.c) {
|
|
3061
|
-
var i, arr = str.split("."), g1 = +format2.groupSize, g2 = +format2.secondaryGroupSize, groupSeparator = format2.groupSeparator || "", intPart = arr[0], fractionPart = arr[1], isNeg = x.s < 0, intDigits = isNeg ? intPart.slice(1) : intPart, len = intDigits.length;
|
|
3062
|
-
if (g2) {
|
|
3063
|
-
i = g1;
|
|
3064
|
-
g1 = g2;
|
|
3065
|
-
g2 = i;
|
|
3066
|
-
len -= i;
|
|
3067
|
-
}
|
|
3068
|
-
if (g1 > 0 && len > 0) {
|
|
3069
|
-
i = len % g1 || g1;
|
|
3070
|
-
intPart = intDigits.substr(0, i);
|
|
3071
|
-
for (; i < len; i += g1) intPart += groupSeparator + intDigits.substr(i, g1);
|
|
3072
|
-
if (g2 > 0) intPart += groupSeparator + intDigits.slice(i);
|
|
3073
|
-
if (isNeg) intPart = "-" + intPart;
|
|
3074
|
-
}
|
|
3075
|
-
str = fractionPart ? intPart + (format2.decimalSeparator || "") + ((g2 = +format2.fractionGroupSize) ? fractionPart.replace(
|
|
3076
|
-
new RegExp("\\d{" + g2 + "}\\B", "g"),
|
|
3077
|
-
"$&" + (format2.fractionGroupSeparator || "")
|
|
3078
|
-
) : fractionPart) : intPart;
|
|
3079
|
-
}
|
|
3080
|
-
return (format2.prefix || "") + str + (format2.suffix || "");
|
|
3081
|
-
};
|
|
3082
|
-
P.toFraction = function(md) {
|
|
3083
|
-
var d, d0, d1, d2, e, exp, n, n0, n1, q, r, s, x = this, xc = x.c;
|
|
3084
|
-
if (md != null) {
|
|
3085
|
-
n = new BigNumber2(md);
|
|
3086
|
-
if (!n.isInteger() && (n.c || n.s !== 1) || n.lt(ONE)) {
|
|
3087
|
-
throw Error(bignumberError + "Argument " + (n.isInteger() ? "out of range: " : "not an integer: ") + valueOf(n));
|
|
3088
|
-
}
|
|
3089
|
-
}
|
|
3090
|
-
if (!xc) return new BigNumber2(x);
|
|
3091
|
-
d = new BigNumber2(ONE);
|
|
3092
|
-
n1 = d0 = new BigNumber2(ONE);
|
|
3093
|
-
d1 = n0 = new BigNumber2(ONE);
|
|
3094
|
-
s = coeffToString(xc);
|
|
3095
|
-
e = d.e = s.length - x.e - 1;
|
|
3096
|
-
d.c[0] = POWS_TEN[(exp = e % LOG_BASE) < 0 ? LOG_BASE + exp : exp];
|
|
3097
|
-
md = !md || n.comparedTo(d) > 0 ? e > 0 ? d : n1 : n;
|
|
3098
|
-
exp = MAX_EXP;
|
|
3099
|
-
MAX_EXP = 1 / 0;
|
|
3100
|
-
n = new BigNumber2(s);
|
|
3101
|
-
n0.c[0] = 0;
|
|
3102
|
-
for (; ; ) {
|
|
3103
|
-
q = div(n, d, 0, 1);
|
|
3104
|
-
d2 = d0.plus(q.times(d1));
|
|
3105
|
-
if (d2.comparedTo(md) == 1) break;
|
|
3106
|
-
d0 = d1;
|
|
3107
|
-
d1 = d2;
|
|
3108
|
-
n1 = n0.plus(q.times(d2 = n1));
|
|
3109
|
-
n0 = d2;
|
|
3110
|
-
d = n.minus(q.times(d2 = d));
|
|
3111
|
-
n = d2;
|
|
3112
|
-
}
|
|
3113
|
-
d2 = div(md.minus(d0), d1, 0, 1);
|
|
3114
|
-
n0 = n0.plus(d2.times(n1));
|
|
3115
|
-
d0 = d0.plus(d2.times(d1));
|
|
3116
|
-
n0.s = n1.s = x.s;
|
|
3117
|
-
e = e * 2;
|
|
3118
|
-
r = div(n1, d1, e, ROUNDING_MODE).minus(x).abs().comparedTo(
|
|
3119
|
-
div(n0, d0, e, ROUNDING_MODE).minus(x).abs()
|
|
3120
|
-
) < 1 ? [n1, d1] : [n0, d0];
|
|
3121
|
-
MAX_EXP = exp;
|
|
3122
|
-
return r;
|
|
3123
|
-
};
|
|
3124
|
-
P.toNumber = function() {
|
|
3125
|
-
return +valueOf(this);
|
|
3126
|
-
};
|
|
3127
|
-
P.toPrecision = function(sd, rm) {
|
|
3128
|
-
if (sd != null) intCheck(sd, 1, MAX);
|
|
3129
|
-
return format(this, sd, rm, 2);
|
|
3130
|
-
};
|
|
3131
|
-
P.toString = function(b) {
|
|
3132
|
-
var str, n = this, s = n.s, e = n.e;
|
|
3133
|
-
if (e === null) {
|
|
3134
|
-
if (s) {
|
|
3135
|
-
str = "Infinity";
|
|
3136
|
-
if (s < 0) str = "-" + str;
|
|
3137
|
-
} else {
|
|
3138
|
-
str = "NaN";
|
|
3139
|
-
}
|
|
3140
|
-
} else {
|
|
3141
|
-
if (b == null) {
|
|
3142
|
-
str = e <= TO_EXP_NEG || e >= TO_EXP_POS ? toExponential(coeffToString(n.c), e) : toFixedPoint(coeffToString(n.c), e, "0");
|
|
3143
|
-
} else if (b === 10 && alphabetHasNormalDecimalDigits) {
|
|
3144
|
-
n = round(new BigNumber2(n), DECIMAL_PLACES + e + 1, ROUNDING_MODE);
|
|
3145
|
-
str = toFixedPoint(coeffToString(n.c), n.e, "0");
|
|
3146
|
-
} else {
|
|
3147
|
-
intCheck(b, 2, ALPHABET.length, "Base");
|
|
3148
|
-
str = convertBase(toFixedPoint(coeffToString(n.c), e, "0"), 10, b, s, true);
|
|
3149
|
-
}
|
|
3150
|
-
if (s < 0 && n.c[0]) str = "-" + str;
|
|
3151
|
-
}
|
|
3152
|
-
return str;
|
|
3153
|
-
};
|
|
3154
|
-
P.valueOf = P.toJSON = function() {
|
|
3155
|
-
return valueOf(this);
|
|
3156
|
-
};
|
|
3157
|
-
P._isBigNumber = true;
|
|
3158
|
-
P[Symbol.toStringTag] = "BigNumber";
|
|
3159
|
-
P[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = P.valueOf;
|
|
3160
|
-
if (configObject != null) BigNumber2.set(configObject);
|
|
3161
|
-
return BigNumber2;
|
|
3162
|
-
}
|
|
3163
|
-
function bitFloor(n) {
|
|
3164
|
-
var i = n | 0;
|
|
3165
|
-
return n > 0 || n === i ? i : i - 1;
|
|
3166
|
-
}
|
|
3167
|
-
function coeffToString(a) {
|
|
3168
|
-
var s, z, i = 1, j = a.length, r = a[0] + "";
|
|
3169
|
-
for (; i < j; ) {
|
|
3170
|
-
s = a[i++] + "";
|
|
3171
|
-
z = LOG_BASE - s.length;
|
|
3172
|
-
for (; z--; s = "0" + s) ;
|
|
3173
|
-
r += s;
|
|
3174
|
-
}
|
|
3175
|
-
for (j = r.length; r.charCodeAt(--j) === 48; ) ;
|
|
3176
|
-
return r.slice(0, j + 1 || 1);
|
|
3177
|
-
}
|
|
3178
|
-
function compare(x, y) {
|
|
3179
|
-
var a, b, xc = x.c, yc = y.c, i = x.s, j = y.s, k = x.e, l = y.e;
|
|
3180
|
-
if (!i || !j) return null;
|
|
3181
|
-
a = xc && !xc[0];
|
|
3182
|
-
b = yc && !yc[0];
|
|
3183
|
-
if (a || b) return a ? b ? 0 : -j : i;
|
|
3184
|
-
if (i != j) return i;
|
|
3185
|
-
a = i < 0;
|
|
3186
|
-
b = k == l;
|
|
3187
|
-
if (!xc || !yc) return b ? 0 : !xc ^ a ? 1 : -1;
|
|
3188
|
-
if (!b) return k > l ^ a ? 1 : -1;
|
|
3189
|
-
j = (k = xc.length) < (l = yc.length) ? k : l;
|
|
3190
|
-
for (i = 0; i < j; i++) if (xc[i] != yc[i]) return xc[i] > yc[i] ^ a ? 1 : -1;
|
|
3191
|
-
return k == l ? 0 : k > l ^ a ? 1 : -1;
|
|
3192
|
-
}
|
|
3193
|
-
function intCheck(n, min, max, name) {
|
|
3194
|
-
if (n < min || n > max || n !== mathfloor(n)) {
|
|
3195
|
-
throw Error(bignumberError + (name || "Argument") + (typeof n == "number" ? n < min || n > max ? " out of range: " : " not an integer: " : " not a primitive number: ") + String(n));
|
|
3196
|
-
}
|
|
3197
|
-
}
|
|
3198
|
-
function isOdd(n) {
|
|
3199
|
-
var k = n.c.length - 1;
|
|
3200
|
-
return bitFloor(n.e / LOG_BASE) == k && n.c[k] % 2 != 0;
|
|
3201
|
-
}
|
|
3202
|
-
function toExponential(str, e) {
|
|
3203
|
-
return (str.length > 1 ? str.charAt(0) + "." + str.slice(1) : str) + (e < 0 ? "e" : "e+") + e;
|
|
3204
|
-
}
|
|
3205
|
-
function toFixedPoint(str, e, z) {
|
|
3206
|
-
var len, zs;
|
|
3207
|
-
if (e < 0) {
|
|
3208
|
-
for (zs = z + "."; ++e; zs += z) ;
|
|
3209
|
-
str = zs + str;
|
|
3210
|
-
} else {
|
|
3211
|
-
len = str.length;
|
|
3212
|
-
if (++e > len) {
|
|
3213
|
-
for (zs = z, e -= len; --e; zs += z) ;
|
|
3214
|
-
str += zs;
|
|
3215
|
-
} else if (e < len) {
|
|
3216
|
-
str = str.slice(0, e) + "." + str.slice(e);
|
|
3217
|
-
}
|
|
3218
|
-
}
|
|
3219
|
-
return str;
|
|
3220
|
-
}
|
|
3221
|
-
var BigNumber = clone();
|
|
3222
|
-
var bignumber_default = BigNumber;
|
|
3223
|
-
|
|
3224
|
-
// ../../node_modules/.pnpm/@paralleldrive+cuid2@3.0.6/node_modules/@paralleldrive/cuid2/src/index.js
|
|
3225
|
-
var defaultLength = 24;
|
|
3226
|
-
var bigLength = 32;
|
|
3227
|
-
var createRandom = () => {
|
|
3228
|
-
if (typeof globalThis !== "undefined" && globalThis.crypto && typeof globalThis.crypto.getRandomValues === "function") {
|
|
3229
|
-
return () => {
|
|
3230
|
-
const buffer = new Uint32Array(1);
|
|
3231
|
-
globalThis.crypto.getRandomValues(buffer);
|
|
3232
|
-
return buffer[0] / 4294967296;
|
|
3233
|
-
};
|
|
3234
|
-
}
|
|
3235
|
-
return Math.random;
|
|
3236
|
-
};
|
|
3237
|
-
var random = createRandom();
|
|
3238
|
-
var createEntropy = (length = 4, rand = random) => {
|
|
3239
|
-
let entropy = "";
|
|
3240
|
-
while (entropy.length < length) {
|
|
3241
|
-
entropy = entropy + Math.floor(rand() * 36).toString(36);
|
|
3242
|
-
}
|
|
3243
|
-
return entropy;
|
|
3244
|
-
};
|
|
3245
|
-
function bufToBigInt(buf) {
|
|
3246
|
-
let value = new bignumber_default(0);
|
|
3247
|
-
for (const i of buf.values()) {
|
|
3248
|
-
value = value.multipliedBy(256).plus(i);
|
|
3249
|
-
}
|
|
3250
|
-
return value;
|
|
3251
|
-
}
|
|
3252
|
-
var hash = (input = "") => {
|
|
3253
|
-
const encoder = new TextEncoder();
|
|
3254
|
-
return bufToBigInt(sha3_512(encoder.encode(input))).toString(36).slice(1);
|
|
3255
|
-
};
|
|
3256
|
-
var alphabet = Array.from(
|
|
3257
|
-
{ length: 26 },
|
|
3258
|
-
(x, i) => String.fromCharCode(i + 97)
|
|
3259
|
-
);
|
|
3260
|
-
var randomLetter = (rand) => alphabet[Math.floor(rand() * alphabet.length)];
|
|
3261
|
-
var createFingerprint = ({
|
|
3262
|
-
globalObj = typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {},
|
|
3263
|
-
random: rand = random
|
|
3264
|
-
} = {}) => {
|
|
3265
|
-
const globals = Object.keys(globalObj).toString();
|
|
3266
|
-
const sourceString = globals.length ? globals + createEntropy(bigLength, rand) : createEntropy(bigLength, rand);
|
|
3267
|
-
return hash(sourceString).substring(0, bigLength);
|
|
3268
|
-
};
|
|
3269
|
-
var createCounter = (count) => () => {
|
|
3270
|
-
return count++;
|
|
3271
|
-
};
|
|
3272
|
-
var initialCountMax = 476782367;
|
|
3273
|
-
var init = ({
|
|
3274
|
-
// Fallback if the user does not pass in a CSPRNG. This should be OK
|
|
3275
|
-
// because we don't rely solely on the random number generator for entropy.
|
|
3276
|
-
// We also use the host fingerprint, current time, and a session counter.
|
|
3277
|
-
random: rand = random,
|
|
3278
|
-
counter = createCounter(Math.floor(rand() * initialCountMax)),
|
|
3279
|
-
length = defaultLength,
|
|
3280
|
-
fingerprint = createFingerprint({ random: rand })
|
|
3281
|
-
} = {}) => {
|
|
3282
|
-
if (length > bigLength) {
|
|
3283
|
-
throw new Error(
|
|
3284
|
-
`Length must be between 2 and ${bigLength}. Received: ${length}`
|
|
3285
|
-
);
|
|
3286
|
-
}
|
|
3287
|
-
return function cuid2() {
|
|
3288
|
-
const firstLetter = randomLetter(rand);
|
|
3289
|
-
const time = Date.now().toString(36);
|
|
3290
|
-
const count = counter().toString(36);
|
|
3291
|
-
const salt = createEntropy(length, rand);
|
|
3292
|
-
const hashInput = `${time + salt + count + fingerprint}`;
|
|
3293
|
-
return `${firstLetter + hash(hashInput).substring(1, length)}`;
|
|
3294
|
-
};
|
|
3295
|
-
};
|
|
3296
|
-
var createId = lazy(init);
|
|
3297
|
-
function lazy(fn) {
|
|
3298
|
-
let initialized;
|
|
3299
|
-
return () => {
|
|
3300
|
-
if (!initialized) {
|
|
3301
|
-
initialized = fn();
|
|
3302
|
-
}
|
|
3303
|
-
return initialized();
|
|
3304
|
-
};
|
|
3305
|
-
}
|
|
3306
|
-
var BaseAdapter = class {
|
|
3307
|
-
convertExpert(expert) {
|
|
3308
|
-
return { instruction: expert.instruction };
|
|
3309
|
-
}
|
|
3310
|
-
execCommand(args) {
|
|
3311
|
-
return new Promise((resolve2) => {
|
|
3312
|
-
const [cmd, ...cmdArgs] = args;
|
|
3313
|
-
if (!cmd) {
|
|
3314
|
-
resolve2({ stdout: "", stderr: "", exitCode: 127 });
|
|
3315
|
-
return;
|
|
3316
|
-
}
|
|
3317
|
-
const proc = spawn(cmd, cmdArgs, { cwd: process.cwd(), stdio: ["pipe", "pipe", "pipe"] });
|
|
3318
|
-
let stdout = "";
|
|
3319
|
-
let stderr = "";
|
|
3320
|
-
proc.stdout.on("data", (data) => {
|
|
3321
|
-
stdout += data.toString();
|
|
3322
|
-
});
|
|
3323
|
-
proc.stderr.on("data", (data) => {
|
|
3324
|
-
stderr += data.toString();
|
|
3325
|
-
});
|
|
3326
|
-
proc.on("close", (code) => {
|
|
3327
|
-
resolve2({ stdout, stderr, exitCode: code ?? 127 });
|
|
3328
|
-
});
|
|
3329
|
-
proc.on("error", () => {
|
|
3330
|
-
resolve2({ stdout: "", stderr: "", exitCode: 127 });
|
|
3331
|
-
});
|
|
3332
|
-
});
|
|
3333
|
-
}
|
|
3334
|
-
executeWithTimeout(proc, timeout) {
|
|
3335
|
-
return new Promise((resolve2, reject) => {
|
|
3336
|
-
let stdout = "";
|
|
3337
|
-
let stderr = "";
|
|
3338
|
-
const timer = setTimeout(() => {
|
|
3339
|
-
proc.kill("SIGTERM");
|
|
3340
|
-
reject(new Error(`${this.name} timed out after ${timeout}ms`));
|
|
3341
|
-
}, timeout);
|
|
3342
|
-
proc.stdout?.on("data", (data) => {
|
|
3343
|
-
stdout += data.toString();
|
|
3344
|
-
});
|
|
3345
|
-
proc.stderr?.on("data", (data) => {
|
|
3346
|
-
stderr += data.toString();
|
|
3347
|
-
});
|
|
3348
|
-
proc.on("close", (code) => {
|
|
3349
|
-
clearTimeout(timer);
|
|
3350
|
-
resolve2({ stdout, stderr, exitCode: code ?? 127 });
|
|
3351
|
-
});
|
|
3352
|
-
proc.on("error", (err) => {
|
|
3353
|
-
clearTimeout(timer);
|
|
3354
|
-
reject(err);
|
|
3355
|
-
});
|
|
3356
|
-
});
|
|
3357
|
-
}
|
|
3358
|
-
};
|
|
3359
|
-
var ClaudeCodeAdapter = class extends BaseAdapter {
|
|
3360
|
-
name = "claude-code";
|
|
3361
|
-
version = "unknown";
|
|
3362
|
-
async checkPrerequisites() {
|
|
3363
|
-
try {
|
|
3364
|
-
const result = await this.execCommand(["claude", "--version"]);
|
|
3365
|
-
if (result.exitCode !== 0) {
|
|
3366
|
-
return {
|
|
3367
|
-
ok: false,
|
|
3368
|
-
error: {
|
|
3369
|
-
type: "cli-not-found",
|
|
3370
|
-
message: "Claude Code CLI is not installed.",
|
|
3371
|
-
helpUrl: "https://docs.anthropic.com/en/docs/claude-code"
|
|
3372
|
-
}
|
|
3373
|
-
};
|
|
3374
|
-
}
|
|
3375
|
-
this.version = result.stdout.trim() || "unknown";
|
|
3376
|
-
} catch {
|
|
3377
|
-
return {
|
|
3378
|
-
ok: false,
|
|
3379
|
-
error: {
|
|
3380
|
-
type: "cli-not-found",
|
|
3381
|
-
message: "Claude Code CLI is not installed.",
|
|
3382
|
-
helpUrl: "https://docs.anthropic.com/en/docs/claude-code"
|
|
3383
|
-
}
|
|
3384
|
-
};
|
|
3385
|
-
}
|
|
3386
|
-
return { ok: true };
|
|
3387
|
-
}
|
|
3388
|
-
async run(params) {
|
|
3389
|
-
const { setting, eventListener, storeCheckpoint } = params;
|
|
3390
|
-
const expert = setting.experts?.[setting.expertKey];
|
|
3391
|
-
if (!expert) {
|
|
3392
|
-
throw new Error(`Expert "${setting.expertKey}" not found`);
|
|
3393
|
-
}
|
|
3394
|
-
if (!setting.jobId || !setting.runId) {
|
|
3395
|
-
throw new Error("ClaudeCodeAdapter requires jobId and runId in setting");
|
|
3396
|
-
}
|
|
3397
|
-
const { jobId, runId } = setting;
|
|
3398
|
-
const expertInfo = { key: setting.expertKey, name: expert.name, version: expert.version };
|
|
3399
|
-
const query = setting.input.text ?? "";
|
|
3400
|
-
const initEvent = createRuntimeInitEvent(
|
|
3401
|
-
jobId,
|
|
3402
|
-
runId,
|
|
3403
|
-
expert.name,
|
|
3404
|
-
"claude-code",
|
|
3405
|
-
this.version,
|
|
3406
|
-
query
|
|
3407
|
-
);
|
|
3408
|
-
eventListener?.(initEvent);
|
|
3409
|
-
const initialCheckpoint = {
|
|
3410
|
-
id: createId(),
|
|
3411
|
-
jobId,
|
|
3412
|
-
runId,
|
|
3413
|
-
status: "init",
|
|
3414
|
-
stepNumber: 0,
|
|
3415
|
-
messages: [],
|
|
3416
|
-
expert: expertInfo,
|
|
3417
|
-
usage: createEmptyUsage(),
|
|
3418
|
-
metadata: { runtime: "claude-code" }
|
|
3419
|
-
};
|
|
3420
|
-
const startRunEvent = createStartRunEvent(jobId, runId, setting.expertKey, initialCheckpoint);
|
|
3421
|
-
eventListener?.(startRunEvent);
|
|
3422
|
-
const state = {
|
|
3423
|
-
checkpoint: initialCheckpoint,
|
|
3424
|
-
events: [initEvent, startRunEvent],
|
|
3425
|
-
pendingToolCalls: /* @__PURE__ */ new Map(),
|
|
3426
|
-
finalOutput: "",
|
|
3427
|
-
lastStreamingText: ""
|
|
3428
|
-
};
|
|
3429
|
-
const startedAt = Date.now();
|
|
3430
|
-
const result = await this.executeClaudeCliStreaming(
|
|
3431
|
-
expert.instruction,
|
|
3432
|
-
query,
|
|
3433
|
-
setting.timeout ?? 6e4,
|
|
3434
|
-
state,
|
|
3435
|
-
eventListener,
|
|
3436
|
-
storeCheckpoint
|
|
3437
|
-
);
|
|
3438
|
-
if (result.exitCode !== 0) {
|
|
3439
|
-
throw new Error(
|
|
3440
|
-
`Claude Code CLI failed with exit code ${result.exitCode}: ${result.stderr || result.stdout}`
|
|
3441
|
-
);
|
|
3442
|
-
}
|
|
3443
|
-
const finalMessage = {
|
|
3444
|
-
id: createId(),
|
|
3445
|
-
type: "expertMessage",
|
|
3446
|
-
contents: [{ type: "textPart", id: createId(), text: state.finalOutput }]
|
|
3447
|
-
};
|
|
3448
|
-
const finalCheckpoint = {
|
|
3449
|
-
...state.checkpoint,
|
|
3450
|
-
status: "completed",
|
|
3451
|
-
stepNumber: state.checkpoint.stepNumber + 1,
|
|
3452
|
-
messages: [...state.checkpoint.messages, finalMessage]
|
|
3453
|
-
};
|
|
3454
|
-
await storeCheckpoint?.(finalCheckpoint);
|
|
3455
|
-
const completeEvent = createCompleteRunEvent(
|
|
3456
|
-
jobId,
|
|
3457
|
-
runId,
|
|
3458
|
-
setting.expertKey,
|
|
3459
|
-
finalCheckpoint,
|
|
3460
|
-
state.finalOutput,
|
|
3461
|
-
startedAt
|
|
3462
|
-
);
|
|
3463
|
-
state.events.push(completeEvent);
|
|
3464
|
-
eventListener?.(completeEvent);
|
|
3465
|
-
return { checkpoint: finalCheckpoint, events: state.events };
|
|
3466
|
-
}
|
|
3467
|
-
async executeClaudeCliStreaming(systemPrompt, prompt, timeout, state, eventListener, storeCheckpoint) {
|
|
3468
|
-
const args = ["-p", prompt, "--output-format", "stream-json", "--verbose"];
|
|
3469
|
-
if (systemPrompt) {
|
|
3470
|
-
args.push("--append-system-prompt", systemPrompt);
|
|
3471
|
-
}
|
|
3472
|
-
const proc = spawn("claude", args, {
|
|
3473
|
-
cwd: process.cwd(),
|
|
3474
|
-
env: getFilteredEnv({
|
|
3475
|
-
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY ?? ""
|
|
3476
|
-
}),
|
|
3477
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
3478
|
-
});
|
|
3479
|
-
proc.stdin.end();
|
|
3480
|
-
return this.executeWithStreaming(proc, timeout, state, eventListener, storeCheckpoint);
|
|
3481
|
-
}
|
|
3482
|
-
executeWithStreaming(proc, timeout, state, eventListener, storeCheckpoint) {
|
|
3483
|
-
return new Promise((resolve2, reject) => {
|
|
3484
|
-
let stdout = "";
|
|
3485
|
-
let stderr = "";
|
|
3486
|
-
let buffer = "";
|
|
3487
|
-
const timer = setTimeout(() => {
|
|
3488
|
-
proc.kill("SIGTERM");
|
|
3489
|
-
reject(new Error(`${this.name} timed out after ${timeout}ms`));
|
|
3490
|
-
}, timeout);
|
|
3491
|
-
proc.stdout?.on("data", (data) => {
|
|
3492
|
-
const chunk = data.toString();
|
|
3493
|
-
stdout += chunk;
|
|
3494
|
-
buffer += chunk;
|
|
3495
|
-
const lines = buffer.split("\n");
|
|
3496
|
-
buffer = lines.pop() ?? "";
|
|
3497
|
-
for (const line of lines) {
|
|
3498
|
-
const trimmed = line.trim();
|
|
3499
|
-
if (!trimmed) continue;
|
|
3500
|
-
try {
|
|
3501
|
-
const parsed = JSON.parse(trimmed);
|
|
3502
|
-
this.handleStreamEvent(parsed, state, eventListener, storeCheckpoint);
|
|
3503
|
-
} catch {
|
|
3504
|
-
}
|
|
3505
|
-
}
|
|
3506
|
-
});
|
|
3507
|
-
proc.stderr?.on("data", (data) => {
|
|
3508
|
-
stderr += data.toString();
|
|
3509
|
-
});
|
|
3510
|
-
proc.on("close", (code) => {
|
|
3511
|
-
clearTimeout(timer);
|
|
3512
|
-
resolve2({ stdout, stderr, exitCode: code ?? 127 });
|
|
3513
|
-
});
|
|
3514
|
-
proc.on("error", (err) => {
|
|
3515
|
-
clearTimeout(timer);
|
|
3516
|
-
reject(err);
|
|
3517
|
-
});
|
|
3518
|
-
});
|
|
3519
|
-
}
|
|
3520
|
-
handleStreamEvent(parsed, state, eventListener, storeCheckpoint) {
|
|
3521
|
-
const { checkpoint } = state;
|
|
3522
|
-
const jobId = checkpoint.jobId;
|
|
3523
|
-
const runId = checkpoint.runId;
|
|
3524
|
-
const expertKey = checkpoint.expert.key;
|
|
3525
|
-
if (parsed.type === "result" && typeof parsed.result === "string") {
|
|
3526
|
-
state.finalOutput = parsed.result;
|
|
3527
|
-
} else if (parsed.type === "assistant" && parsed.message) {
|
|
3528
|
-
const message = parsed.message;
|
|
3529
|
-
if (message.content) {
|
|
3530
|
-
for (const content of message.content) {
|
|
3531
|
-
if (content.type === "text") {
|
|
3532
|
-
const text = content.text?.trim();
|
|
3533
|
-
if (text && text !== state.lastStreamingText) {
|
|
3534
|
-
state.lastStreamingText = text;
|
|
3535
|
-
}
|
|
3536
|
-
} else if (content.type === "tool_use") {
|
|
3537
|
-
const toolCall = {
|
|
3538
|
-
id: content.id ?? createId(),
|
|
3539
|
-
skillName: "claude-code",
|
|
3540
|
-
toolName: content.name ?? "unknown",
|
|
3541
|
-
args: content.input ?? {}
|
|
3542
|
-
};
|
|
3543
|
-
state.pendingToolCalls.set(toolCall.id, toolCall);
|
|
3544
|
-
const event = createCallToolsEvent(
|
|
3545
|
-
jobId,
|
|
3546
|
-
runId,
|
|
3547
|
-
expertKey,
|
|
3548
|
-
checkpoint.stepNumber,
|
|
3549
|
-
[toolCall],
|
|
3550
|
-
checkpoint
|
|
3551
|
-
);
|
|
3552
|
-
state.events.push(event);
|
|
3553
|
-
eventListener?.(event);
|
|
3554
|
-
}
|
|
3555
|
-
}
|
|
3556
|
-
}
|
|
3557
|
-
} else if (parsed.type === "user" && parsed.message) {
|
|
3558
|
-
const message = parsed.message;
|
|
3559
|
-
if (message.content) {
|
|
3560
|
-
for (const content of message.content) {
|
|
3561
|
-
if (content.type === "tool_result") {
|
|
3562
|
-
const toolCallId = content.tool_use_id ?? "";
|
|
3563
|
-
const resultContent = content.content ?? "";
|
|
3564
|
-
const pendingToolCall = state.pendingToolCalls.get(toolCallId);
|
|
3565
|
-
const toolName = pendingToolCall?.toolName ?? "unknown";
|
|
3566
|
-
state.pendingToolCalls.delete(toolCallId);
|
|
3567
|
-
const toolResultMessage = {
|
|
3568
|
-
id: createId(),
|
|
3569
|
-
type: "toolMessage",
|
|
3570
|
-
contents: [
|
|
3571
|
-
{
|
|
3572
|
-
type: "toolResultPart",
|
|
3573
|
-
id: createId(),
|
|
3574
|
-
toolCallId,
|
|
3575
|
-
toolName,
|
|
3576
|
-
contents: [{ type: "textPart", id: createId(), text: resultContent }]
|
|
3577
|
-
}
|
|
3578
|
-
]
|
|
3579
|
-
};
|
|
3580
|
-
state.checkpoint = {
|
|
3581
|
-
...state.checkpoint,
|
|
3582
|
-
stepNumber: state.checkpoint.stepNumber + 1,
|
|
3583
|
-
messages: [...state.checkpoint.messages, toolResultMessage]
|
|
3584
|
-
};
|
|
3585
|
-
storeCheckpoint?.(state.checkpoint);
|
|
3586
|
-
const event = createResolveToolResultsEvent(
|
|
3587
|
-
jobId,
|
|
3588
|
-
runId,
|
|
3589
|
-
expertKey,
|
|
3590
|
-
state.checkpoint.stepNumber,
|
|
3591
|
-
[
|
|
3592
|
-
{
|
|
3593
|
-
id: toolCallId,
|
|
3594
|
-
skillName: "claude-code",
|
|
3595
|
-
toolName,
|
|
3596
|
-
result: [{ type: "textPart", id: createId(), text: resultContent }]
|
|
3597
|
-
}
|
|
3598
|
-
]
|
|
3599
|
-
);
|
|
3600
|
-
state.events.push(event);
|
|
3601
|
-
eventListener?.(event);
|
|
3602
|
-
}
|
|
3603
|
-
}
|
|
3604
|
-
}
|
|
3605
|
-
} else if (parsed.type === "content_block_delta" && parsed.delta) {
|
|
3606
|
-
const delta = parsed.delta;
|
|
3607
|
-
const text = delta.text?.trim();
|
|
3608
|
-
if (delta.type === "text_delta" && text) ;
|
|
3609
|
-
}
|
|
3610
|
-
}
|
|
3611
|
-
};
|
|
3612
|
-
function cursorToolCallToPerstack(cursorToolCall) {
|
|
3613
|
-
const toolKey = Object.keys(cursorToolCall.tool_call)[0];
|
|
3614
|
-
const toolData = cursorToolCall.tool_call[toolKey];
|
|
3615
|
-
const toolName = toolKey.replace("ToolCall", "");
|
|
3616
|
-
return {
|
|
3617
|
-
toolCall: {
|
|
3618
|
-
id: cursorToolCall.call_id,
|
|
3619
|
-
skillName: "cursor",
|
|
3620
|
-
toolName,
|
|
3621
|
-
args: toolData.args
|
|
3622
|
-
},
|
|
3623
|
-
toolName
|
|
3624
|
-
};
|
|
3625
|
-
}
|
|
3626
|
-
function cursorToolResultToPerstack(cursorToolCall) {
|
|
3627
|
-
const toolKey = Object.keys(cursorToolCall.tool_call)[0];
|
|
3628
|
-
const toolData = cursorToolCall.tool_call[toolKey];
|
|
3629
|
-
const toolName = toolKey.replace("ToolCall", "");
|
|
3630
|
-
const content = toolData.result?.success?.content ?? toolData.result?.error ?? "";
|
|
3631
|
-
return {
|
|
3632
|
-
id: cursorToolCall.call_id,
|
|
3633
|
-
skillName: "cursor",
|
|
3634
|
-
toolName,
|
|
3635
|
-
result: [{ type: "textPart", id: createId(), text: content }]
|
|
3636
|
-
};
|
|
3637
|
-
}
|
|
3638
|
-
var CursorAdapter = class extends BaseAdapter {
|
|
3639
|
-
name = "cursor";
|
|
3640
|
-
version = "unknown";
|
|
3641
|
-
async checkPrerequisites() {
|
|
3642
|
-
try {
|
|
3643
|
-
const result = await this.execCommand(["cursor-agent", "--version"]);
|
|
3644
|
-
if (result.exitCode !== 0) {
|
|
3645
|
-
return {
|
|
3646
|
-
ok: false,
|
|
3647
|
-
error: {
|
|
3648
|
-
type: "cli-not-found",
|
|
3649
|
-
message: "Cursor CLI (cursor-agent) is not installed.",
|
|
3650
|
-
helpUrl: "https://docs.cursor.com/context/rules"
|
|
3651
|
-
}
|
|
3652
|
-
};
|
|
3653
|
-
}
|
|
3654
|
-
this.version = result.stdout.trim() || "unknown";
|
|
3655
|
-
} catch {
|
|
3656
|
-
return {
|
|
3657
|
-
ok: false,
|
|
3658
|
-
error: {
|
|
3659
|
-
type: "cli-not-found",
|
|
3660
|
-
message: "Cursor CLI (cursor-agent) is not installed.",
|
|
3661
|
-
helpUrl: "https://docs.cursor.com/context/rules"
|
|
3662
|
-
}
|
|
3663
|
-
};
|
|
3664
|
-
}
|
|
3665
|
-
return { ok: true };
|
|
3666
|
-
}
|
|
3667
|
-
async run(params) {
|
|
3668
|
-
const { setting, eventListener, storeCheckpoint } = params;
|
|
3669
|
-
const expert = setting.experts?.[setting.expertKey];
|
|
3670
|
-
if (!expert) {
|
|
3671
|
-
throw new Error(`Expert "${setting.expertKey}" not found`);
|
|
3672
|
-
}
|
|
3673
|
-
if (!setting.jobId || !setting.runId) {
|
|
3674
|
-
throw new Error("CursorAdapter requires jobId and runId in setting");
|
|
3675
|
-
}
|
|
3676
|
-
const { jobId, runId } = setting;
|
|
3677
|
-
const expertInfo = { key: setting.expertKey, name: expert.name, version: expert.version };
|
|
3678
|
-
const query = setting.input.text;
|
|
3679
|
-
const prompt = this.buildPrompt(expert.instruction, query);
|
|
3680
|
-
const initEvent = createRuntimeInitEvent(
|
|
3681
|
-
jobId,
|
|
3682
|
-
runId,
|
|
3683
|
-
expert.name,
|
|
3684
|
-
"cursor",
|
|
3685
|
-
this.version,
|
|
3686
|
-
query
|
|
3687
|
-
);
|
|
3688
|
-
eventListener?.(initEvent);
|
|
3689
|
-
const initialCheckpoint = {
|
|
3690
|
-
id: createId(),
|
|
3691
|
-
jobId,
|
|
3692
|
-
runId,
|
|
3693
|
-
status: "init",
|
|
3694
|
-
stepNumber: 0,
|
|
3695
|
-
messages: [],
|
|
3696
|
-
expert: expertInfo,
|
|
3697
|
-
usage: createEmptyUsage(),
|
|
3698
|
-
metadata: { runtime: "cursor" }
|
|
3699
|
-
};
|
|
3700
|
-
const startRunEvent = createStartRunEvent(jobId, runId, setting.expertKey, initialCheckpoint);
|
|
3701
|
-
eventListener?.(startRunEvent);
|
|
3702
|
-
const state = {
|
|
3703
|
-
checkpoint: initialCheckpoint,
|
|
3704
|
-
events: [initEvent, startRunEvent],
|
|
3705
|
-
pendingToolCalls: /* @__PURE__ */ new Map(),
|
|
3706
|
-
finalOutput: "",
|
|
3707
|
-
lastStreamingText: ""
|
|
3708
|
-
};
|
|
3709
|
-
const startedAt = Date.now();
|
|
3710
|
-
const result = await this.executeCursorAgentStreaming(
|
|
3711
|
-
prompt,
|
|
3712
|
-
setting.timeout ?? 6e4,
|
|
3713
|
-
state,
|
|
3714
|
-
eventListener,
|
|
3715
|
-
storeCheckpoint
|
|
3716
|
-
);
|
|
3717
|
-
if (result.exitCode !== 0) {
|
|
3718
|
-
throw new Error(
|
|
3719
|
-
`Cursor CLI failed with exit code ${result.exitCode}: ${result.stderr || result.stdout}`
|
|
3720
|
-
);
|
|
3721
|
-
}
|
|
3722
|
-
const finalMessage = {
|
|
3723
|
-
id: createId(),
|
|
3724
|
-
type: "expertMessage",
|
|
3725
|
-
contents: [{ type: "textPart", id: createId(), text: state.finalOutput }]
|
|
3726
|
-
};
|
|
3727
|
-
const finalCheckpoint = {
|
|
3728
|
-
...state.checkpoint,
|
|
3729
|
-
status: "completed",
|
|
3730
|
-
stepNumber: state.checkpoint.stepNumber + 1,
|
|
3731
|
-
messages: [...state.checkpoint.messages, finalMessage]
|
|
3732
|
-
};
|
|
3733
|
-
await storeCheckpoint?.(finalCheckpoint);
|
|
3734
|
-
const completeEvent = createCompleteRunEvent(
|
|
3735
|
-
jobId,
|
|
3736
|
-
runId,
|
|
3737
|
-
setting.expertKey,
|
|
3738
|
-
finalCheckpoint,
|
|
3739
|
-
state.finalOutput,
|
|
3740
|
-
startedAt
|
|
3741
|
-
);
|
|
3742
|
-
state.events.push(completeEvent);
|
|
3743
|
-
eventListener?.(completeEvent);
|
|
3744
|
-
return { checkpoint: finalCheckpoint, events: state.events };
|
|
3745
|
-
}
|
|
3746
|
-
buildPrompt(instruction, query) {
|
|
3747
|
-
let prompt = instruction;
|
|
3748
|
-
if (query) {
|
|
3749
|
-
prompt += `
|
|
3750
|
-
|
|
3751
|
-
## User Request
|
|
3752
|
-
${query}`;
|
|
3753
|
-
}
|
|
3754
|
-
return prompt;
|
|
3755
|
-
}
|
|
3756
|
-
async executeCursorAgentStreaming(prompt, timeout, state, eventListener, storeCheckpoint) {
|
|
3757
|
-
const proc = spawn(
|
|
3758
|
-
"cursor-agent",
|
|
3759
|
-
["--print", "--output-format", "stream-json", "--stream-partial-output", "--force", prompt],
|
|
3760
|
-
{ cwd: process.cwd(), env: getFilteredEnv(), stdio: ["pipe", "pipe", "pipe"] }
|
|
3761
|
-
);
|
|
3762
|
-
proc.stdin.end();
|
|
3763
|
-
return this.executeWithStreaming(proc, timeout, state, eventListener, storeCheckpoint);
|
|
3764
|
-
}
|
|
3765
|
-
executeWithStreaming(proc, timeout, state, eventListener, storeCheckpoint) {
|
|
3766
|
-
return new Promise((resolve2, reject) => {
|
|
3767
|
-
let stdout = "";
|
|
3768
|
-
let stderr = "";
|
|
3769
|
-
let buffer = "";
|
|
3770
|
-
const timer = setTimeout(() => {
|
|
3771
|
-
proc.kill("SIGTERM");
|
|
3772
|
-
reject(new Error(`${this.name} timed out after ${timeout}ms`));
|
|
3773
|
-
}, timeout);
|
|
3774
|
-
proc.stdout?.on("data", (data) => {
|
|
3775
|
-
const chunk = data.toString();
|
|
3776
|
-
stdout += chunk;
|
|
3777
|
-
buffer += chunk;
|
|
3778
|
-
const lines = buffer.split("\n");
|
|
3779
|
-
buffer = lines.pop() ?? "";
|
|
3780
|
-
for (const line of lines) {
|
|
3781
|
-
const trimmed = line.trim();
|
|
3782
|
-
if (!trimmed) continue;
|
|
3783
|
-
try {
|
|
3784
|
-
const parsed = JSON.parse(trimmed);
|
|
3785
|
-
this.handleStreamEvent(parsed, state, eventListener, storeCheckpoint);
|
|
3786
|
-
} catch {
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
});
|
|
3790
|
-
proc.stderr?.on("data", (data) => {
|
|
3791
|
-
stderr += data.toString();
|
|
3792
|
-
});
|
|
3793
|
-
proc.on("close", (code) => {
|
|
3794
|
-
clearTimeout(timer);
|
|
3795
|
-
resolve2({ stdout, stderr, exitCode: code ?? 127 });
|
|
3796
|
-
});
|
|
3797
|
-
proc.on("error", (err) => {
|
|
3798
|
-
clearTimeout(timer);
|
|
3799
|
-
reject(err);
|
|
3800
|
-
});
|
|
3801
|
-
});
|
|
3802
|
-
}
|
|
3803
|
-
handleStreamEvent(parsed, state, eventListener, storeCheckpoint) {
|
|
3804
|
-
const { checkpoint } = state;
|
|
3805
|
-
const jobId = checkpoint.jobId;
|
|
3806
|
-
const runId = checkpoint.runId;
|
|
3807
|
-
const expertKey = checkpoint.expert.key;
|
|
3808
|
-
if (parsed.type === "result" && typeof parsed.result === "string") {
|
|
3809
|
-
state.finalOutput = parsed.result;
|
|
3810
|
-
} else if (parsed.type === "assistant" && parsed.message) {
|
|
3811
|
-
const message = parsed.message;
|
|
3812
|
-
if (message.content) {
|
|
3813
|
-
for (const content of message.content) {
|
|
3814
|
-
const text = content.text?.trim();
|
|
3815
|
-
if (content.type === "text" && text && text !== state.lastStreamingText) {
|
|
3816
|
-
state.lastStreamingText = text;
|
|
3817
|
-
}
|
|
3818
|
-
}
|
|
3819
|
-
}
|
|
3820
|
-
} else if (parsed.type === "tool_call" && parsed.subtype === "started") {
|
|
3821
|
-
const cursorToolCall = parsed;
|
|
3822
|
-
const { toolCall } = cursorToolCallToPerstack(cursorToolCall);
|
|
3823
|
-
state.pendingToolCalls.set(cursorToolCall.call_id, toolCall);
|
|
3824
|
-
const event = createCallToolsEvent(
|
|
3825
|
-
jobId,
|
|
3826
|
-
runId,
|
|
3827
|
-
expertKey,
|
|
3828
|
-
checkpoint.stepNumber,
|
|
3829
|
-
[toolCall],
|
|
3830
|
-
checkpoint
|
|
3831
|
-
);
|
|
3832
|
-
state.events.push(event);
|
|
3833
|
-
eventListener?.(event);
|
|
3834
|
-
} else if (parsed.type === "tool_call" && parsed.subtype === "completed") {
|
|
3835
|
-
const cursorToolCall = parsed;
|
|
3836
|
-
const toolResult = cursorToolResultToPerstack(cursorToolCall);
|
|
3837
|
-
state.pendingToolCalls.delete(cursorToolCall.call_id);
|
|
3838
|
-
const toolResultMessage = {
|
|
3839
|
-
id: createId(),
|
|
3840
|
-
type: "toolMessage",
|
|
3841
|
-
contents: [
|
|
3842
|
-
{
|
|
3843
|
-
type: "toolResultPart",
|
|
3844
|
-
id: createId(),
|
|
3845
|
-
toolCallId: toolResult.id,
|
|
3846
|
-
toolName: toolResult.toolName,
|
|
3847
|
-
contents: toolResult.result.filter(
|
|
3848
|
-
(part) => part.type === "textPart"
|
|
3849
|
-
)
|
|
3850
|
-
}
|
|
3851
|
-
]
|
|
3852
|
-
};
|
|
3853
|
-
state.checkpoint = {
|
|
3854
|
-
...state.checkpoint,
|
|
3855
|
-
stepNumber: state.checkpoint.stepNumber + 1,
|
|
3856
|
-
messages: [...state.checkpoint.messages, toolResultMessage]
|
|
3857
|
-
};
|
|
3858
|
-
storeCheckpoint?.(state.checkpoint);
|
|
3859
|
-
const event = createResolveToolResultsEvent(
|
|
3860
|
-
jobId,
|
|
3861
|
-
runId,
|
|
3862
|
-
expertKey,
|
|
3863
|
-
state.checkpoint.stepNumber,
|
|
3864
|
-
[toolResult]
|
|
3865
|
-
);
|
|
3866
|
-
state.events.push(event);
|
|
3867
|
-
eventListener?.(event);
|
|
3868
|
-
}
|
|
3869
|
-
}
|
|
3870
|
-
};
|
|
3871
|
-
|
|
3872
|
-
// ../../packages/runtimes/docker/src/dockerfile-generator.ts
|
|
3873
|
-
function detectRequiredRuntimes(config, expertKey) {
|
|
3874
|
-
const runtimes = /* @__PURE__ */ new Set();
|
|
3875
|
-
runtimes.add("nodejs");
|
|
3876
|
-
const expert = config.experts?.[expertKey];
|
|
3877
|
-
if (!expert?.skills) {
|
|
3878
|
-
return runtimes;
|
|
3879
|
-
}
|
|
3880
|
-
for (const skill of Object.values(expert.skills)) {
|
|
3881
|
-
if (skill.type !== "mcpStdioSkill") continue;
|
|
3882
|
-
const mcpSkill = skill;
|
|
3883
|
-
if (mcpSkill.command === "npx" || mcpSkill.command === "node") {
|
|
3884
|
-
runtimes.add("nodejs");
|
|
3885
|
-
}
|
|
3886
|
-
if (mcpSkill.command === "uvx" || mcpSkill.command === "python" || mcpSkill.command === "python3") {
|
|
3887
|
-
runtimes.add("python");
|
|
3888
|
-
}
|
|
3889
|
-
}
|
|
3890
|
-
return runtimes;
|
|
3891
|
-
}
|
|
3892
|
-
function generateBaseImageLayers(runtimes) {
|
|
3893
|
-
const lines = [];
|
|
3894
|
-
lines.push("FROM node:22-bookworm-slim");
|
|
3895
|
-
lines.push("");
|
|
3896
|
-
lines.push("RUN apt-get update && apt-get install -y --no-install-recommends \\");
|
|
3897
|
-
lines.push(" ca-certificates \\");
|
|
3898
|
-
lines.push(" curl \\");
|
|
3899
|
-
lines.push(" && rm -rf /var/lib/apt/lists/*");
|
|
3900
|
-
lines.push("");
|
|
3901
|
-
if (runtimes.has("python")) {
|
|
3902
|
-
lines.push("RUN apt-get update && apt-get install -y --no-install-recommends \\");
|
|
3903
|
-
lines.push(" python3 \\");
|
|
3904
|
-
lines.push(" python3-pip \\");
|
|
3905
|
-
lines.push(" python3-venv \\");
|
|
3906
|
-
lines.push(" && rm -rf /var/lib/apt/lists/* \\");
|
|
3907
|
-
lines.push(" && pip3 install --break-system-packages uv");
|
|
3908
|
-
lines.push("");
|
|
3909
|
-
}
|
|
3910
|
-
return lines.join("\n");
|
|
3911
|
-
}
|
|
3912
|
-
function generateRuntimeInstallLayers() {
|
|
3913
|
-
const lines = [];
|
|
3914
|
-
lines.push("RUN npm install -g @perstack/runtime @perstack/base");
|
|
3915
|
-
lines.push("");
|
|
3916
|
-
return lines.join("\n");
|
|
3917
|
-
}
|
|
3918
|
-
function generateDockerfile(config, expertKey, options) {
|
|
3919
|
-
const runtimes = detectRequiredRuntimes(config, expertKey);
|
|
3920
|
-
const lines = [];
|
|
3921
|
-
lines.push(generateBaseImageLayers(runtimes));
|
|
3922
|
-
lines.push("WORKDIR /app");
|
|
3923
|
-
lines.push("");
|
|
3924
|
-
lines.push(generateRuntimeInstallLayers());
|
|
3925
|
-
lines.push("RUN groupadd -r perstack && useradd -r -g perstack -d /home/perstack -m perstack");
|
|
3926
|
-
lines.push("RUN mkdir -p /workspace && chown -R perstack:perstack /workspace /app");
|
|
3927
|
-
lines.push("");
|
|
3928
|
-
lines.push("COPY --chown=perstack:perstack perstack.toml /app/perstack.toml");
|
|
3929
|
-
lines.push("");
|
|
3930
|
-
if (options?.proxyEnabled) {
|
|
3931
|
-
lines.push("ENV PERSTACK_PROXY_URL=http://proxy:3128");
|
|
3932
|
-
lines.push("ENV NPM_CONFIG_PROXY=http://proxy:3128");
|
|
3933
|
-
lines.push("ENV NPM_CONFIG_HTTPS_PROXY=http://proxy:3128");
|
|
3934
|
-
lines.push("ENV NODE_OPTIONS=--use-env-proxy");
|
|
3935
|
-
lines.push("");
|
|
3936
|
-
}
|
|
3937
|
-
lines.push("USER perstack");
|
|
3938
|
-
lines.push("");
|
|
3939
|
-
lines.push("WORKDIR /workspace");
|
|
3940
|
-
lines.push("");
|
|
3941
|
-
lines.push(
|
|
3942
|
-
`ENTRYPOINT ["perstack-runtime", "run", "--config", "/app/perstack.toml", ${JSON.stringify(expertKey)}]`
|
|
3943
|
-
);
|
|
3944
|
-
lines.push("");
|
|
3945
|
-
return lines.join("\n");
|
|
3946
|
-
}
|
|
3947
|
-
|
|
3948
|
-
// ../../packages/runtimes/docker/src/env-resolver.ts
|
|
3949
|
-
function getProviderEnvKeys(provider) {
|
|
3950
|
-
if (!provider) return [];
|
|
3951
|
-
switch (provider.providerName) {
|
|
3952
|
-
case "anthropic":
|
|
3953
|
-
return ["ANTHROPIC_API_KEY"];
|
|
3954
|
-
case "openai":
|
|
3955
|
-
return ["OPENAI_API_KEY"];
|
|
3956
|
-
case "google":
|
|
3957
|
-
return ["GOOGLE_API_KEY"];
|
|
3958
|
-
case "azure-openai":
|
|
3959
|
-
return ["AZURE_OPENAI_API_KEY"];
|
|
3960
|
-
case "amazon-bedrock":
|
|
3961
|
-
return ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"];
|
|
3962
|
-
case "google-vertex":
|
|
3963
|
-
return ["GOOGLE_APPLICATION_CREDENTIALS"];
|
|
3964
|
-
case "deepseek":
|
|
3965
|
-
return ["DEEPSEEK_API_KEY"];
|
|
3966
|
-
case "ollama":
|
|
3967
|
-
return [];
|
|
3968
|
-
default:
|
|
3969
|
-
return [];
|
|
3970
|
-
}
|
|
3971
|
-
}
|
|
3972
|
-
function extractRequiredEnvVars(config, expertKey) {
|
|
3973
|
-
const requirements = [];
|
|
3974
|
-
const providerEnvKeys = getProviderEnvKeys(config.provider);
|
|
3975
|
-
for (const key of providerEnvKeys) {
|
|
3976
|
-
requirements.push({
|
|
3977
|
-
name: key,
|
|
3978
|
-
source: "provider",
|
|
3979
|
-
required: true
|
|
3980
|
-
});
|
|
3981
|
-
}
|
|
3982
|
-
const expert = config.experts?.[expertKey];
|
|
3983
|
-
if (expert?.skills) {
|
|
3984
|
-
for (const skill of Object.values(expert.skills)) {
|
|
3985
|
-
if (skill.type !== "mcpStdioSkill") continue;
|
|
3986
|
-
const requiredEnv = skill.requiredEnv ?? [];
|
|
3987
|
-
for (const envName of requiredEnv) {
|
|
3988
|
-
if (!requirements.some((r) => r.name === envName)) {
|
|
3989
|
-
requirements.push({
|
|
3990
|
-
name: envName,
|
|
3991
|
-
source: "skill",
|
|
3992
|
-
required: true
|
|
3993
|
-
});
|
|
3994
|
-
}
|
|
3995
|
-
}
|
|
3996
|
-
}
|
|
3997
|
-
}
|
|
3998
|
-
requirements.push({
|
|
3999
|
-
name: "PERSTACK_API_KEY",
|
|
4000
|
-
source: "runtime",
|
|
4001
|
-
required: false
|
|
4002
|
-
});
|
|
4003
|
-
return requirements;
|
|
4004
|
-
}
|
|
4005
|
-
function resolveEnvValues(requirements, env) {
|
|
4006
|
-
const resolved = {};
|
|
4007
|
-
const missing = [];
|
|
4008
|
-
for (const req of requirements) {
|
|
4009
|
-
const value = env[req.name];
|
|
4010
|
-
if (value !== void 0) {
|
|
4011
|
-
resolved[req.name] = value;
|
|
4012
|
-
} else if (req.required) {
|
|
4013
|
-
missing.push(req.name);
|
|
4014
|
-
}
|
|
4015
|
-
}
|
|
4016
|
-
return { resolved, missing };
|
|
4017
|
-
}
|
|
4018
|
-
|
|
4019
|
-
// ../../packages/runtimes/docker/src/proxy-generator.ts
|
|
4020
|
-
function getProviderApiDomains(provider) {
|
|
4021
|
-
if (!provider) return [];
|
|
4022
|
-
switch (provider.providerName) {
|
|
4023
|
-
case "anthropic":
|
|
4024
|
-
return ["api.anthropic.com"];
|
|
4025
|
-
case "openai":
|
|
4026
|
-
return ["api.openai.com"];
|
|
4027
|
-
case "google":
|
|
4028
|
-
return ["generativelanguage.googleapis.com"];
|
|
4029
|
-
case "azure-openai":
|
|
4030
|
-
return ["*.openai.azure.com"];
|
|
4031
|
-
case "amazon-bedrock":
|
|
4032
|
-
return ["bedrock.*.amazonaws.com", "bedrock-runtime.*.amazonaws.com"];
|
|
4033
|
-
case "google-vertex":
|
|
4034
|
-
return ["*.aiplatform.googleapis.com"];
|
|
4035
|
-
case "deepseek":
|
|
4036
|
-
return ["api.deepseek.com"];
|
|
4037
|
-
case "ollama":
|
|
4038
|
-
return [];
|
|
4039
|
-
default:
|
|
4040
|
-
return [];
|
|
4041
|
-
}
|
|
4042
|
-
}
|
|
4043
|
-
function collectSkillAllowedDomains(config, expertKey) {
|
|
4044
|
-
const domains = [];
|
|
4045
|
-
const expert = config.experts?.[expertKey];
|
|
4046
|
-
if (!expert?.skills) return domains;
|
|
4047
|
-
for (const skill of Object.values(expert.skills)) {
|
|
4048
|
-
if (skill.type === "mcpStdioSkill" || skill.type === "mcpSseSkill") {
|
|
4049
|
-
const skillDomains = skill.allowedDomains;
|
|
4050
|
-
if (skillDomains) {
|
|
4051
|
-
domains.push(...skillDomains);
|
|
4052
|
-
}
|
|
4053
|
-
}
|
|
4054
|
-
}
|
|
4055
|
-
return domains;
|
|
4056
|
-
}
|
|
4057
|
-
function collectAllowedDomains(config, expertKey) {
|
|
4058
|
-
const domains = /* @__PURE__ */ new Set();
|
|
4059
|
-
domains.add("registry.npmjs.org");
|
|
4060
|
-
const perstackApiDomain = getPerstackApiDomain(config.perstackApiBaseUrl);
|
|
4061
|
-
if (perstackApiDomain) {
|
|
4062
|
-
domains.add(perstackApiDomain);
|
|
4063
|
-
}
|
|
4064
|
-
const skillDomains = collectSkillAllowedDomains(config, expertKey);
|
|
4065
|
-
for (const domain of skillDomains) {
|
|
4066
|
-
domains.add(domain);
|
|
4067
|
-
}
|
|
4068
|
-
const providerDomains = getProviderApiDomains(config.provider);
|
|
4069
|
-
for (const domain of providerDomains) {
|
|
4070
|
-
domains.add(domain);
|
|
4071
|
-
}
|
|
4072
|
-
return Array.from(domains);
|
|
4073
|
-
}
|
|
4074
|
-
function getPerstackApiDomain(baseUrl) {
|
|
4075
|
-
const url = baseUrl ?? "https://api.perstack.ai";
|
|
4076
|
-
try {
|
|
4077
|
-
return new URL(url).hostname;
|
|
4078
|
-
} catch {
|
|
4079
|
-
return "api.perstack.ai";
|
|
4080
|
-
}
|
|
4081
|
-
}
|
|
4082
|
-
function normalizeTrailingDot(domain) {
|
|
4083
|
-
return domain.endsWith(".") ? domain.slice(0, -1) : domain;
|
|
4084
|
-
}
|
|
4085
|
-
function generateSquidAllowlistAcl(domains) {
|
|
4086
|
-
const normalizedDomains = domains.map(normalizeTrailingDot);
|
|
4087
|
-
const wildcards = /* @__PURE__ */ new Set();
|
|
4088
|
-
for (const domain of normalizedDomains) {
|
|
4089
|
-
if (domain.startsWith("*.")) {
|
|
4090
|
-
wildcards.add(domain.slice(2));
|
|
4091
|
-
}
|
|
4092
|
-
}
|
|
4093
|
-
const seen = /* @__PURE__ */ new Set();
|
|
4094
|
-
const lines = [];
|
|
4095
|
-
for (const domain of normalizedDomains) {
|
|
4096
|
-
if (domain.startsWith("*.")) {
|
|
4097
|
-
const squidFormat = `.${domain.slice(2)}`;
|
|
4098
|
-
if (!seen.has(squidFormat)) {
|
|
4099
|
-
seen.add(squidFormat);
|
|
4100
|
-
lines.push(squidFormat);
|
|
4101
|
-
}
|
|
4102
|
-
} else {
|
|
4103
|
-
const isSubdomainOfWildcard = Array.from(wildcards).some((w) => domain.endsWith(`.${w}`));
|
|
4104
|
-
if (!isSubdomainOfWildcard && !seen.has(domain)) {
|
|
4105
|
-
seen.add(domain);
|
|
4106
|
-
lines.push(domain);
|
|
4107
|
-
}
|
|
4108
|
-
}
|
|
4109
|
-
}
|
|
4110
|
-
return lines.join("\n");
|
|
4111
|
-
}
|
|
4112
|
-
function generateSquidConf(options) {
|
|
4113
|
-
const { allowedDomains, verbose } = Array.isArray(options) || options === void 0 ? { allowedDomains: options, verbose: false } : options;
|
|
4114
|
-
const lines = [];
|
|
4115
|
-
lines.push("http_port 3128");
|
|
4116
|
-
lines.push("");
|
|
4117
|
-
lines.push("acl SSL_ports port 443");
|
|
4118
|
-
lines.push("acl Safe_ports port 443");
|
|
4119
|
-
lines.push("acl CONNECT method CONNECT");
|
|
4120
|
-
lines.push("");
|
|
4121
|
-
lines.push("acl internal_nets dst 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 127.0.0.0/8");
|
|
4122
|
-
lines.push("acl link_local dst 169.254.0.0/16");
|
|
4123
|
-
lines.push("acl internal_nets_v6 dst ::1/128 fe80::/10 fc00::/7");
|
|
4124
|
-
lines.push("http_access deny internal_nets");
|
|
4125
|
-
lines.push("http_access deny link_local");
|
|
4126
|
-
lines.push("http_access deny internal_nets_v6");
|
|
4127
|
-
lines.push("");
|
|
4128
|
-
lines.push("http_access deny !Safe_ports");
|
|
4129
|
-
lines.push("http_access deny CONNECT !SSL_ports");
|
|
4130
|
-
lines.push("http_access deny !CONNECT");
|
|
4131
|
-
lines.push("");
|
|
4132
|
-
if (allowedDomains && allowedDomains.length > 0) {
|
|
4133
|
-
lines.push('acl allowed_domains dstdomain "/etc/squid/allowed_domains.txt"');
|
|
4134
|
-
lines.push("");
|
|
4135
|
-
lines.push("http_access allow CONNECT SSL_ports allowed_domains");
|
|
4136
|
-
} else {
|
|
4137
|
-
lines.push("http_access allow CONNECT SSL_ports");
|
|
4138
|
-
}
|
|
4139
|
-
lines.push("http_access deny all");
|
|
4140
|
-
lines.push("");
|
|
4141
|
-
if (verbose) {
|
|
4142
|
-
lines.push("logformat perstack %tl %Ss %rm %ru %Hs");
|
|
4143
|
-
lines.push("access_log stdio:/dev/stdout perstack");
|
|
4144
|
-
} else {
|
|
4145
|
-
lines.push("access_log none");
|
|
4146
|
-
}
|
|
4147
|
-
lines.push("cache_log /dev/null");
|
|
4148
|
-
lines.push("");
|
|
4149
|
-
return lines.join("\n");
|
|
4150
|
-
}
|
|
4151
|
-
function generateProxyDockerfile(hasAllowlist) {
|
|
4152
|
-
const lines = [];
|
|
4153
|
-
lines.push("FROM debian:bookworm-slim");
|
|
4154
|
-
lines.push("");
|
|
4155
|
-
lines.push("RUN apt-get update && apt-get install -y --no-install-recommends \\");
|
|
4156
|
-
lines.push(" squid \\");
|
|
4157
|
-
lines.push(" dnsmasq \\");
|
|
4158
|
-
lines.push(" netcat-openbsd \\");
|
|
4159
|
-
lines.push(" && rm -rf /var/lib/apt/lists/*");
|
|
4160
|
-
lines.push("");
|
|
4161
|
-
lines.push("COPY squid.conf /etc/squid/squid.conf");
|
|
4162
|
-
{
|
|
4163
|
-
lines.push("COPY allowed_domains.txt /etc/squid/allowed_domains.txt");
|
|
4164
|
-
}
|
|
4165
|
-
lines.push("COPY start.sh /start.sh");
|
|
4166
|
-
lines.push("RUN chmod +x /start.sh");
|
|
4167
|
-
lines.push("");
|
|
4168
|
-
lines.push("EXPOSE 3128 53/udp");
|
|
4169
|
-
lines.push("");
|
|
4170
|
-
lines.push('CMD ["/start.sh"]');
|
|
4171
|
-
lines.push("");
|
|
4172
|
-
return lines.join("\n");
|
|
4173
|
-
}
|
|
4174
|
-
function generateProxyStartScript() {
|
|
4175
|
-
const lines = [];
|
|
4176
|
-
lines.push("#!/bin/sh");
|
|
4177
|
-
lines.push("# Allow proxy user to write to stdout for access logs");
|
|
4178
|
-
lines.push("chmod 666 /dev/stdout 2>/dev/null || true");
|
|
4179
|
-
lines.push("dnsmasq --no-daemon --server=8.8.8.8 --server=8.8.4.4 &");
|
|
4180
|
-
lines.push("exec squid -N -d 1");
|
|
4181
|
-
lines.push("");
|
|
4182
|
-
return lines.join("\n");
|
|
4183
|
-
}
|
|
4184
|
-
function generateProxyComposeService(internalNetworkName, externalNetworkName) {
|
|
4185
|
-
const lines = [];
|
|
4186
|
-
lines.push(" proxy:");
|
|
4187
|
-
lines.push(" build:");
|
|
4188
|
-
lines.push(" context: ./proxy");
|
|
4189
|
-
lines.push(" dockerfile: Dockerfile");
|
|
4190
|
-
lines.push(" networks:");
|
|
4191
|
-
lines.push(` - ${internalNetworkName}`);
|
|
4192
|
-
lines.push(` - ${externalNetworkName}`);
|
|
4193
|
-
lines.push(" healthcheck:");
|
|
4194
|
-
lines.push(' test: ["CMD-SHELL", "nc -z localhost 3128 || exit 1"]');
|
|
4195
|
-
lines.push(" interval: 2s");
|
|
4196
|
-
lines.push(" timeout: 5s");
|
|
4197
|
-
lines.push(" retries: 10");
|
|
4198
|
-
return lines.join("\n");
|
|
4199
|
-
}
|
|
4200
|
-
|
|
4201
|
-
// ../../packages/runtimes/docker/src/compose-generator.ts
|
|
4202
|
-
function validateWorkspacePath(path11) {
|
|
4203
|
-
if (path11.includes("..") || path11.includes("\n") || path11.includes(";") || path11.includes("$")) {
|
|
4204
|
-
throw new Error(`Invalid workspace path: ${path11}`);
|
|
4205
|
-
}
|
|
4206
|
-
}
|
|
4207
|
-
function generateComposeFile(options) {
|
|
4208
|
-
const { proxyEnabled, networkName, envKeys, workspacePath, additionalVolumes } = options;
|
|
4209
|
-
if (workspacePath) {
|
|
4210
|
-
validateWorkspacePath(workspacePath);
|
|
4211
|
-
}
|
|
4212
|
-
for (const volume of additionalVolumes ?? []) {
|
|
4213
|
-
const hostPath = volume.split(":")[0];
|
|
4214
|
-
if (hostPath) {
|
|
4215
|
-
validateWorkspacePath(hostPath);
|
|
4216
|
-
}
|
|
4217
|
-
}
|
|
4218
|
-
const internalNetworkName = `${networkName}-internal`;
|
|
4219
|
-
const lines = [];
|
|
4220
|
-
lines.push("services:");
|
|
4221
|
-
lines.push(" runtime:");
|
|
4222
|
-
lines.push(" build:");
|
|
4223
|
-
lines.push(" context: .");
|
|
4224
|
-
lines.push(" dockerfile: Dockerfile");
|
|
4225
|
-
const allEnvKeys = [...envKeys];
|
|
4226
|
-
if (proxyEnabled) {
|
|
4227
|
-
allEnvKeys.push("HTTP_PROXY=http://proxy:3128");
|
|
4228
|
-
allEnvKeys.push("HTTPS_PROXY=http://proxy:3128");
|
|
4229
|
-
allEnvKeys.push("http_proxy=http://proxy:3128");
|
|
4230
|
-
allEnvKeys.push("https_proxy=http://proxy:3128");
|
|
4231
|
-
allEnvKeys.push("NO_PROXY=localhost,127.0.0.1");
|
|
4232
|
-
allEnvKeys.push("no_proxy=localhost,127.0.0.1");
|
|
4233
|
-
}
|
|
4234
|
-
if (allEnvKeys.length > 0) {
|
|
4235
|
-
lines.push(" environment:");
|
|
4236
|
-
for (const key of allEnvKeys) {
|
|
4237
|
-
lines.push(` - ${key}`);
|
|
4238
|
-
}
|
|
4239
|
-
}
|
|
4240
|
-
const hasVolumes = workspacePath || additionalVolumes && additionalVolumes.length > 0;
|
|
4241
|
-
if (hasVolumes) {
|
|
4242
|
-
lines.push(" volumes:");
|
|
4243
|
-
if (workspacePath) {
|
|
4244
|
-
lines.push(` - ${workspacePath}:/workspace:rw`);
|
|
4245
|
-
}
|
|
4246
|
-
for (const volume of additionalVolumes ?? []) {
|
|
4247
|
-
lines.push(` - ${volume}`);
|
|
4248
|
-
}
|
|
4249
|
-
}
|
|
4250
|
-
lines.push(" stdin_open: true");
|
|
4251
|
-
lines.push(" tty: true");
|
|
4252
|
-
lines.push(" cap_drop:");
|
|
4253
|
-
lines.push(" - ALL");
|
|
4254
|
-
lines.push(" security_opt:");
|
|
4255
|
-
lines.push(" - no-new-privileges:true");
|
|
4256
|
-
lines.push(" read_only: true");
|
|
4257
|
-
lines.push(" tmpfs:");
|
|
4258
|
-
lines.push(" - /tmp:size=256M,mode=1777,exec");
|
|
4259
|
-
lines.push(" - /home/perstack/.npm:size=512M,uid=999,gid=999,mode=0755,exec");
|
|
4260
|
-
lines.push(" - /home/perstack/.cache:size=256M,uid=999,gid=999,mode=0755,exec");
|
|
4261
|
-
lines.push(" deploy:");
|
|
4262
|
-
lines.push(" resources:");
|
|
4263
|
-
lines.push(" limits:");
|
|
4264
|
-
lines.push(" memory: 2G");
|
|
4265
|
-
lines.push(" cpus: '2'");
|
|
4266
|
-
lines.push(" pids: 256");
|
|
4267
|
-
lines.push(" reservations:");
|
|
4268
|
-
lines.push(" memory: 256M");
|
|
4269
|
-
if (proxyEnabled) {
|
|
4270
|
-
lines.push(" depends_on:");
|
|
4271
|
-
lines.push(" proxy:");
|
|
4272
|
-
lines.push(" condition: service_healthy");
|
|
4273
|
-
lines.push(" networks:");
|
|
4274
|
-
lines.push(` - ${internalNetworkName}`);
|
|
4275
|
-
} else {
|
|
4276
|
-
lines.push(" networks:");
|
|
4277
|
-
lines.push(` - ${networkName}`);
|
|
4278
|
-
}
|
|
4279
|
-
lines.push("");
|
|
4280
|
-
if (proxyEnabled) {
|
|
4281
|
-
lines.push(generateProxyComposeService(internalNetworkName, networkName));
|
|
4282
|
-
lines.push("");
|
|
4283
|
-
}
|
|
4284
|
-
lines.push("networks:");
|
|
4285
|
-
if (proxyEnabled) {
|
|
4286
|
-
lines.push(` ${internalNetworkName}:`);
|
|
4287
|
-
lines.push(" driver: bridge");
|
|
4288
|
-
lines.push(" internal: true");
|
|
4289
|
-
lines.push(` ${networkName}:`);
|
|
4290
|
-
lines.push(" driver: bridge");
|
|
4291
|
-
} else {
|
|
4292
|
-
lines.push(` ${networkName}:`);
|
|
4293
|
-
lines.push(" driver: bridge");
|
|
4294
|
-
}
|
|
4295
|
-
lines.push("");
|
|
4296
|
-
return lines.join("\n");
|
|
4297
|
-
}
|
|
4298
|
-
function generateBuildContext(config, expertKey, options) {
|
|
4299
|
-
const { workspacePath, verbose, additionalEnvKeys, additionalVolumes } = typeof options === "string" || options === void 0 ? {
|
|
4300
|
-
workspacePath: options,
|
|
4301
|
-
verbose: false,
|
|
4302
|
-
additionalEnvKeys: [],
|
|
4303
|
-
additionalVolumes: []
|
|
4304
|
-
} : { additionalEnvKeys: [], additionalVolumes: [], ...options };
|
|
4305
|
-
const allowedDomains = collectAllowedDomains(config, expertKey);
|
|
4306
|
-
const hasAllowlist = allowedDomains.length > 0;
|
|
4307
|
-
const dockerfile = generateDockerfile(config, expertKey, { proxyEnabled: hasAllowlist });
|
|
4308
|
-
const containerConfig = { ...config, runtime: "local" };
|
|
4309
|
-
const configToml = TOML.stringify(containerConfig);
|
|
4310
|
-
let proxyDockerfileContent = null;
|
|
4311
|
-
let proxySquidConf = null;
|
|
4312
|
-
let proxyAllowlist = null;
|
|
4313
|
-
let proxyStartScript = null;
|
|
4314
|
-
if (hasAllowlist) {
|
|
4315
|
-
proxyDockerfileContent = generateProxyDockerfile();
|
|
4316
|
-
proxySquidConf = generateSquidConf({ allowedDomains, verbose });
|
|
4317
|
-
proxyAllowlist = generateSquidAllowlistAcl(allowedDomains);
|
|
4318
|
-
proxyStartScript = generateProxyStartScript();
|
|
4319
|
-
}
|
|
4320
|
-
const envRequirements = extractRequiredEnvVars(config, expertKey);
|
|
4321
|
-
const envKeys = envRequirements.map((r) => r.name);
|
|
4322
|
-
const allEnvKeys = [.../* @__PURE__ */ new Set([...envKeys, ...additionalEnvKeys ?? []])];
|
|
4323
|
-
const resolvedWorkspacePath = workspacePath ?? "./workspace";
|
|
4324
|
-
const composeFile = generateComposeFile({
|
|
4325
|
-
proxyEnabled: hasAllowlist,
|
|
4326
|
-
networkName: "perstack-net",
|
|
4327
|
-
envKeys: allEnvKeys,
|
|
4328
|
-
workspacePath: resolvedWorkspacePath,
|
|
4329
|
-
additionalVolumes
|
|
4330
|
-
});
|
|
4331
|
-
return {
|
|
4332
|
-
dockerfile,
|
|
4333
|
-
configToml,
|
|
4334
|
-
proxyDockerfile: proxyDockerfileContent,
|
|
4335
|
-
proxySquidConf,
|
|
4336
|
-
proxyAllowlist,
|
|
4337
|
-
proxyStartScript,
|
|
4338
|
-
composeFile
|
|
4339
|
-
};
|
|
4340
|
-
}
|
|
4341
|
-
|
|
4342
|
-
// ../../packages/runtimes/docker/src/lib/output-parser.ts
|
|
4343
|
-
function parseBuildOutputLine(line) {
|
|
4344
|
-
const trimmed = line.trim();
|
|
4345
|
-
if (!trimmed) return null;
|
|
4346
|
-
let stage = "building";
|
|
4347
|
-
if (trimmed.includes("Pulling") || trimmed.includes("pull")) {
|
|
4348
|
-
stage = "pulling";
|
|
4349
|
-
}
|
|
4350
|
-
const serviceMatch = trimmed.match(/^\s*#\d+\s+\[([^\]]+)\]/);
|
|
4351
|
-
const service = serviceMatch?.[1]?.split(" ")[0] ?? "runtime";
|
|
4352
|
-
return { stage, service, message: trimmed };
|
|
4353
|
-
}
|
|
4354
|
-
function parseProxyLogLine(line) {
|
|
4355
|
-
const logContent = line.replace(/^[^|]+\|\s*/, "");
|
|
4356
|
-
const connectMatch = logContent.match(/CONNECT\s+([^:\s]+):(\d+)/);
|
|
4357
|
-
if (!connectMatch) return null;
|
|
4358
|
-
const domain = connectMatch[1];
|
|
4359
|
-
const port = Number.parseInt(connectMatch[2], 10);
|
|
4360
|
-
if (!domain || Number.isNaN(port)) return null;
|
|
4361
|
-
const isBlocked = logContent.includes("TCP_DENIED") || logContent.includes("/403");
|
|
4362
|
-
const isAllowed = logContent.includes("TCP_TUNNEL") || logContent.includes("HIER_DIRECT") || logContent.includes("/200");
|
|
4363
|
-
if (isBlocked) {
|
|
4364
|
-
return {
|
|
4365
|
-
action: "blocked",
|
|
4366
|
-
domain,
|
|
4367
|
-
port,
|
|
4368
|
-
reason: "Domain not in allowlist"
|
|
4369
|
-
};
|
|
4370
|
-
}
|
|
4371
|
-
if (isAllowed) {
|
|
4372
|
-
return {
|
|
4373
|
-
action: "allowed",
|
|
4374
|
-
domain,
|
|
4375
|
-
port
|
|
4376
|
-
};
|
|
4377
|
-
}
|
|
4378
|
-
return null;
|
|
4379
|
-
}
|
|
4380
|
-
|
|
4381
|
-
// ../../packages/runtimes/docker/src/lib/stream-buffer.ts
|
|
4382
|
-
var StreamBuffer = class {
|
|
4383
|
-
buffer = "";
|
|
4384
|
-
processChunk(chunk, onLine) {
|
|
4385
|
-
this.buffer += chunk;
|
|
4386
|
-
const lines = this.buffer.split("\n");
|
|
4387
|
-
this.buffer = lines.pop() ?? "";
|
|
4388
|
-
for (const line of lines) {
|
|
4389
|
-
onLine(line);
|
|
4390
|
-
}
|
|
4391
|
-
}
|
|
4392
|
-
flush(onLine) {
|
|
4393
|
-
if (this.buffer.trim()) {
|
|
4394
|
-
onLine(this.buffer);
|
|
4395
|
-
this.buffer = "";
|
|
4396
|
-
}
|
|
4397
|
-
}
|
|
4398
|
-
getRemaining() {
|
|
4399
|
-
return this.buffer;
|
|
4400
|
-
}
|
|
4401
|
-
};
|
|
4402
|
-
|
|
4403
|
-
// ../../packages/runtimes/docker/src/lib/build-strategy.ts
|
|
4404
|
-
var QuietBuildStrategy = class {
|
|
4405
|
-
async build(context, execCommand, _processFactory) {
|
|
4406
|
-
const composeFile = path10.join(context.buildDir, "docker-compose.yml");
|
|
4407
|
-
const args = ["docker", "compose", "-f", composeFile, "build"];
|
|
4408
|
-
const result = await execCommand(args);
|
|
4409
|
-
if (result.exitCode !== 0) {
|
|
4410
|
-
throw new Error(`Docker build failed: ${result.stderr}`);
|
|
4411
|
-
}
|
|
4412
|
-
}
|
|
4413
|
-
};
|
|
4414
|
-
var VerboseBuildStrategy = class {
|
|
4415
|
-
async build(context, _execCommand, processFactory) {
|
|
4416
|
-
const composeFile = path10.join(context.buildDir, "docker-compose.yml");
|
|
4417
|
-
const args = ["compose", "-f", composeFile, "build", "--progress=plain"];
|
|
4418
|
-
const exitCode = await this.execCommandWithOutput(args, processFactory);
|
|
4419
|
-
if (exitCode !== 0) {
|
|
4420
|
-
throw new Error(`Docker build failed with exit code ${exitCode}`);
|
|
4421
|
-
}
|
|
4422
|
-
}
|
|
4423
|
-
execCommandWithOutput(args, processFactory) {
|
|
4424
|
-
return new Promise((resolve2) => {
|
|
4425
|
-
const proc = processFactory("docker", args, {
|
|
4426
|
-
cwd: process.cwd(),
|
|
4427
|
-
stdio: ["pipe", process.stderr, process.stderr]
|
|
4428
|
-
});
|
|
4429
|
-
proc.on("close", (code) => resolve2(code ?? 127));
|
|
4430
|
-
proc.on("error", () => resolve2(127));
|
|
4431
|
-
});
|
|
4432
|
-
}
|
|
4433
|
-
};
|
|
4434
|
-
var VerboseProgressBuildStrategy = class {
|
|
4435
|
-
async build(context, _execCommand, processFactory) {
|
|
4436
|
-
const { buildDir, jobId, runId, eventListener } = context;
|
|
4437
|
-
if (!jobId || !runId || !eventListener) {
|
|
4438
|
-
throw new Error("VerboseProgressBuildStrategy requires jobId, runId, and eventListener");
|
|
4439
|
-
}
|
|
4440
|
-
const composeFile = path10.join(buildDir, "docker-compose.yml");
|
|
4441
|
-
const args = ["compose", "-f", composeFile, "build", "--progress=plain"];
|
|
4442
|
-
eventListener(
|
|
4443
|
-
createRuntimeEvent("dockerBuildProgress", jobId, runId, {
|
|
4444
|
-
stage: "building",
|
|
4445
|
-
service: "runtime",
|
|
4446
|
-
message: "Starting Docker build..."
|
|
4447
|
-
})
|
|
4448
|
-
);
|
|
4449
|
-
const exitCode = await this.execCommandWithBuildProgress(
|
|
4450
|
-
args,
|
|
4451
|
-
jobId,
|
|
4452
|
-
runId,
|
|
4453
|
-
eventListener,
|
|
4454
|
-
processFactory
|
|
4455
|
-
);
|
|
4456
|
-
if (exitCode !== 0) {
|
|
4457
|
-
eventListener(
|
|
4458
|
-
createRuntimeEvent("dockerBuildProgress", jobId, runId, {
|
|
4459
|
-
stage: "error",
|
|
4460
|
-
service: "runtime",
|
|
4461
|
-
message: `Docker build failed with exit code ${exitCode}`
|
|
4462
|
-
})
|
|
4463
|
-
);
|
|
4464
|
-
throw new Error(`Docker build failed with exit code ${exitCode}`);
|
|
4465
|
-
}
|
|
4466
|
-
eventListener(
|
|
4467
|
-
createRuntimeEvent("dockerBuildProgress", jobId, runId, {
|
|
4468
|
-
stage: "complete",
|
|
4469
|
-
service: "runtime",
|
|
4470
|
-
message: "Docker build completed"
|
|
4471
|
-
})
|
|
4472
|
-
);
|
|
4473
|
-
}
|
|
4474
|
-
execCommandWithBuildProgress(args, jobId, runId, eventListener, processFactory) {
|
|
4475
|
-
return new Promise((resolve2) => {
|
|
4476
|
-
const proc = processFactory("docker", args, {
|
|
4477
|
-
cwd: process.cwd(),
|
|
4478
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
4479
|
-
});
|
|
4480
|
-
const buffer = new StreamBuffer();
|
|
4481
|
-
const processLine = (line) => {
|
|
4482
|
-
const parsed = parseBuildOutputLine(line);
|
|
4483
|
-
if (parsed) {
|
|
4484
|
-
eventListener(
|
|
4485
|
-
createRuntimeEvent("dockerBuildProgress", jobId, runId, {
|
|
4486
|
-
stage: parsed.stage,
|
|
4487
|
-
service: parsed.service,
|
|
4488
|
-
message: parsed.message
|
|
4489
|
-
})
|
|
4490
|
-
);
|
|
4491
|
-
}
|
|
4492
|
-
};
|
|
4493
|
-
proc.stdout?.on("data", (data) => buffer.processChunk(data.toString(), processLine));
|
|
4494
|
-
proc.stderr?.on("data", (data) => buffer.processChunk(data.toString(), processLine));
|
|
4495
|
-
proc.on("close", (code) => {
|
|
4496
|
-
buffer.flush(processLine);
|
|
4497
|
-
resolve2(code ?? 127);
|
|
4498
|
-
});
|
|
4499
|
-
proc.on("error", () => resolve2(127));
|
|
4500
|
-
});
|
|
4501
|
-
}
|
|
4502
|
-
};
|
|
4503
|
-
function selectBuildStrategy(verbose, hasEventListener, hasJobAndRunId) {
|
|
4504
|
-
if (verbose && hasEventListener && hasJobAndRunId) {
|
|
4505
|
-
return new VerboseProgressBuildStrategy();
|
|
4506
|
-
}
|
|
4507
|
-
if (verbose) {
|
|
4508
|
-
return new VerboseBuildStrategy();
|
|
4509
|
-
}
|
|
4510
|
-
return new QuietBuildStrategy();
|
|
4511
|
-
}
|
|
4512
|
-
|
|
4513
|
-
// ../../packages/runtimes/docker/src/lib/cli-builder.ts
|
|
4514
|
-
function buildCliArgs(setting) {
|
|
4515
|
-
const args = [];
|
|
4516
|
-
if (setting.jobId !== void 0) {
|
|
4517
|
-
args.push("--job-id", setting.jobId);
|
|
4518
|
-
}
|
|
4519
|
-
if (setting.runId !== void 0) {
|
|
4520
|
-
args.push("--run-id", setting.runId);
|
|
4521
|
-
}
|
|
4522
|
-
if (setting.model !== void 0) {
|
|
4523
|
-
args.push("--model", setting.model);
|
|
4524
|
-
}
|
|
4525
|
-
const maxSteps = setting.maxSteps ?? 100;
|
|
4526
|
-
args.push("--max-steps", String(maxSteps));
|
|
4527
|
-
if (setting.maxRetries !== void 0) {
|
|
4528
|
-
args.push("--max-retries", String(setting.maxRetries));
|
|
4529
|
-
}
|
|
4530
|
-
if (setting.timeout !== void 0) {
|
|
4531
|
-
args.push("--timeout", String(setting.timeout));
|
|
4532
|
-
}
|
|
4533
|
-
if (setting.input.interactiveToolCallResult) {
|
|
4534
|
-
args.push("-i");
|
|
4535
|
-
args.push(JSON.stringify(setting.input.interactiveToolCallResult));
|
|
4536
|
-
} else {
|
|
4537
|
-
args.push(setting.input.text ?? "");
|
|
4538
|
-
}
|
|
4539
|
-
return args;
|
|
4540
|
-
}
|
|
4541
|
-
|
|
4542
|
-
// ../../packages/runtimes/docker/src/lib/constants.ts
|
|
4543
|
-
var TERMINAL_EVENT_TYPES = [
|
|
4544
|
-
"completeRun",
|
|
4545
|
-
"stopRunByInteractiveTool",
|
|
4546
|
-
"stopRunByDelegate",
|
|
4547
|
-
"stopRunByExceededMaxSteps"
|
|
4548
|
-
];
|
|
4549
|
-
|
|
4550
|
-
// ../../packages/runtimes/docker/src/lib/event-parser.ts
|
|
4551
|
-
function parseContainerEvent(line) {
|
|
4552
|
-
const trimmed = line.trim();
|
|
4553
|
-
if (!trimmed) return null;
|
|
4554
|
-
let parsed;
|
|
4555
|
-
try {
|
|
4556
|
-
parsed = JSON.parse(trimmed);
|
|
4557
|
-
} catch {
|
|
4558
|
-
return null;
|
|
4559
|
-
}
|
|
4560
|
-
if (isTerminalEvent(parsed) && "checkpoint" in parsed) {
|
|
4561
|
-
try {
|
|
4562
|
-
parsed.checkpoint = checkpointSchema.parse(parsed.checkpoint);
|
|
4563
|
-
} catch {
|
|
4564
|
-
return null;
|
|
4565
|
-
}
|
|
4566
|
-
}
|
|
4567
|
-
return parsed;
|
|
4568
|
-
}
|
|
4569
|
-
function isTerminalEvent(event) {
|
|
4570
|
-
return TERMINAL_EVENT_TYPES.includes(event.type);
|
|
4571
|
-
}
|
|
4572
|
-
function findTerminalEvent(events) {
|
|
4573
|
-
return events.find((e) => isTerminalEvent(e) && "checkpoint" in e);
|
|
4574
|
-
}
|
|
4575
|
-
var defaultProcessFactory = (command, args, options) => {
|
|
4576
|
-
return spawn(command, args, options);
|
|
4577
|
-
};
|
|
4578
|
-
|
|
4579
|
-
// ../../packages/runtimes/docker/src/docker-adapter.ts
|
|
4580
|
-
var DockerAdapter = class extends BaseAdapter {
|
|
4581
|
-
name = "docker";
|
|
4582
|
-
version = "0.0.1";
|
|
4583
|
-
processFactory;
|
|
4584
|
-
constructor(processFactory = defaultProcessFactory) {
|
|
4585
|
-
super();
|
|
4586
|
-
this.processFactory = processFactory;
|
|
4587
|
-
}
|
|
4588
|
-
createProcess(command, args, options) {
|
|
4589
|
-
return this.processFactory(command, args, options);
|
|
4590
|
-
}
|
|
4591
|
-
createPrerequisiteError(message, helpUrl) {
|
|
4592
|
-
return { ok: false, error: { type: "cli-not-found", message, helpUrl } };
|
|
4593
|
-
}
|
|
4594
|
-
async checkPrerequisites() {
|
|
4595
|
-
const cliNotFoundError = this.createPrerequisiteError(
|
|
4596
|
-
"Docker CLI is not installed or not in PATH.",
|
|
4597
|
-
"https://docs.docker.com/get-docker/"
|
|
4598
|
-
);
|
|
4599
|
-
const daemonNotRunningError = this.createPrerequisiteError(
|
|
4600
|
-
"Docker daemon is not running.",
|
|
4601
|
-
"https://docs.docker.com/config/daemon/start/"
|
|
4602
|
-
);
|
|
4603
|
-
try {
|
|
4604
|
-
const result = await this.execCommand(["docker", "--version"]);
|
|
4605
|
-
if (result.exitCode !== 0) return cliNotFoundError;
|
|
4606
|
-
const versionMatch = result.stdout.match(/Docker version ([\d.]+)/);
|
|
4607
|
-
this.version = versionMatch?.[1] ?? "unknown";
|
|
4608
|
-
} catch {
|
|
4609
|
-
return cliNotFoundError;
|
|
4610
|
-
}
|
|
4611
|
-
try {
|
|
4612
|
-
const pingResult = await this.execCommand(["docker", "info"]);
|
|
4613
|
-
if (pingResult.exitCode !== 0) return daemonNotRunningError;
|
|
4614
|
-
} catch {
|
|
4615
|
-
return daemonNotRunningError;
|
|
4616
|
-
}
|
|
4617
|
-
return { ok: true };
|
|
4618
|
-
}
|
|
4619
|
-
convertExpert(expert) {
|
|
4620
|
-
return { instruction: expert.instruction };
|
|
4621
|
-
}
|
|
4622
|
-
async run(params) {
|
|
4623
|
-
const { setting, config, eventListener, workspace, additionalEnvKeys, additionalVolumes } = params;
|
|
4624
|
-
if (!config) {
|
|
4625
|
-
throw new Error("DockerAdapter requires config in AdapterRunParams");
|
|
4626
|
-
}
|
|
4627
|
-
if (!setting.jobId || !setting.runId) {
|
|
4628
|
-
throw new Error("DockerAdapter requires jobId and runId in setting");
|
|
4629
|
-
}
|
|
4630
|
-
const events = [];
|
|
4631
|
-
const resolvedWorkspace = this.resolveWorkspacePath(workspace);
|
|
4632
|
-
const { expertKey, jobId, runId } = setting;
|
|
4633
|
-
const buildDir = await this.prepareBuildContext(
|
|
4634
|
-
config,
|
|
4635
|
-
expertKey,
|
|
4636
|
-
resolvedWorkspace,
|
|
4637
|
-
setting.verbose,
|
|
4638
|
-
additionalEnvKeys,
|
|
4639
|
-
additionalVolumes
|
|
4640
|
-
);
|
|
4641
|
-
let signalReceived = false;
|
|
4642
|
-
const signalHandler = async (signal) => {
|
|
4643
|
-
if (signalReceived) return;
|
|
4644
|
-
signalReceived = true;
|
|
4645
|
-
await this.cleanup(buildDir);
|
|
4646
|
-
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
4647
|
-
};
|
|
4648
|
-
process.on("SIGINT", () => signalHandler("SIGINT"));
|
|
4649
|
-
process.on("SIGTERM", () => signalHandler("SIGTERM"));
|
|
4650
|
-
try {
|
|
4651
|
-
const buildStartEvent = createRuntimeEvent("dockerBuildProgress", jobId, runId, {
|
|
4652
|
-
stage: "building",
|
|
4653
|
-
service: "runtime",
|
|
4654
|
-
message: "Building Docker images..."
|
|
4655
|
-
});
|
|
4656
|
-
events.push(buildStartEvent);
|
|
4657
|
-
eventListener?.(buildStartEvent);
|
|
4658
|
-
await this.buildImages(
|
|
4659
|
-
buildDir,
|
|
4660
|
-
setting.verbose,
|
|
4661
|
-
jobId,
|
|
4662
|
-
runId,
|
|
4663
|
-
eventListener ? (event) => {
|
|
4664
|
-
events.push(event);
|
|
4665
|
-
eventListener(event);
|
|
4666
|
-
} : void 0
|
|
4667
|
-
);
|
|
4668
|
-
const buildCompleteEvent = createRuntimeEvent("dockerBuildProgress", jobId, runId, {
|
|
4669
|
-
stage: "complete",
|
|
4670
|
-
service: "runtime",
|
|
4671
|
-
message: "Docker images built successfully"
|
|
4672
|
-
});
|
|
4673
|
-
events.push(buildCompleteEvent);
|
|
4674
|
-
eventListener?.(buildCompleteEvent);
|
|
4675
|
-
const envRequirements = extractRequiredEnvVars(config, expertKey);
|
|
4676
|
-
const envSource = { ...process.env, ...setting.env };
|
|
4677
|
-
const { resolved: envVars, missing } = resolveEnvValues(envRequirements, envSource);
|
|
4678
|
-
if (missing.length > 0) {
|
|
4679
|
-
throw new Error(`Missing required environment variables: ${missing.join(", ")}`);
|
|
4680
|
-
}
|
|
4681
|
-
const cliArgs = buildCliArgs(setting);
|
|
4682
|
-
const maxSteps = setting.maxSteps ?? 100;
|
|
4683
|
-
const processTimeout = (setting.timeout ?? 6e4) * maxSteps;
|
|
4684
|
-
const result = await this.runContainer(
|
|
4685
|
-
buildDir,
|
|
4686
|
-
cliArgs,
|
|
4687
|
-
envVars,
|
|
4688
|
-
processTimeout,
|
|
4689
|
-
setting.verbose,
|
|
4690
|
-
jobId,
|
|
4691
|
-
runId,
|
|
4692
|
-
(event) => {
|
|
4693
|
-
events.push(event);
|
|
4694
|
-
eventListener?.(event);
|
|
4695
|
-
}
|
|
4696
|
-
);
|
|
4697
|
-
if (result.exitCode !== 0) {
|
|
4698
|
-
throw new Error(
|
|
4699
|
-
`Docker container failed with exit code ${result.exitCode}: ${result.stderr}`
|
|
4700
|
-
);
|
|
4701
|
-
}
|
|
4702
|
-
const terminalEvent = findTerminalEvent(events);
|
|
4703
|
-
if (!terminalEvent?.checkpoint) {
|
|
4704
|
-
throw new Error("No terminal event with checkpoint received from container");
|
|
4705
|
-
}
|
|
4706
|
-
return { checkpoint: terminalEvent.checkpoint, events };
|
|
4707
|
-
} finally {
|
|
4708
|
-
process.removeAllListeners("SIGINT");
|
|
4709
|
-
process.removeAllListeners("SIGTERM");
|
|
4710
|
-
await this.cleanup(buildDir);
|
|
4711
|
-
}
|
|
4712
|
-
}
|
|
4713
|
-
resolveWorkspacePath(workspace) {
|
|
4714
|
-
if (!workspace) return void 0;
|
|
4715
|
-
const resolved = path10.resolve(workspace);
|
|
4716
|
-
if (!fs.existsSync(resolved)) {
|
|
4717
|
-
throw new Error(`Workspace path does not exist: ${resolved}`);
|
|
4718
|
-
}
|
|
4719
|
-
const stats = fs.statSync(resolved);
|
|
4720
|
-
if (!stats.isDirectory()) {
|
|
4721
|
-
throw new Error(`Workspace path is not a directory: ${resolved}`);
|
|
4722
|
-
}
|
|
4723
|
-
return resolved;
|
|
4724
|
-
}
|
|
4725
|
-
async prepareBuildContext(config, expertKey, workspace, verbose, additionalEnvKeys, additionalVolumes) {
|
|
4726
|
-
const buildDir = fs.mkdtempSync(path10.join(os.tmpdir(), "perstack-docker-"));
|
|
4727
|
-
const context = generateBuildContext(config, expertKey, {
|
|
4728
|
-
workspacePath: workspace,
|
|
4729
|
-
verbose,
|
|
4730
|
-
additionalEnvKeys,
|
|
4731
|
-
additionalVolumes
|
|
4732
|
-
});
|
|
4733
|
-
fs.writeFileSync(path10.join(buildDir, "Dockerfile"), context.dockerfile);
|
|
4734
|
-
fs.writeFileSync(path10.join(buildDir, "perstack.toml"), context.configToml);
|
|
4735
|
-
fs.writeFileSync(path10.join(buildDir, "docker-compose.yml"), context.composeFile);
|
|
4736
|
-
if (context.proxyDockerfile) {
|
|
4737
|
-
const proxyDir = path10.join(buildDir, "proxy");
|
|
4738
|
-
fs.mkdirSync(proxyDir);
|
|
4739
|
-
fs.writeFileSync(path10.join(proxyDir, "Dockerfile"), context.proxyDockerfile);
|
|
4740
|
-
if (context.proxySquidConf) {
|
|
4741
|
-
fs.writeFileSync(path10.join(proxyDir, "squid.conf"), context.proxySquidConf);
|
|
4742
|
-
}
|
|
4743
|
-
if (context.proxyAllowlist) {
|
|
4744
|
-
fs.writeFileSync(path10.join(proxyDir, "allowed_domains.txt"), context.proxyAllowlist);
|
|
4745
|
-
}
|
|
4746
|
-
if (context.proxyStartScript) {
|
|
4747
|
-
fs.writeFileSync(path10.join(proxyDir, "start.sh"), context.proxyStartScript);
|
|
4748
|
-
}
|
|
4749
|
-
}
|
|
4750
|
-
if (!workspace) {
|
|
4751
|
-
const workspaceDir = path10.join(buildDir, "workspace");
|
|
4752
|
-
fs.mkdirSync(workspaceDir);
|
|
4753
|
-
}
|
|
4754
|
-
return buildDir;
|
|
4755
|
-
}
|
|
4756
|
-
async buildImages(buildDir, verbose, jobId, runId, eventListener) {
|
|
4757
|
-
const strategy = selectBuildStrategy(verbose, !!eventListener, !!(jobId && runId));
|
|
4758
|
-
await strategy.build(
|
|
4759
|
-
{ buildDir, jobId, runId, eventListener },
|
|
4760
|
-
(args) => this.execCommand(args),
|
|
4761
|
-
this.processFactory
|
|
4762
|
-
);
|
|
4763
|
-
}
|
|
4764
|
-
emitContainerStatus(eventListener, jobId, runId, status, service, message) {
|
|
4765
|
-
eventListener(
|
|
4766
|
-
createRuntimeEvent("dockerContainerStatus", jobId, runId, { status, service, message })
|
|
4767
|
-
);
|
|
4768
|
-
}
|
|
4769
|
-
async runContainer(buildDir, cliArgs, envVars, timeout, verbose, jobId, runId, eventListener) {
|
|
4770
|
-
const composeFile = path10.join(buildDir, "docker-compose.yml");
|
|
4771
|
-
let proxyLogProcess;
|
|
4772
|
-
if (verbose) {
|
|
4773
|
-
this.emitContainerStatus(
|
|
4774
|
-
eventListener,
|
|
4775
|
-
jobId,
|
|
4776
|
-
runId,
|
|
4777
|
-
"starting",
|
|
4778
|
-
"runtime",
|
|
4779
|
-
"Starting runtime container..."
|
|
4780
|
-
);
|
|
4781
|
-
}
|
|
4782
|
-
const envArgs = [];
|
|
4783
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
4784
|
-
envArgs.push("-e", `${key}=${value}`);
|
|
4785
|
-
}
|
|
4786
|
-
const args = ["compose", "-f", composeFile, "run", "--rm", ...envArgs, "runtime", ...cliArgs];
|
|
4787
|
-
const proc = this.createProcess("docker", args, {
|
|
4788
|
-
cwd: buildDir,
|
|
4789
|
-
env: { ...process.env },
|
|
4790
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
4791
|
-
});
|
|
4792
|
-
proc.stdin?.end();
|
|
4793
|
-
if (verbose) {
|
|
4794
|
-
proxyLogProcess = this.startProxyLogStream(composeFile, jobId, runId, eventListener);
|
|
4795
|
-
}
|
|
4796
|
-
if (verbose) {
|
|
4797
|
-
this.emitContainerStatus(
|
|
4798
|
-
eventListener,
|
|
4799
|
-
jobId,
|
|
4800
|
-
runId,
|
|
4801
|
-
"running",
|
|
4802
|
-
"runtime",
|
|
4803
|
-
"Runtime container started"
|
|
4804
|
-
);
|
|
4805
|
-
}
|
|
4806
|
-
try {
|
|
4807
|
-
const result = await this.executeWithStreaming(proc, timeout, eventListener);
|
|
4808
|
-
if (verbose) {
|
|
4809
|
-
this.emitContainerStatus(
|
|
4810
|
-
eventListener,
|
|
4811
|
-
jobId,
|
|
4812
|
-
runId,
|
|
4813
|
-
"stopped",
|
|
4814
|
-
"runtime",
|
|
4815
|
-
`Runtime container exited with code ${result.exitCode}`
|
|
4816
|
-
);
|
|
4817
|
-
}
|
|
4818
|
-
return result;
|
|
4819
|
-
} finally {
|
|
4820
|
-
if (proxyLogProcess) {
|
|
4821
|
-
proxyLogProcess.kill("SIGTERM");
|
|
4822
|
-
}
|
|
4823
|
-
}
|
|
4824
|
-
}
|
|
4825
|
-
startProxyLogStream(composeFile, jobId, runId, eventListener) {
|
|
4826
|
-
const proc = this.createProcess(
|
|
4827
|
-
"docker",
|
|
4828
|
-
["compose", "-f", composeFile, "logs", "-f", "proxy"],
|
|
4829
|
-
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
4830
|
-
);
|
|
4831
|
-
const buffer = new StreamBuffer();
|
|
4832
|
-
const processLine = (line) => {
|
|
4833
|
-
const trimmed = line.trim();
|
|
4834
|
-
if (!trimmed) return;
|
|
4835
|
-
const proxyEvent = parseProxyLogLine(trimmed);
|
|
4836
|
-
if (proxyEvent) {
|
|
4837
|
-
eventListener(createRuntimeEvent("proxyAccess", jobId, runId, proxyEvent));
|
|
4838
|
-
}
|
|
4839
|
-
};
|
|
4840
|
-
proc.stdout?.on("data", (data) => buffer.processChunk(data.toString(), processLine));
|
|
4841
|
-
proc.stderr?.on("data", (data) => buffer.processChunk(data.toString(), processLine));
|
|
4842
|
-
return proc;
|
|
4843
|
-
}
|
|
4844
|
-
executeWithStreaming(proc, timeout, eventListener) {
|
|
4845
|
-
return new Promise((resolve2, reject) => {
|
|
4846
|
-
let stdout = "";
|
|
4847
|
-
let stderr = "";
|
|
4848
|
-
const buffer = new StreamBuffer();
|
|
4849
|
-
const timer = setTimeout(() => {
|
|
4850
|
-
proc.kill("SIGTERM");
|
|
4851
|
-
reject(new Error(`Docker container timed out after ${timeout}ms`));
|
|
4852
|
-
}, timeout);
|
|
4853
|
-
const processLine = (line) => {
|
|
4854
|
-
const parsed = parseContainerEvent(line);
|
|
4855
|
-
if (parsed) eventListener(parsed);
|
|
4856
|
-
};
|
|
4857
|
-
proc.stdout?.on("data", (data) => {
|
|
4858
|
-
const chunk = data.toString();
|
|
4859
|
-
stdout += chunk;
|
|
4860
|
-
buffer.processChunk(chunk, processLine);
|
|
4861
|
-
});
|
|
4862
|
-
proc.stderr?.on("data", (data) => {
|
|
4863
|
-
stderr += data.toString();
|
|
4864
|
-
});
|
|
4865
|
-
proc.on("close", (code) => {
|
|
4866
|
-
clearTimeout(timer);
|
|
4867
|
-
buffer.flush(processLine);
|
|
4868
|
-
resolve2({ stdout, stderr, exitCode: code ?? 127 });
|
|
4869
|
-
});
|
|
4870
|
-
proc.on("error", (err) => {
|
|
4871
|
-
clearTimeout(timer);
|
|
4872
|
-
reject(err);
|
|
4873
|
-
});
|
|
4874
|
-
});
|
|
4875
|
-
}
|
|
4876
|
-
async cleanup(buildDir) {
|
|
4877
|
-
try {
|
|
4878
|
-
await this.execCommand([
|
|
4879
|
-
"docker",
|
|
4880
|
-
"compose",
|
|
4881
|
-
"-f",
|
|
4882
|
-
path10.join(buildDir, "docker-compose.yml"),
|
|
4883
|
-
"down",
|
|
4884
|
-
"--volumes",
|
|
4885
|
-
"--remove-orphans"
|
|
4886
|
-
]);
|
|
4887
|
-
} catch {
|
|
4888
|
-
}
|
|
4889
|
-
try {
|
|
4890
|
-
fs.rmSync(buildDir, { recursive: true, force: true });
|
|
4891
|
-
} catch {
|
|
4892
|
-
}
|
|
4893
|
-
}
|
|
4894
|
-
};
|
|
4895
|
-
var GeminiAdapter = class extends BaseAdapter {
|
|
4896
|
-
name = "gemini";
|
|
4897
|
-
version = "unknown";
|
|
4898
|
-
async checkPrerequisites() {
|
|
4899
|
-
try {
|
|
4900
|
-
const result = await this.execCommand(["gemini", "--version"]);
|
|
4901
|
-
if (result.exitCode !== 0) {
|
|
4902
|
-
return {
|
|
4903
|
-
ok: false,
|
|
4904
|
-
error: {
|
|
4905
|
-
type: "cli-not-found",
|
|
4906
|
-
message: "Gemini CLI is not installed.",
|
|
4907
|
-
helpUrl: "https://github.com/google-gemini/gemini-cli"
|
|
4908
|
-
}
|
|
4909
|
-
};
|
|
4910
|
-
}
|
|
4911
|
-
this.version = result.stdout.trim() || "unknown";
|
|
4912
|
-
} catch {
|
|
4913
|
-
return {
|
|
4914
|
-
ok: false,
|
|
4915
|
-
error: {
|
|
4916
|
-
type: "cli-not-found",
|
|
4917
|
-
message: "Gemini CLI is not installed.",
|
|
4918
|
-
helpUrl: "https://github.com/google-gemini/gemini-cli"
|
|
4919
|
-
}
|
|
4920
|
-
};
|
|
4921
|
-
}
|
|
4922
|
-
if (!process.env.GEMINI_API_KEY) {
|
|
1105
|
+
case "deepseek": {
|
|
1106
|
+
const apiKey = env.DEEPSEEK_API_KEY;
|
|
1107
|
+
if (!apiKey) throw new Error("DEEPSEEK_API_KEY is not set");
|
|
4923
1108
|
return {
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
helpUrl: "https://github.com/google-gemini/gemini-cli#authentication"
|
|
4929
|
-
}
|
|
1109
|
+
providerName: "deepseek",
|
|
1110
|
+
apiKey,
|
|
1111
|
+
baseUrl: setting.baseUrl ?? env.DEEPSEEK_BASE_URL,
|
|
1112
|
+
headers: setting.headers
|
|
4930
1113
|
};
|
|
4931
1114
|
}
|
|
4932
|
-
return { ok: true };
|
|
4933
|
-
}
|
|
4934
|
-
async run(params) {
|
|
4935
|
-
const { setting, eventListener, storeCheckpoint } = params;
|
|
4936
|
-
const expert = setting.experts?.[setting.expertKey];
|
|
4937
|
-
if (!expert) {
|
|
4938
|
-
throw new Error(`Expert "${setting.expertKey}" not found`);
|
|
4939
|
-
}
|
|
4940
|
-
if (!setting.jobId || !setting.runId) {
|
|
4941
|
-
throw new Error("GeminiAdapter requires jobId and runId in setting");
|
|
4942
|
-
}
|
|
4943
|
-
const { jobId, runId } = setting;
|
|
4944
|
-
const expertInfo = { key: setting.expertKey, name: expert.name, version: expert.version };
|
|
4945
|
-
const query = setting.input.text;
|
|
4946
|
-
const prompt = this.buildPrompt(expert.instruction, query);
|
|
4947
|
-
const initEvent = createRuntimeInitEvent(
|
|
4948
|
-
jobId,
|
|
4949
|
-
runId,
|
|
4950
|
-
expert.name,
|
|
4951
|
-
"gemini",
|
|
4952
|
-
this.version,
|
|
4953
|
-
query
|
|
4954
|
-
);
|
|
4955
|
-
eventListener?.(initEvent);
|
|
4956
|
-
const initialCheckpoint = {
|
|
4957
|
-
id: createId(),
|
|
4958
|
-
jobId,
|
|
4959
|
-
runId,
|
|
4960
|
-
status: "init",
|
|
4961
|
-
stepNumber: 0,
|
|
4962
|
-
messages: [],
|
|
4963
|
-
expert: expertInfo,
|
|
4964
|
-
usage: createEmptyUsage(),
|
|
4965
|
-
metadata: { runtime: "gemini" }
|
|
4966
|
-
};
|
|
4967
|
-
const startRunEvent = createStartRunEvent(jobId, runId, setting.expertKey, initialCheckpoint);
|
|
4968
|
-
eventListener?.(startRunEvent);
|
|
4969
|
-
const state = {
|
|
4970
|
-
checkpoint: initialCheckpoint,
|
|
4971
|
-
events: [initEvent, startRunEvent],
|
|
4972
|
-
pendingToolCalls: /* @__PURE__ */ new Map(),
|
|
4973
|
-
finalOutput: "",
|
|
4974
|
-
accumulatedText: "",
|
|
4975
|
-
lastStreamingText: ""
|
|
4976
|
-
};
|
|
4977
|
-
const startedAt = Date.now();
|
|
4978
|
-
const result = await this.executeGeminiCliStreaming(
|
|
4979
|
-
prompt,
|
|
4980
|
-
setting.timeout ?? 6e4,
|
|
4981
|
-
state,
|
|
4982
|
-
eventListener,
|
|
4983
|
-
storeCheckpoint
|
|
4984
|
-
);
|
|
4985
|
-
if (result.exitCode !== 0) {
|
|
4986
|
-
throw new Error(
|
|
4987
|
-
`Gemini CLI failed with exit code ${result.exitCode}: ${result.stderr || result.stdout}`
|
|
4988
|
-
);
|
|
4989
|
-
}
|
|
4990
|
-
const finalMessage = {
|
|
4991
|
-
id: createId(),
|
|
4992
|
-
type: "expertMessage",
|
|
4993
|
-
contents: [{ type: "textPart", id: createId(), text: state.finalOutput }]
|
|
4994
|
-
};
|
|
4995
|
-
const finalCheckpoint = {
|
|
4996
|
-
...state.checkpoint,
|
|
4997
|
-
status: "completed",
|
|
4998
|
-
stepNumber: state.checkpoint.stepNumber + 1,
|
|
4999
|
-
messages: [...state.checkpoint.messages, finalMessage]
|
|
5000
|
-
};
|
|
5001
|
-
await storeCheckpoint?.(finalCheckpoint);
|
|
5002
|
-
const completeEvent = createCompleteRunEvent(
|
|
5003
|
-
jobId,
|
|
5004
|
-
runId,
|
|
5005
|
-
setting.expertKey,
|
|
5006
|
-
finalCheckpoint,
|
|
5007
|
-
state.finalOutput,
|
|
5008
|
-
startedAt
|
|
5009
|
-
);
|
|
5010
|
-
state.events.push(completeEvent);
|
|
5011
|
-
eventListener?.(completeEvent);
|
|
5012
|
-
return { checkpoint: finalCheckpoint, events: state.events };
|
|
5013
1115
|
}
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
1116
|
+
}
|
|
1117
|
+
function getAllJobs2() {
|
|
1118
|
+
return getAllJobs();
|
|
1119
|
+
}
|
|
1120
|
+
function getAllRuns2() {
|
|
1121
|
+
return getAllRuns();
|
|
1122
|
+
}
|
|
1123
|
+
function getMostRecentRun() {
|
|
1124
|
+
const runs = getAllRuns2();
|
|
1125
|
+
if (runs.length === 0) {
|
|
1126
|
+
throw new Error("No runs found");
|
|
5024
1127
|
}
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
5036
|
-
});
|
|
5037
|
-
proc.stdin.end();
|
|
5038
|
-
return this.executeWithStreaming(proc, timeout, state, eventListener, storeCheckpoint);
|
|
1128
|
+
return runs[0];
|
|
1129
|
+
}
|
|
1130
|
+
function getCheckpointsByJobId2(jobId) {
|
|
1131
|
+
return getCheckpointsByJobId(jobId);
|
|
1132
|
+
}
|
|
1133
|
+
function getMostRecentCheckpoint(jobId) {
|
|
1134
|
+
const targetJobId = jobId ?? getMostRecentRun().jobId;
|
|
1135
|
+
const checkpoints = getCheckpointsByJobId2(targetJobId);
|
|
1136
|
+
if (checkpoints.length === 0) {
|
|
1137
|
+
throw new Error(`No checkpoints found for job ${targetJobId}`);
|
|
5039
1138
|
}
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
buffer += chunk;
|
|
5053
|
-
const lines = buffer.split("\n");
|
|
5054
|
-
buffer = lines.pop() ?? "";
|
|
5055
|
-
for (const line of lines) {
|
|
5056
|
-
const trimmed = line.trim();
|
|
5057
|
-
if (!trimmed) continue;
|
|
5058
|
-
try {
|
|
5059
|
-
const parsed = JSON.parse(trimmed);
|
|
5060
|
-
this.handleStreamEvent(parsed, state, eventListener, storeCheckpoint);
|
|
5061
|
-
} catch {
|
|
5062
|
-
}
|
|
5063
|
-
}
|
|
5064
|
-
});
|
|
5065
|
-
proc.stderr?.on("data", (data) => {
|
|
5066
|
-
stderr += data.toString();
|
|
5067
|
-
});
|
|
5068
|
-
proc.on("close", (code) => {
|
|
5069
|
-
clearTimeout(timer);
|
|
5070
|
-
resolve2({ stdout, stderr, exitCode: code ?? 127 });
|
|
5071
|
-
});
|
|
5072
|
-
proc.on("error", (err) => {
|
|
5073
|
-
clearTimeout(timer);
|
|
5074
|
-
reject(err);
|
|
1139
|
+
return checkpoints[checkpoints.length - 1];
|
|
1140
|
+
}
|
|
1141
|
+
function getRecentExperts(limit) {
|
|
1142
|
+
const runs = getAllRuns2();
|
|
1143
|
+
const expertMap = /* @__PURE__ */ new Map();
|
|
1144
|
+
for (const setting of runs) {
|
|
1145
|
+
const expertKey = setting.expertKey;
|
|
1146
|
+
if (!expertMap.has(expertKey) || expertMap.get(expertKey).lastUsed < setting.updatedAt) {
|
|
1147
|
+
expertMap.set(expertKey, {
|
|
1148
|
+
key: expertKey,
|
|
1149
|
+
name: expertKey,
|
|
1150
|
+
lastUsed: setting.updatedAt
|
|
5075
1151
|
});
|
|
5076
|
-
});
|
|
5077
|
-
}
|
|
5078
|
-
handleStreamEvent(parsed, state, eventListener, storeCheckpoint) {
|
|
5079
|
-
const { checkpoint } = state;
|
|
5080
|
-
const jobId = checkpoint.jobId;
|
|
5081
|
-
const runId = checkpoint.runId;
|
|
5082
|
-
const expertKey = checkpoint.expert.key;
|
|
5083
|
-
if (parsed.type === "result" && parsed.status === "success") {
|
|
5084
|
-
if (typeof parsed.output === "string") {
|
|
5085
|
-
state.finalOutput = parsed.output;
|
|
5086
|
-
}
|
|
5087
|
-
} else if (parsed.type === "message" && parsed.role === "assistant") {
|
|
5088
|
-
const content = parsed.content?.trim();
|
|
5089
|
-
if (content) {
|
|
5090
|
-
if (parsed.delta === true) {
|
|
5091
|
-
state.accumulatedText += content;
|
|
5092
|
-
} else {
|
|
5093
|
-
state.accumulatedText = content;
|
|
5094
|
-
}
|
|
5095
|
-
state.finalOutput = state.accumulatedText;
|
|
5096
|
-
if (content !== state.lastStreamingText) {
|
|
5097
|
-
state.lastStreamingText = content;
|
|
5098
|
-
}
|
|
5099
|
-
}
|
|
5100
|
-
} else if (parsed.type === "tool_use") {
|
|
5101
|
-
state.accumulatedText = "";
|
|
5102
|
-
state.lastStreamingText = "";
|
|
5103
|
-
const toolCall = {
|
|
5104
|
-
id: parsed.tool_id ?? createId(),
|
|
5105
|
-
skillName: "gemini",
|
|
5106
|
-
toolName: parsed.tool_name ?? "unknown",
|
|
5107
|
-
args: parsed.parameters ?? {}
|
|
5108
|
-
};
|
|
5109
|
-
state.pendingToolCalls.set(toolCall.id, toolCall);
|
|
5110
|
-
const event = createCallToolsEvent(
|
|
5111
|
-
jobId,
|
|
5112
|
-
runId,
|
|
5113
|
-
expertKey,
|
|
5114
|
-
checkpoint.stepNumber,
|
|
5115
|
-
[toolCall],
|
|
5116
|
-
checkpoint
|
|
5117
|
-
);
|
|
5118
|
-
state.events.push(event);
|
|
5119
|
-
eventListener?.(event);
|
|
5120
|
-
} else if (parsed.type === "tool_result") {
|
|
5121
|
-
const toolId = parsed.tool_id ?? "";
|
|
5122
|
-
const output = parsed.output ?? "";
|
|
5123
|
-
const pendingToolCall = state.pendingToolCalls.get(toolId);
|
|
5124
|
-
const toolName = pendingToolCall?.toolName ?? "unknown";
|
|
5125
|
-
state.pendingToolCalls.delete(toolId);
|
|
5126
|
-
const toolResultMessage = {
|
|
5127
|
-
id: createId(),
|
|
5128
|
-
type: "toolMessage",
|
|
5129
|
-
contents: [
|
|
5130
|
-
{
|
|
5131
|
-
type: "toolResultPart",
|
|
5132
|
-
id: createId(),
|
|
5133
|
-
toolCallId: toolId,
|
|
5134
|
-
toolName,
|
|
5135
|
-
contents: [{ type: "textPart", id: createId(), text: output }]
|
|
5136
|
-
}
|
|
5137
|
-
]
|
|
5138
|
-
};
|
|
5139
|
-
state.checkpoint = {
|
|
5140
|
-
...state.checkpoint,
|
|
5141
|
-
stepNumber: state.checkpoint.stepNumber + 1,
|
|
5142
|
-
messages: [...state.checkpoint.messages, toolResultMessage]
|
|
5143
|
-
};
|
|
5144
|
-
storeCheckpoint?.(state.checkpoint);
|
|
5145
|
-
const event = createResolveToolResultsEvent(
|
|
5146
|
-
jobId,
|
|
5147
|
-
runId,
|
|
5148
|
-
expertKey,
|
|
5149
|
-
state.checkpoint.stepNumber,
|
|
5150
|
-
[
|
|
5151
|
-
{
|
|
5152
|
-
id: toolId,
|
|
5153
|
-
skillName: "gemini",
|
|
5154
|
-
toolName,
|
|
5155
|
-
result: [{ type: "textPart", id: createId(), text: output }]
|
|
5156
|
-
}
|
|
5157
|
-
]
|
|
5158
|
-
);
|
|
5159
|
-
state.events.push(event);
|
|
5160
|
-
eventListener?.(event);
|
|
5161
1152
|
}
|
|
5162
1153
|
}
|
|
5163
|
-
|
|
5164
|
-
registerAdapter("cursor", () => new CursorAdapter());
|
|
5165
|
-
registerAdapter("claude-code", () => new ClaudeCodeAdapter());
|
|
5166
|
-
registerAdapter("gemini", () => new GeminiAdapter());
|
|
5167
|
-
registerAdapter("docker", () => new DockerAdapter());
|
|
5168
|
-
function getAdapter(runtime) {
|
|
5169
|
-
return getAdapter$1(runtime);
|
|
1154
|
+
return Array.from(expertMap.values()).sort((a, b) => b.lastUsed - a.lastUsed).slice(0, limit);
|
|
5170
1155
|
}
|
|
5171
|
-
function
|
|
5172
|
-
|
|
1156
|
+
function getCheckpointById(jobId, checkpointId) {
|
|
1157
|
+
const checkpointPath = getCheckpointPath(jobId, checkpointId);
|
|
1158
|
+
if (!existsSync(checkpointPath)) {
|
|
1159
|
+
throw new Error(`Checkpoint ${checkpointId} not found in job ${jobId}`);
|
|
1160
|
+
}
|
|
1161
|
+
const checkpoint = readFileSync(checkpointPath, "utf-8");
|
|
1162
|
+
return checkpointSchema.parse(JSON.parse(checkpoint));
|
|
5173
1163
|
}
|
|
5174
|
-
function
|
|
5175
|
-
return
|
|
1164
|
+
function getCheckpointsWithDetails(jobId) {
|
|
1165
|
+
return getCheckpointsByJobId2(jobId).map((cp) => ({
|
|
1166
|
+
id: cp.id,
|
|
1167
|
+
runId: cp.runId,
|
|
1168
|
+
stepNumber: cp.stepNumber,
|
|
1169
|
+
contextWindowUsage: cp.contextWindowUsage ?? 0
|
|
1170
|
+
})).sort((a, b) => b.stepNumber - a.stepNumber);
|
|
5176
1171
|
}
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
const {
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
config,
|
|
5184
|
-
eventListener,
|
|
5185
|
-
storeCheckpoint,
|
|
5186
|
-
storeEvent,
|
|
5187
|
-
retrieveCheckpoint,
|
|
5188
|
-
workspace,
|
|
5189
|
-
additionalEnvKeys,
|
|
5190
|
-
additionalVolumes
|
|
5191
|
-
} = params;
|
|
5192
|
-
const setting = {
|
|
5193
|
-
...params.setting,
|
|
5194
|
-
jobId: params.setting.jobId ?? createId(),
|
|
5195
|
-
runId: createId()
|
|
5196
|
-
// runId is always generated internally, never from external input
|
|
5197
|
-
};
|
|
5198
|
-
if (!isAdapterAvailable(runtime)) {
|
|
5199
|
-
const available = getRegisteredRuntimes().join(", ");
|
|
5200
|
-
throw new Error(`Runtime "${runtime}" is not available. Available runtimes: ${available}.`);
|
|
1172
|
+
function getAllEventContentsForJob(jobId, maxStepNumber) {
|
|
1173
|
+
const runIds = getRunIdsByJobId(jobId);
|
|
1174
|
+
const allEvents = [];
|
|
1175
|
+
for (const runId of runIds) {
|
|
1176
|
+
const events = getEventContents(jobId, runId, maxStepNumber);
|
|
1177
|
+
allEvents.push(...events);
|
|
5201
1178
|
}
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
1179
|
+
return allEvents.sort((a, b) => a.timestamp - b.timestamp);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// src/lib/context.ts
|
|
1183
|
+
var defaultProvider = "anthropic";
|
|
1184
|
+
var defaultModel = "claude-sonnet-4-5";
|
|
1185
|
+
async function resolveRunContext(input) {
|
|
1186
|
+
const perstackConfig = await getPerstackConfig(input.configPath);
|
|
1187
|
+
let checkpoint;
|
|
1188
|
+
if (input.resumeFrom) {
|
|
1189
|
+
if (!input.continueJob) {
|
|
1190
|
+
throw new Error("--resume-from requires --continue-job");
|
|
5210
1191
|
}
|
|
5211
|
-
|
|
1192
|
+
checkpoint = getCheckpointById(input.continueJob, input.resumeFrom);
|
|
1193
|
+
} else if (input.continueJob) {
|
|
1194
|
+
checkpoint = getMostRecentCheckpoint(input.continueJob);
|
|
1195
|
+
} else if (input.continue) {
|
|
1196
|
+
checkpoint = getMostRecentCheckpoint();
|
|
1197
|
+
}
|
|
1198
|
+
if ((input.continue || input.continueJob || input.resumeFrom) && !checkpoint) {
|
|
1199
|
+
throw new Error("No checkpoint found");
|
|
1200
|
+
}
|
|
1201
|
+
if (checkpoint && input.expertKey && checkpoint.expert.key !== input.expertKey) {
|
|
1202
|
+
throw new Error(
|
|
1203
|
+
`Checkpoint expert key ${checkpoint.expert.key} does not match input expert key ${input.expertKey}`
|
|
1204
|
+
);
|
|
5212
1205
|
}
|
|
5213
|
-
const
|
|
5214
|
-
|
|
1206
|
+
const envPath = input.envPath && input.envPath.length > 0 ? input.envPath : perstackConfig.envPath ?? [".env", ".env.local"];
|
|
1207
|
+
const env = getEnv(envPath);
|
|
1208
|
+
const provider = input.provider ?? perstackConfig.provider?.providerName ?? defaultProvider;
|
|
1209
|
+
const model = input.model ?? perstackConfig.model ?? defaultModel;
|
|
1210
|
+
const providerConfig = getProviderConfig(provider, env, perstackConfig.provider);
|
|
1211
|
+
const experts = Object.fromEntries(
|
|
1212
|
+
Object.entries(perstackConfig.experts ?? {}).map(([name, expert]) => {
|
|
1213
|
+
return [
|
|
1214
|
+
name,
|
|
1215
|
+
{
|
|
1216
|
+
name,
|
|
1217
|
+
version: expert.version ?? "1.0.0",
|
|
1218
|
+
description: expert.description,
|
|
1219
|
+
instruction: expert.instruction,
|
|
1220
|
+
skills: expert.skills,
|
|
1221
|
+
delegates: expert.delegates,
|
|
1222
|
+
tags: expert.tags
|
|
1223
|
+
}
|
|
1224
|
+
];
|
|
1225
|
+
})
|
|
1226
|
+
);
|
|
1227
|
+
return {
|
|
1228
|
+
perstackConfig,
|
|
5215
1229
|
checkpoint,
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
workspace,
|
|
5222
|
-
additionalEnvKeys,
|
|
5223
|
-
additionalVolumes
|
|
5224
|
-
});
|
|
5225
|
-
return { checkpoint: result.checkpoint };
|
|
1230
|
+
env,
|
|
1231
|
+
providerConfig,
|
|
1232
|
+
model,
|
|
1233
|
+
experts
|
|
1234
|
+
};
|
|
5226
1235
|
}
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
1236
|
+
|
|
1237
|
+
// src/lib/interactive.ts
|
|
1238
|
+
function parseInteractiveToolCallResult(query, checkpoint) {
|
|
1239
|
+
const lastMessage = checkpoint.messages[checkpoint.messages.length - 1];
|
|
1240
|
+
if (lastMessage.type !== "expertMessage") {
|
|
1241
|
+
throw new Error("Last message is not a expert message");
|
|
1242
|
+
}
|
|
1243
|
+
const content = lastMessage.contents.find((c) => c.type === "toolCallPart");
|
|
1244
|
+
if (!content || content.type !== "toolCallPart") {
|
|
1245
|
+
throw new Error("Last message content is not a tool call part");
|
|
5231
1246
|
}
|
|
1247
|
+
const toolCallId = content.toolCallId;
|
|
1248
|
+
const toolName = content.toolName;
|
|
1249
|
+
const pendingToolCall = checkpoint.pendingToolCalls?.find((tc) => tc.id === toolCallId);
|
|
1250
|
+
const skillName = pendingToolCall?.skillName ?? "";
|
|
1251
|
+
return {
|
|
1252
|
+
interactiveToolCallResult: {
|
|
1253
|
+
toolCallId,
|
|
1254
|
+
toolName,
|
|
1255
|
+
skillName,
|
|
1256
|
+
text: query
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
function parseInteractiveToolCallResultJson(query) {
|
|
5232
1261
|
try {
|
|
5233
|
-
const
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
1262
|
+
const parsed = JSON.parse(query);
|
|
1263
|
+
if (typeof parsed === "object" && parsed !== null && "toolCallId" in parsed && "toolName" in parsed && "skillName" in parsed && "text" in parsed) {
|
|
1264
|
+
return {
|
|
1265
|
+
interactiveToolCallResult: parsed
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
return null;
|
|
5239
1269
|
} catch {
|
|
5240
|
-
|
|
1270
|
+
return null;
|
|
5241
1271
|
}
|
|
5242
|
-
return cachedVersion;
|
|
5243
1272
|
}
|
|
5244
1273
|
|
|
5245
1274
|
// src/run.ts
|
|
@@ -5252,26 +1281,16 @@ var runCommand = new Command().command("run").description("Run Perstack with JSO
|
|
|
5252
1281
|
"Maximum number of steps to run, default is undefined (no limit)"
|
|
5253
1282
|
).option("--max-retries <maxRetries>", "Maximum number of generation retries, default is 5").option(
|
|
5254
1283
|
"--timeout <timeout>",
|
|
5255
|
-
"Timeout for each generation in milliseconds, default is
|
|
1284
|
+
"Timeout for each generation in milliseconds, default is 300000 (5 minutes)"
|
|
5256
1285
|
).option("--job-id <jobId>", "Job ID for identifying the job").option(
|
|
5257
1286
|
"--env-path <path>",
|
|
5258
1287
|
"Path to the environment file (can be specified multiple times), default is .env and .env.local",
|
|
5259
1288
|
(value, previous) => previous.concat(value),
|
|
5260
1289
|
[]
|
|
5261
|
-
).option(
|
|
5262
|
-
"--env <name>",
|
|
5263
|
-
"Environment variable name to pass to Docker runtime (can be specified multiple times)",
|
|
5264
|
-
(value, previous) => previous.concat(value),
|
|
5265
|
-
[]
|
|
5266
1290
|
).option("--verbose", "Enable verbose logging").option("--continue", "Continue the most recent job with new query").option("--continue-job <jobId>", "Continue the specified job with new query").option(
|
|
5267
1291
|
"--resume-from <checkpointId>",
|
|
5268
1292
|
"Resume from a specific checkpoint (requires --continue or --continue-job)"
|
|
5269
|
-
).option("-i, --interactive-tool-call-result", "Query is interactive tool call result").option(
|
|
5270
|
-
"--volume <volume>",
|
|
5271
|
-
"Additional volume mount for Docker runtime (format: hostPath:containerPath:mode, can be specified multiple times)",
|
|
5272
|
-
(value, previous) => previous.concat(value),
|
|
5273
|
-
[]
|
|
5274
|
-
).option(
|
|
1293
|
+
).option("-i, --interactive-tool-call-result", "Query is interactive tool call result").option(
|
|
5275
1294
|
"--filter <types>",
|
|
5276
1295
|
"Filter events by type (comma-separated, e.g., completeRun,stopRunByError)"
|
|
5277
1296
|
).action(async (expertKey, query, options) => {
|
|
@@ -5302,34 +1321,44 @@ var runCommand = new Command().command("run").description("Run Perstack with JSO
|
|
|
5302
1321
|
resumeFrom: input.options.resumeFrom,
|
|
5303
1322
|
expertKey: input.expertKey
|
|
5304
1323
|
});
|
|
5305
|
-
const
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
1324
|
+
const lockfilePath = findLockfile();
|
|
1325
|
+
const lockfile = lockfilePath ? loadLockfile(lockfilePath) ?? void 0 : void 0;
|
|
1326
|
+
const jobId = checkpoint?.jobId ?? input.options.jobId ?? createId();
|
|
1327
|
+
const runId = createId();
|
|
1328
|
+
await run(
|
|
1329
|
+
{
|
|
1330
|
+
setting: {
|
|
1331
|
+
jobId,
|
|
1332
|
+
runId,
|
|
1333
|
+
expertKey: input.expertKey,
|
|
1334
|
+
input: input.options.interactiveToolCallResult ? parseInteractiveToolCallResultJson(input.query) ?? (checkpoint ? parseInteractiveToolCallResult(input.query, checkpoint) : { text: input.query }) : { text: input.query },
|
|
1335
|
+
experts,
|
|
1336
|
+
model,
|
|
1337
|
+
providerConfig,
|
|
1338
|
+
reasoningBudget: input.options.reasoningBudget ?? perstackConfig.reasoningBudget,
|
|
1339
|
+
maxSteps: input.options.maxSteps ?? perstackConfig.maxSteps,
|
|
1340
|
+
maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
|
|
1341
|
+
timeout: input.options.timeout ?? perstackConfig.timeout,
|
|
1342
|
+
perstackApiBaseUrl: perstackConfig.perstackApiBaseUrl,
|
|
1343
|
+
perstackApiKey: env.PERSTACK_API_KEY,
|
|
1344
|
+
perstackBaseSkillCommand: perstackConfig.perstackBaseSkillCommand,
|
|
1345
|
+
env,
|
|
1346
|
+
proxyUrl: process.env.PERSTACK_PROXY_URL,
|
|
1347
|
+
verbose: input.options.verbose
|
|
1348
|
+
},
|
|
1349
|
+
checkpoint
|
|
5324
1350
|
},
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
1351
|
+
{
|
|
1352
|
+
eventListener,
|
|
1353
|
+
storeCheckpoint: defaultStoreCheckpoint,
|
|
1354
|
+
storeEvent: defaultStoreEvent,
|
|
1355
|
+
retrieveCheckpoint: defaultRetrieveCheckpoint,
|
|
1356
|
+
storeJob,
|
|
1357
|
+
retrieveJob: retrieveJob,
|
|
1358
|
+
createJob: createInitialJob,
|
|
1359
|
+
lockfile
|
|
1360
|
+
}
|
|
1361
|
+
);
|
|
5333
1362
|
} catch (error) {
|
|
5334
1363
|
if (error instanceof Error) {
|
|
5335
1364
|
console.error(error.message);
|
|
@@ -5686,28 +1715,9 @@ var useRuntimeInfo = (options) => {
|
|
|
5686
1715
|
maxRetries: options.initialConfig.maxRetries,
|
|
5687
1716
|
timeout: options.initialConfig.timeout,
|
|
5688
1717
|
activeSkills: [],
|
|
5689
|
-
contextWindowUsage: options.initialConfig.contextWindowUsage
|
|
5690
|
-
runtime: options.initialConfig.runtime
|
|
1718
|
+
contextWindowUsage: options.initialConfig.contextWindowUsage
|
|
5691
1719
|
});
|
|
5692
1720
|
const handleEvent = useCallback((event) => {
|
|
5693
|
-
if (event.type === "dockerBuildProgress") {
|
|
5694
|
-
const buildEvent = event;
|
|
5695
|
-
setRuntimeInfo((prev) => ({
|
|
5696
|
-
...prev,
|
|
5697
|
-
dockerState: buildEvent.stage === "complete" ? "running" : "building"
|
|
5698
|
-
}));
|
|
5699
|
-
return null;
|
|
5700
|
-
}
|
|
5701
|
-
if (event.type === "dockerContainerStatus") {
|
|
5702
|
-
const containerEvent = event;
|
|
5703
|
-
if (containerEvent.service === "runtime") {
|
|
5704
|
-
setRuntimeInfo((prev) => ({
|
|
5705
|
-
...prev,
|
|
5706
|
-
dockerState: containerEvent.status
|
|
5707
|
-
}));
|
|
5708
|
-
}
|
|
5709
|
-
return null;
|
|
5710
|
-
}
|
|
5711
1721
|
if (event.type === "initializeRuntime") {
|
|
5712
1722
|
setRuntimeInfo((prev) => ({
|
|
5713
1723
|
runtimeVersion: event.runtimeVersion,
|
|
@@ -5721,9 +1731,7 @@ var useRuntimeInfo = (options) => {
|
|
|
5721
1731
|
query: event.query,
|
|
5722
1732
|
statusChangedAt: Date.now(),
|
|
5723
1733
|
activeSkills: [],
|
|
5724
|
-
contextWindowUsage: prev.contextWindowUsage
|
|
5725
|
-
runtime: prev.runtime,
|
|
5726
|
-
dockerState: prev.dockerState === "building" ? "running" : prev.dockerState
|
|
1734
|
+
contextWindowUsage: prev.contextWindowUsage
|
|
5727
1735
|
}));
|
|
5728
1736
|
return { initialized: true };
|
|
5729
1737
|
}
|
|
@@ -6173,7 +2181,7 @@ function renderTodo(action, color) {
|
|
|
6173
2181
|
] }) });
|
|
6174
2182
|
}
|
|
6175
2183
|
function renderReadTextFile(action, color) {
|
|
6176
|
-
const { path:
|
|
2184
|
+
const { path: path4, content, from, to } = action;
|
|
6177
2185
|
const lineRange = from !== void 0 && to !== void 0 ? `#${from}-${to}` : "";
|
|
6178
2186
|
const lines = content?.split("\n") ?? [];
|
|
6179
2187
|
return /* @__PURE__ */ jsx(
|
|
@@ -6181,24 +2189,24 @@ function renderReadTextFile(action, color) {
|
|
|
6181
2189
|
{
|
|
6182
2190
|
indicatorColor: color,
|
|
6183
2191
|
label: "Read Text File",
|
|
6184
|
-
summary: `${shortenPath(
|
|
2192
|
+
summary: `${shortenPath(path4)}${lineRange}`,
|
|
6185
2193
|
children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines.map((line, idx) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 1, children: /* @__PURE__ */ jsx(Text, { color: "white", dimColor: true, children: line }) }, `read-${idx}`)) })
|
|
6186
2194
|
}
|
|
6187
2195
|
);
|
|
6188
2196
|
}
|
|
6189
2197
|
function renderWriteTextFile(action, color) {
|
|
6190
|
-
const { path:
|
|
2198
|
+
const { path: path4, text } = action;
|
|
6191
2199
|
const lines = text.split("\n");
|
|
6192
|
-
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "Write Text File", summary: shortenPath(
|
|
2200
|
+
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "Write Text File", summary: shortenPath(path4), children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines.map((line, idx) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
6193
2201
|
/* @__PURE__ */ jsx(Text, { color: "green", dimColor: true, children: "+" }),
|
|
6194
2202
|
/* @__PURE__ */ jsx(Text, { color: "white", dimColor: true, children: line })
|
|
6195
2203
|
] }, `write-${idx}`)) }) });
|
|
6196
2204
|
}
|
|
6197
2205
|
function renderEditTextFile(action, color) {
|
|
6198
|
-
const { path:
|
|
2206
|
+
const { path: path4, oldText, newText } = action;
|
|
6199
2207
|
const oldLines = oldText.split("\n");
|
|
6200
2208
|
const newLines = newText.split("\n");
|
|
6201
|
-
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "Edit Text File", summary: shortenPath(
|
|
2209
|
+
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "Edit Text File", summary: shortenPath(path4), children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
6202
2210
|
oldLines.map((line, idx) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
6203
2211
|
/* @__PURE__ */ jsx(Text, { color: "red", dimColor: true, children: "-" }),
|
|
6204
2212
|
/* @__PURE__ */ jsx(Text, { color: "white", dimColor: true, children: line })
|
|
@@ -6210,18 +2218,18 @@ function renderEditTextFile(action, color) {
|
|
|
6210
2218
|
] }) });
|
|
6211
2219
|
}
|
|
6212
2220
|
function renderAppendTextFile(action, color) {
|
|
6213
|
-
const { path:
|
|
2221
|
+
const { path: path4, text } = action;
|
|
6214
2222
|
const lines = text.split("\n");
|
|
6215
|
-
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "Append Text File", summary: shortenPath(
|
|
2223
|
+
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "Append Text File", summary: shortenPath(path4), children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines.map((line, idx) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
6216
2224
|
/* @__PURE__ */ jsx(Text, { color: "green", dimColor: true, children: "+" }),
|
|
6217
2225
|
/* @__PURE__ */ jsx(Text, { color: "white", dimColor: true, children: line })
|
|
6218
2226
|
] }, `append-${idx}`)) }) });
|
|
6219
2227
|
}
|
|
6220
2228
|
function renderListDirectory(action, color) {
|
|
6221
|
-
const { path:
|
|
2229
|
+
const { path: path4, items } = action;
|
|
6222
2230
|
const itemLines = items?.map((item) => `${item.type === "directory" ? "\u{1F4C1}" : "\u{1F4C4}"} ${item.name}`) ?? [];
|
|
6223
2231
|
const { visible, remaining } = summarizeOutput(itemLines, RENDER_CONSTANTS.LIST_DIR_MAX_ITEMS);
|
|
6224
|
-
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "List", summary: shortenPath(
|
|
2232
|
+
return /* @__PURE__ */ jsx(ActionRow, { indicatorColor: color, label: "List", summary: shortenPath(path4), children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
6225
2233
|
visible.map((line, idx) => /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateText(line, UI_CONSTANTS.TRUNCATE_TEXT_DEFAULT) }, `dir-${idx}`)),
|
|
6226
2234
|
remaining > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
6227
2235
|
"... +",
|
|
@@ -6284,16 +2292,10 @@ var RunSetting = ({
|
|
|
6284
2292
|
borderRight: false,
|
|
6285
2293
|
children: [
|
|
6286
2294
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
6287
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children:
|
|
6288
|
-
info.
|
|
6289
|
-
" ",
|
|
6290
|
-
|
|
6291
|
-
info.dockerState ?? "initializing",
|
|
6292
|
-
")"
|
|
6293
|
-
] }) : info.runtimeVersion && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
6294
|
-
" ",
|
|
6295
|
-
"(",
|
|
6296
|
-
info.runtime === "local" ? `v${info.runtimeVersion}` : info.runtimeVersion,
|
|
2295
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Perstack" }),
|
|
2296
|
+
info.runtimeVersion && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
2297
|
+
" (v",
|
|
2298
|
+
info.runtimeVersion,
|
|
6297
2299
|
")"
|
|
6298
2300
|
] })
|
|
6299
2301
|
] }),
|
|
@@ -6610,7 +2612,7 @@ var ExecutionApp = (props) => {
|
|
|
6610
2612
|
};
|
|
6611
2613
|
function renderExecution(params) {
|
|
6612
2614
|
const eventQueue = new EventQueue();
|
|
6613
|
-
const result = new Promise((
|
|
2615
|
+
const result = new Promise((resolve, reject) => {
|
|
6614
2616
|
let resolved = false;
|
|
6615
2617
|
const { waitUntilExit } = render(
|
|
6616
2618
|
/* @__PURE__ */ jsx(
|
|
@@ -6622,7 +2624,7 @@ function renderExecution(params) {
|
|
|
6622
2624
|
},
|
|
6623
2625
|
onComplete: (result2) => {
|
|
6624
2626
|
resolved = true;
|
|
6625
|
-
|
|
2627
|
+
resolve(result2);
|
|
6626
2628
|
}
|
|
6627
2629
|
}
|
|
6628
2630
|
)
|
|
@@ -6825,7 +2827,7 @@ var SelectionApp = (props) => {
|
|
|
6825
2827
|
] });
|
|
6826
2828
|
};
|
|
6827
2829
|
async function renderSelection(params) {
|
|
6828
|
-
return new Promise((
|
|
2830
|
+
return new Promise((resolve, reject) => {
|
|
6829
2831
|
let resolved = false;
|
|
6830
2832
|
const { waitUntilExit } = render(
|
|
6831
2833
|
/* @__PURE__ */ jsx(
|
|
@@ -6834,7 +2836,7 @@ async function renderSelection(params) {
|
|
|
6834
2836
|
...params,
|
|
6835
2837
|
onComplete: (result) => {
|
|
6836
2838
|
resolved = true;
|
|
6837
|
-
|
|
2839
|
+
resolve(result);
|
|
6838
2840
|
}
|
|
6839
2841
|
}
|
|
6840
2842
|
)
|
|
@@ -6857,21 +2859,16 @@ var startCommand = new Command().command("start").description("Start Perstack wi
|
|
|
6857
2859
|
"Maximum number of steps to run, default is undefined (no limit)"
|
|
6858
2860
|
).option("--max-retries <maxRetries>", "Maximum number of generation retries, default is 5").option(
|
|
6859
2861
|
"--timeout <timeout>",
|
|
6860
|
-
"Timeout for each generation in milliseconds, default is
|
|
2862
|
+
"Timeout for each generation in milliseconds, default is 300000 (5 minutes)"
|
|
6861
2863
|
).option("--job-id <jobId>", "Job ID for identifying the job").option(
|
|
6862
2864
|
"--env-path <path>",
|
|
6863
2865
|
"Path to the environment file (can be specified multiple times), default is .env and .env.local",
|
|
6864
2866
|
(value, previous) => previous.concat(value),
|
|
6865
2867
|
[]
|
|
6866
|
-
).option(
|
|
6867
|
-
"--env <name>",
|
|
6868
|
-
"Environment variable name to pass to Docker runtime (can be specified multiple times)",
|
|
6869
|
-
(value, previous) => previous.concat(value),
|
|
6870
|
-
[]
|
|
6871
2868
|
).option("--verbose", "Enable verbose logging").option("--continue", "Continue the most recent job with new query").option("--continue-job <jobId>", "Continue the specified job with new query").option(
|
|
6872
2869
|
"--resume-from <checkpointId>",
|
|
6873
2870
|
"Resume from a specific checkpoint (requires --continue or --continue-job)"
|
|
6874
|
-
).option("-i, --interactive-tool-call-result", "Query is interactive tool call result").
|
|
2871
|
+
).option("-i, --interactive-tool-call-result", "Query is interactive tool call result").action(async (expertKey, query, options) => {
|
|
6875
2872
|
const input = parseWithFriendlyError(startCommandInputSchema, { expertKey, query, options });
|
|
6876
2873
|
try {
|
|
6877
2874
|
const { perstackConfig, checkpoint, env, providerConfig, model, experts } = await resolveRunContext({
|
|
@@ -6884,7 +2881,6 @@ var startCommand = new Command().command("start").description("Start Perstack wi
|
|
|
6884
2881
|
resumeFrom: input.options.resumeFrom,
|
|
6885
2882
|
expertKey: input.expertKey
|
|
6886
2883
|
});
|
|
6887
|
-
const runtime = input.options.runtime ?? perstackConfig.runtime ?? "docker";
|
|
6888
2884
|
const maxSteps = input.options.maxSteps ?? perstackConfig.maxSteps;
|
|
6889
2885
|
const maxRetries = input.options.maxRetries ?? perstackConfig.maxRetries ?? defaultMaxRetries;
|
|
6890
2886
|
const timeout = input.options.timeout ?? perstackConfig.timeout ?? defaultTimeout;
|
|
@@ -6936,53 +2932,63 @@ var startCommand = new Command().command("start").description("Start Perstack wi
|
|
|
6936
2932
|
);
|
|
6937
2933
|
return;
|
|
6938
2934
|
}
|
|
2935
|
+
const lockfilePath = findLockfile();
|
|
2936
|
+
const lockfile = lockfilePath ? loadLockfile(lockfilePath) ?? void 0 : void 0;
|
|
6939
2937
|
let currentQuery = selection.query;
|
|
6940
|
-
let currentJobId = currentCheckpoint?.jobId ?? input.options.jobId;
|
|
2938
|
+
let currentJobId = currentCheckpoint?.jobId ?? input.options.jobId ?? createId();
|
|
6941
2939
|
let isNextQueryInteractiveToolResult = input.options.interactiveToolCallResult ?? false;
|
|
6942
2940
|
let isFirstIteration = true;
|
|
6943
2941
|
const initialHistoricalEvents = currentCheckpoint ? getAllEventContentsForJob(currentCheckpoint.jobId, currentCheckpoint.stepNumber) : void 0;
|
|
6944
2942
|
while (currentQuery !== null) {
|
|
6945
2943
|
const historicalEvents = isFirstIteration ? initialHistoricalEvents : void 0;
|
|
2944
|
+
const runId = createId();
|
|
6946
2945
|
const { result: executionResult, eventListener } = renderExecution({
|
|
6947
2946
|
expertKey: selection.expertKey,
|
|
6948
2947
|
query: currentQuery,
|
|
6949
2948
|
config: {
|
|
6950
|
-
runtimeVersion
|
|
2949
|
+
runtimeVersion,
|
|
6951
2950
|
model,
|
|
6952
2951
|
maxSteps,
|
|
6953
2952
|
maxRetries,
|
|
6954
2953
|
timeout,
|
|
6955
|
-
contextWindowUsage: currentCheckpoint?.contextWindowUsage ?? 0
|
|
6956
|
-
runtime
|
|
2954
|
+
contextWindowUsage: currentCheckpoint?.contextWindowUsage ?? 0
|
|
6957
2955
|
},
|
|
6958
2956
|
continueTimeoutMs: CONTINUE_TIMEOUT_MS,
|
|
6959
2957
|
historicalEvents
|
|
6960
2958
|
});
|
|
6961
|
-
const
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
2959
|
+
const runResult = await run(
|
|
2960
|
+
{
|
|
2961
|
+
setting: {
|
|
2962
|
+
jobId: currentJobId,
|
|
2963
|
+
runId,
|
|
2964
|
+
expertKey: selection.expertKey,
|
|
2965
|
+
input: isNextQueryInteractiveToolResult && currentCheckpoint ? parseInteractiveToolCallResult(currentQuery, currentCheckpoint) : { text: currentQuery },
|
|
2966
|
+
experts,
|
|
2967
|
+
model,
|
|
2968
|
+
providerConfig,
|
|
2969
|
+
reasoningBudget: input.options.reasoningBudget ?? perstackConfig.reasoningBudget,
|
|
2970
|
+
maxSteps: input.options.maxSteps ?? perstackConfig.maxSteps,
|
|
2971
|
+
maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
|
|
2972
|
+
timeout: input.options.timeout ?? perstackConfig.timeout,
|
|
2973
|
+
perstackApiBaseUrl: perstackConfig.perstackApiBaseUrl,
|
|
2974
|
+
perstackApiKey: env.PERSTACK_API_KEY,
|
|
2975
|
+
perstackBaseSkillCommand: perstackConfig.perstackBaseSkillCommand,
|
|
2976
|
+
env,
|
|
2977
|
+
verbose: input.options.verbose
|
|
2978
|
+
},
|
|
2979
|
+
checkpoint: currentCheckpoint
|
|
6978
2980
|
},
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
2981
|
+
{
|
|
2982
|
+
eventListener,
|
|
2983
|
+
storeCheckpoint: defaultStoreCheckpoint,
|
|
2984
|
+
storeEvent: defaultStoreEvent,
|
|
2985
|
+
retrieveCheckpoint: defaultRetrieveCheckpoint,
|
|
2986
|
+
storeJob: storeJob,
|
|
2987
|
+
retrieveJob: retrieveJob,
|
|
2988
|
+
createJob: createInitialJob,
|
|
2989
|
+
lockfile
|
|
2990
|
+
}
|
|
2991
|
+
);
|
|
6986
2992
|
const result = await executionResult;
|
|
6987
2993
|
const canContinue = runResult.status === "completed" || runResult.status === "stoppedByExceededMaxSteps" || runResult.status === "stoppedByError" || runResult.status === "stoppedByInteractiveTool";
|
|
6988
2994
|
if (result.nextQuery && canContinue) {
|
|
@@ -7007,10 +3013,5 @@ var startCommand = new Command().command("start").description("Start Perstack wi
|
|
|
7007
3013
|
// bin/cli.ts
|
|
7008
3014
|
var program = new Command().name(package_default.name).description(package_default.description).version(package_default.version).addCommand(startCommand).addCommand(runCommand).addCommand(logCommand).addCommand(installCommand);
|
|
7009
3015
|
program.parse();
|
|
7010
|
-
/*! Bundled license information:
|
|
7011
|
-
|
|
7012
|
-
@noble/hashes/utils.js:
|
|
7013
|
-
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
7014
|
-
*/
|
|
7015
3016
|
//# sourceMappingURL=cli.js.map
|
|
7016
3017
|
//# sourceMappingURL=cli.js.map
|