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/dist/bin/cli.js CHANGED
@@ -1,17 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import { writeFile, mkdir, readFile } from 'fs/promises';
4
- import * as path10 from 'path';
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 { registerAdapter, parseWithFriendlyError, runCommandInputSchema, validateEventFilter, createFilteredEventListener, startCommandInputSchema, defaultMaxRetries, defaultTimeout, defaultPerstackApiBaseUrl, checkpointSchema, jobSchema, runSettingSchema, createRuntimeInitEvent, createEmptyUsage, createStartRunEvent, createCompleteRunEvent, getFilteredEnv, createCallToolsEvent, createResolveToolResultsEvent, createRuntimeEvent, perstackConfigSchema, expertSchema, isAdapterAvailable as isAdapterAvailable$1, getRegisteredRuntimes as getRegisteredRuntimes$1, getAdapter as getAdapter$1 } from '@perstack/core';
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 { spawn, execSync } from 'child_process';
14
- import * as os from 'os';
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.76",
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(path10__default.resolve(process.cwd(), configPath), "utf-8");
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(path10__default.resolve(process.cwd()));
78
+ return await findPerstackConfigStringRecursively(path2.resolve(process.cwd()));
81
79
  }
82
80
  async function findPerstackConfigStringRecursively(cwd) {
83
81
  try {
84
- const tomlString = await readFile(path10__default.resolve(cwd, "perstack.toml"), "utf-8");
82
+ const tomlString = await readFile(path2.resolve(cwd, "perstack.toml"), "utf-8");
85
83
  return tomlString;
86
84
  } catch {
87
- if (cwd === path10__default.parse(cwd).root) {
85
+ if (cwd === path2.parse(cwd).root) {
88
86
  return null;
89
87
  }
90
- return await findPerstackConfigStringRecursively(path10__default.dirname(cwd));
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 path10__default.resolve(process.cwd(), configPath);
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 = path10__default.resolve(cwd, "perstack.toml");
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 === path10__default.parse(cwd).root) {
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(path10__default.dirname(cwd));
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: path10__default.basename(configPath),
291
+ configPath: path2.basename(configPath),
294
292
  experts: lockfileExperts
295
293
  };
296
- const lockfilePath = path10__default.join(path10__default.dirname(configPath), "perstack.lock");
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 = path10__default.join(basePath, "jobs", jobId);
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(storage, basePath) {
374
+ function createStorageAdapter(basePath) {
698
375
  return {
699
- getAllJobs: () => storage.getAllJobs(),
700
- retrieveJob: (jobId) => storage.retrieveJob(jobId),
701
- getCheckpointsByJobId: (jobId) => storage.getCheckpointsByJobId(jobId),
702
- retrieveCheckpoint: (jobId, checkpointId) => storage.retrieveCheckpoint(jobId, checkpointId),
703
- getEventContents: (jobId, runId, maxStep) => storage.getEventContents(jobId, runId, maxStep),
704
- getAllRuns: () => storage.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 = path10__default.join(basePath, "jobs");
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(["callTools", "resolveToolResults", "stopRunByInteractiveTool"]);
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(path11) {
447
+ function parseFieldPath(path4) {
767
448
  const parts = [];
768
449
  let current = "";
769
450
  let i = 0;
770
- while (i < path11.length) {
771
- if (path11[i] === ".") {
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 (path11[i] === "[" && path11[i + 1] === "]") {
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 += path11[i];
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, path11) {
501
+ function getFieldValue(obj, path4) {
821
502
  let current = obj;
822
- for (let i = 0; i < path11.length; i++) {
823
- const segment = path11[i];
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 = path11.slice(i + 1);
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) => ERROR_EVENT_TYPES2.has(e.type)).length,
948
- toolCallCount: events.filter((e) => TOOL_EVENT_TYPES2.has(e.type)).length,
949
- delegationCount: events.filter((e) => DELEGATION_EVENT_TYPES2.has(e.type)).length,
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 storage = new FileSystemStorage({ basePath: storagePath });
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
- ok: false,
4925
- error: {
4926
- type: "auth-missing",
4927
- message: "GEMINI_API_KEY environment variable is not set.",
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
- buildPrompt(instruction, query) {
5015
- let prompt = `## Instructions
5016
- ${instruction}`;
5017
- if (query) {
5018
- prompt += `
5019
-
5020
- ## User Request
5021
- ${query}`;
5022
- }
5023
- return prompt;
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
- async executeGeminiCliStreaming(prompt, timeout, state, eventListener, storeCheckpoint) {
5026
- const proc = spawn("gemini", ["-p", prompt, "--output-format", "stream-json"], {
5027
- cwd: process.cwd(),
5028
- env: getFilteredEnv({
5029
- GEMINI_API_KEY: process.env.GEMINI_API_KEY ?? "",
5030
- XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME ?? "",
5031
- GOOGLE_APPLICATION_CREDENTIALS: process.env.GOOGLE_APPLICATION_CREDENTIALS ?? "",
5032
- USER: process.env.USER ?? "",
5033
- LOGNAME: process.env.LOGNAME ?? ""
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
- executeWithStreaming(proc, timeout, state, eventListener, storeCheckpoint) {
5041
- return new Promise((resolve2, reject) => {
5042
- let stdout = "";
5043
- let stderr = "";
5044
- let buffer = "";
5045
- const timer = setTimeout(() => {
5046
- proc.kill("SIGTERM");
5047
- reject(new Error(`${this.name} timed out after ${timeout}ms`));
5048
- }, timeout);
5049
- proc.stdout?.on("data", (data) => {
5050
- const chunk = data.toString();
5051
- stdout += chunk;
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 isAdapterAvailable(runtime) {
5172
- return isAdapterAvailable$1(runtime);
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 getRegisteredRuntimes() {
5175
- return getRegisteredRuntimes$1();
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
- // ../../packages/runner/src/dispatch.ts
5179
- async function dispatchToRuntime(params) {
5180
- const {
5181
- checkpoint,
5182
- runtime,
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
- const adapter = getAdapter(runtime);
5203
- const prereqResult = await adapter.checkPrerequisites();
5204
- if (!prereqResult.ok) {
5205
- const { error } = prereqResult;
5206
- let message = `Runtime "${runtime}" prerequisites not met: ${error.message}`;
5207
- if (error.helpUrl) {
5208
- message += `
5209
- See: ${error.helpUrl}`;
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
- throw new Error(message);
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 result = await adapter.run({
5214
- setting,
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
- config,
5217
- eventListener,
5218
- storeCheckpoint: storeCheckpoint ?? defaultStoreCheckpoint,
5219
- storeEvent: storeEvent ?? defaultStoreEvent,
5220
- retrieveCheckpoint: retrieveCheckpoint ?? defaultRetrieveCheckpoint,
5221
- workspace,
5222
- additionalEnvKeys,
5223
- additionalVolumes
5224
- });
5225
- return { checkpoint: result.checkpoint };
1230
+ env,
1231
+ providerConfig,
1232
+ model,
1233
+ experts
1234
+ };
5226
1235
  }
5227
- var cachedVersion = null;
5228
- function getRuntimeVersion() {
5229
- if (cachedVersion) {
5230
- return cachedVersion;
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 result = execSync("perstack-runtime --version", {
5234
- encoding: "utf-8",
5235
- timeout: 5e3,
5236
- stdio: ["pipe", "pipe", "pipe"]
5237
- });
5238
- cachedVersion = result.trim() || "unknown";
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
- cachedVersion = "unknown";
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 60000 (1 minute)"
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("--runtime <runtime>", "Execution runtime (docker, local, cursor, claude-code, gemini)").option("--workspace <workspace>", "Workspace directory for Docker runtime").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 runtime = input.options.runtime ?? perstackConfig.runtime ?? "docker";
5306
- await dispatchToRuntime({
5307
- setting: {
5308
- jobId: checkpoint?.jobId ?? input.options.jobId,
5309
- expertKey: input.expertKey,
5310
- input: input.options.interactiveToolCallResult ? parseInteractiveToolCallResultJson(input.query) ?? (checkpoint ? parseInteractiveToolCallResult(input.query, checkpoint) : { text: input.query }) : { text: input.query },
5311
- experts,
5312
- model,
5313
- providerConfig,
5314
- reasoningBudget: input.options.reasoningBudget ?? perstackConfig.reasoningBudget,
5315
- maxSteps: input.options.maxSteps ?? perstackConfig.maxSteps,
5316
- maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
5317
- timeout: input.options.timeout ?? perstackConfig.timeout,
5318
- perstackApiBaseUrl: perstackConfig.perstackApiBaseUrl,
5319
- perstackApiKey: env.PERSTACK_API_KEY,
5320
- perstackBaseSkillCommand: perstackConfig.perstackBaseSkillCommand,
5321
- env,
5322
- proxyUrl: process.env.PERSTACK_PROXY_URL,
5323
- verbose: input.options.verbose
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
- checkpoint,
5326
- runtime,
5327
- config: perstackConfig,
5328
- eventListener,
5329
- workspace: input.options.workspace,
5330
- additionalEnvKeys: input.options.env,
5331
- additionalVolumes: input.options.volume
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: path11, content, from, to } = action;
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(path11)}${lineRange}`,
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: path11, text } = action;
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(path11), children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines.map((line, idx) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
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: path11, oldText, newText } = action;
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(path11), children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
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: path11, text } = action;
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(path11), children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines.map((line, idx) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
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: path11, items } = action;
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(path11), children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
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: info.runtime === "local" ? "Local" : info.runtime === "claude-code" ? "Claude Code" : (info.runtime ?? "docker").charAt(0).toUpperCase() + (info.runtime ?? "docker").slice(1) }),
6288
- info.runtime === "docker" || !info.runtime ? /* @__PURE__ */ jsxs(Text, { color: info.dockerState === "building" ? "yellow" : "gray", children: [
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((resolve2, reject) => {
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
- resolve2(result2);
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((resolve2, reject) => {
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
- resolve2(result);
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 60000 (1 minute)"
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").option("--runtime <runtime>", "Execution runtime (docker, local, cursor, claude-code, gemini)").option("--workspace <workspace>", "Workspace directory for Docker runtime").action(async (expertKey, query, options) => {
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: getRuntimeVersion(),
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 { checkpoint: runResult } = await dispatchToRuntime({
6962
- setting: {
6963
- jobId: currentJobId,
6964
- expertKey: selection.expertKey,
6965
- input: isNextQueryInteractiveToolResult && currentCheckpoint ? parseInteractiveToolCallResult(currentQuery, currentCheckpoint) : { text: currentQuery },
6966
- experts,
6967
- model,
6968
- providerConfig,
6969
- reasoningBudget: input.options.reasoningBudget ?? perstackConfig.reasoningBudget,
6970
- maxSteps: input.options.maxSteps ?? perstackConfig.maxSteps,
6971
- maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
6972
- timeout: input.options.timeout ?? perstackConfig.timeout,
6973
- perstackApiBaseUrl: perstackConfig.perstackApiBaseUrl,
6974
- perstackApiKey: env.PERSTACK_API_KEY,
6975
- perstackBaseSkillCommand: perstackConfig.perstackBaseSkillCommand,
6976
- env,
6977
- verbose: input.options.verbose
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
- checkpoint: currentCheckpoint,
6980
- runtime,
6981
- config: perstackConfig,
6982
- eventListener,
6983
- workspace: input.options.workspace,
6984
- additionalEnvKeys: input.options.env
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