@cartanova/qgrid-cli 1.5.6 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/dist/application/qgrid/oauth.js +1 -1
- package/bundle/dist/application/qgrid/qgrid.dispatcher.js +166 -0
- package/bundle/dist/application/qgrid/qgrid.frame.js +28 -36
- package/bundle/dist/application/qgrid/qgrid.types.js +5 -16
- package/bundle/dist/i18n/sd.generated.js +2 -2
- package/bundle/dist/sonamu.config.js +6 -9
- package/bundle/src/application/qgrid/oauth.ts +1 -1
- package/bundle/src/application/qgrid/qgrid.dispatcher.ts +184 -0
- package/bundle/src/application/qgrid/qgrid.frame.ts +28 -50
- package/bundle/src/application/qgrid/qgrid.types.ts +2 -14
- package/bundle/src/application/sonamu.generated.http +2 -1
- package/bundle/src/i18n/sd.generated.ts +1 -1
- package/bundle/src/sonamu.config.ts +4 -7
- package/bundle/web-dist/client/assets/index-D8eEjsZj.js +78 -0
- package/bundle/web-dist/client/assets/{logs-KoJtGoEG.js → logs-CKnJzuH6.js} +1 -1
- package/bundle/web-dist/client/assets/{routes-CqzIoGYg.js → routes-DQKecVGa.js} +1 -1
- package/bundle/web-dist/client/assets/{sd.generated-Duipc8HN.js → sd.generated-NHYHS_-0.js} +1 -1
- package/bundle/web-dist/client/assets/services.generated-DDVXMid7.js +1 -0
- package/bundle/web-dist/client/assets/{show-BuMxiSr1.js → show-D2z1qxJ5.js} +1 -1
- package/bundle/web-dist/client/assets/tokens-BaywaQkm.js +1 -0
- package/bundle/web-dist/client/index.html +2 -2
- package/bundle/web-dist/server/assets/{copy-BPyN_0Dp.js → copy-BVWDOV2T.js} +1 -1
- package/bundle/web-dist/server/assets/{lazyRouteComponent-Bmjwy0OA.js → lazyRouteComponent-BJmwxFyJ.js} +2 -2
- package/bundle/web-dist/server/assets/{logs-BgcF7jVg.js → logs-DgIbufNf.js} +3 -3
- package/bundle/web-dist/server/assets/{routes-DVA-nsZ-.js → routes-x7-hqUm0.js} +2 -2
- package/bundle/web-dist/server/assets/{sd.generated-CDVQy4CJ.js → sd.generated-BZPIp4uL.js} +1 -1
- package/bundle/web-dist/server/assets/{services.generated-DWyvb1vb.js → services.generated-BA0gbdmd.js} +5 -4
- package/bundle/web-dist/server/assets/{shim-CqVZY710.js → shim-DGrmZkac.js} +1 -1
- package/bundle/web-dist/server/assets/{show-BnKnfNFP.js → show-Bk3NayMH.js} +4 -4
- package/bundle/web-dist/server/assets/{tokens-7z55hPRV.js → tokens-CVSwt0x0.js} +6 -17
- package/bundle/web-dist/server/entry-server.generated.js +7 -7
- package/package.json +1 -1
- package/bundle/dist/application/qgrid/pool.js +0 -128
- package/bundle/dist/application/qgrid/worker.js +0 -189
- package/bundle/src/application/qgrid/pool.ts +0 -165
- package/bundle/src/application/qgrid/worker.ts +0 -240
- package/bundle/web-dist/client/assets/index-BnqlZB1V.js +0 -78
- package/bundle/web-dist/client/assets/services.generated-Ccs6tru4.js +0 -1
- package/bundle/web-dist/client/assets/tokens--z-eVto5.js +0 -1
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/sonamu.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Qgrid</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-D8eEjsZj.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Dw2cE7zH.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/preload-helper-ca-nBW7U.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-DH4kUfK2.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-DJRQAbrY.js">
|
|
13
|
-
<link rel="modulepreload" crossorigin href="/assets/sd.generated-
|
|
13
|
+
<link rel="modulepreload" crossorigin href="/assets/sd.generated-NHYHS_-0.js">
|
|
14
14
|
<link rel="stylesheet" crossorigin href="/assets/index-BRZCFaFz.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as
|
|
1
|
+
import { D as require_react, E as require_jsx_runtime } from "./sd.generated-BZPIp4uL.js";
|
|
2
2
|
require_react();
|
|
3
3
|
var import_jsx_runtime = require_jsx_runtime();
|
|
4
4
|
var lucideCheck = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as require_shim } from "./shim-
|
|
1
|
+
import { C as require_react_dom, D as require_react, E as require_jsx_runtime, ot as __toESM, rt as __commonJSMin } from "./sd.generated-BZPIp4uL.js";
|
|
2
|
+
import { t as require_shim } from "./shim-DGrmZkac.js";
|
|
3
3
|
//#region ../../node_modules/.pnpm/@tanstack+router-core@1.143.6/node_modules/@tanstack/router-core/dist/esm/utils.js
|
|
4
4
|
function last(arr) {
|
|
5
5
|
return arr[arr.length - 1];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import { n as RequestLogService, r as TokenService, t as QgridService } from "./services.generated-
|
|
3
|
-
import { a as Link, o as useNavigate } from "./lazyRouteComponent-
|
|
1
|
+
import { D as require_react, E as require_jsx_runtime, ot as __toESM } from "./sd.generated-BZPIp4uL.js";
|
|
2
|
+
import { n as RequestLogService, r as TokenService, t as QgridService } from "./services.generated-BA0gbdmd.js";
|
|
3
|
+
import { a as Link, o as useNavigate } from "./lazyRouteComponent-BJmwxFyJ.js";
|
|
4
4
|
import { n as Route } from "../entry-server.generated.js";
|
|
5
5
|
import { n as formatUsd, t as formatMicroUsd } from "./cost-DdHTzQDR.js";
|
|
6
6
|
//#region ~icons/lucide/chevron-left.jsx
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as TokenService, t as QgridService } from "./services.generated-
|
|
1
|
+
import { C as require_react_dom, D as require_react, E as require_jsx_runtime, T as useQueryClient, ot as __toESM } from "./sd.generated-BZPIp4uL.js";
|
|
2
|
+
import { r as TokenService, t as QgridService } from "./services.generated-BA0gbdmd.js";
|
|
3
3
|
import { n as formatUsd } from "./cost-DdHTzQDR.js";
|
|
4
4
|
//#region ../../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@19.2.4/node_modules/@dnd-kit/utilities/dist/utilities.esm.js
|
|
5
5
|
var import_react_dom = /* @__PURE__ */ __toESM(require_react_dom());
|
|
@@ -22148,4 +22148,4 @@ SD.enumLabels = (enumName) => {
|
|
|
22148
22148
|
} });
|
|
22149
22149
|
};
|
|
22150
22150
|
//#endregion
|
|
22151
|
-
export {
|
|
22151
|
+
export { timeUntilStale as $, hasNextPage as A, hashKey as B, require_react_dom as C, require_react as D, require_jsx_runtime as E, onlineManager as F, noop$1 as G, isValidTimeout as H, notifyManager as I, resolveEnabled as J, partialMatchKey as K, pendingThenable as L, infiniteQueryBehavior as M, Query as N, Mutation as O, fetchState as P, skipToken as Q, environmentManager as R, require_lib as S, useQueryClient as T, matchMutation as U, hashQueryKeyByOptions as V, matchQuery as W, shallowEqualObjects as X, resolveStaleTime as Y, shouldThrowError as Z, date as _, dedupeAndFlatten as a, __require as at, object as b, zArrayable as c, ZodObject as d, timeoutManager as et, ZodOptional as f, custom as g, boolean as h, SonamuQueryMode as i, __exportAll as it, hasPreviousPage as j, getDefaultState as k, ZodArray as l, bigint as m, SUPPORTED_LOCALES as n, Subscribable as nt, fetch$1 as o, __toESM as ot, _enum as p, replaceData as q, setLocale as r, __commonJSMin as rt, useRefreshable as s, SD as t, focusManager as tt, ZodNullable as u, int as v, QueryClientProvider as w, string as x, number as y, functionalUpdate as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as timeUntilStale, A as hasNextPage, B as hashKey, D as require_react, E as require_jsx_runtime, G as noop, H as isValidTimeout, I as notifyManager, J as resolveEnabled, L as pendingThenable, M as infiniteQueryBehavior, P as fetchState, R as environmentManager, S as require_lib, T as useQueryClient, X as shallowEqualObjects, Y as resolveStaleTime, Z as shouldThrowError, a as dedupeAndFlatten, et as timeoutManager, j as hasPreviousPage, k as getDefaultState, nt as Subscribable, o as fetch, ot as __toESM, q as replaceData, s as useRefreshable, tt as focusManager } from "./sd.generated-BZPIp4uL.js";
|
|
2
2
|
//#region ../../node_modules/.pnpm/@tanstack+query-core@5.95.2/node_modules/@tanstack/query-core/build/modern/queryObserver.js
|
|
3
3
|
var QueryObserver = class extends Subscribable {
|
|
4
4
|
constructor(client, options) {
|
|
@@ -835,19 +835,20 @@ var RequestLogService;
|
|
|
835
835
|
})(RequestLogService || (RequestLogService = {}));
|
|
836
836
|
var QgridService;
|
|
837
837
|
(function(_QgridService) {
|
|
838
|
-
async function query(prompt, system, timeout) {
|
|
838
|
+
async function query(prompt, system, timeout, model) {
|
|
839
839
|
return fetch({
|
|
840
840
|
method: "POST",
|
|
841
841
|
url: `/api/qgrid/query`,
|
|
842
842
|
data: {
|
|
843
843
|
prompt,
|
|
844
844
|
system,
|
|
845
|
-
timeout
|
|
845
|
+
timeout,
|
|
846
|
+
model
|
|
846
847
|
}
|
|
847
848
|
});
|
|
848
849
|
}
|
|
849
850
|
_QgridService.query = query;
|
|
850
|
-
_QgridService.useQueryMutation = () => useMutation({ mutationFn: (params) => query(params.prompt, params.system, params.timeout) });
|
|
851
|
+
_QgridService.useQueryMutation = () => useMutation({ mutationFn: (params) => query(params.prompt, params.system, params.timeout, params.model) });
|
|
851
852
|
async function stats() {
|
|
852
853
|
return fetch({
|
|
853
854
|
method: "GET",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as require_react, rt as __commonJSMin } from "./sd.generated-BZPIp4uL.js";
|
|
2
2
|
//#region ../../node_modules/.pnpm/use-sync-external-store@1.6.0_react@19.2.4/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js
|
|
3
3
|
/**
|
|
4
4
|
* @license React
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import { n as RequestLogService } from "./services.generated-
|
|
3
|
-
import { a as Link } from "./lazyRouteComponent-
|
|
1
|
+
import { D as require_react, E as require_jsx_runtime, it as __exportAll, ot as __toESM, rt as __commonJSMin } from "./sd.generated-BZPIp4uL.js";
|
|
2
|
+
import { n as RequestLogService } from "./services.generated-BA0gbdmd.js";
|
|
3
|
+
import { a as Link } from "./lazyRouteComponent-BJmwxFyJ.js";
|
|
4
4
|
import { t as Route } from "../entry-server.generated.js";
|
|
5
|
-
import { n as lucideCheck, t as lucideCopy } from "./copy-
|
|
5
|
+
import { n as lucideCheck, t as lucideCopy } from "./copy-BVWDOV2T.js";
|
|
6
6
|
import minpath from "node:path";
|
|
7
7
|
import minproc from "node:process";
|
|
8
8
|
import { fileURLToPath as urlToPath } from "node:url";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import { r as TokenService, t as QgridService } from "./services.generated-
|
|
1
|
+
import { D as require_react, E as require_jsx_runtime, T as useQueryClient, _ as date, b as object, c as zArrayable, g as custom, h as boolean, i as SonamuQueryMode, m as bigint, ot as __toESM, p as _enum, v as int, x as string, y as number } from "./sd.generated-BZPIp4uL.js";
|
|
2
|
+
import { r as TokenService, t as QgridService } from "./services.generated-BA0gbdmd.js";
|
|
3
3
|
import { a as lucideKeyRound, i as ro, r as Q } from "../entry-server.generated.js";
|
|
4
|
-
import { n as lucideCheck, t as lucideCopy } from "./copy-
|
|
4
|
+
import { n as lucideCheck, t as lucideCopy } from "./copy-BVWDOV2T.js";
|
|
5
5
|
//#region ~icons/lucide/eye.jsx
|
|
6
6
|
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
7
7
|
var import_jsx_runtime = require_jsx_runtime();
|
|
@@ -350,10 +350,12 @@ var lucideTrash2 = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg",
|
|
|
350
350
|
object({
|
|
351
351
|
system: string().optional(),
|
|
352
352
|
prompt: string(),
|
|
353
|
+
model: string().optional(),
|
|
353
354
|
timeout: number().optional()
|
|
354
355
|
});
|
|
355
356
|
object({
|
|
356
357
|
text: string(),
|
|
358
|
+
tokenName: string().optional(),
|
|
357
359
|
usage: object({
|
|
358
360
|
input_tokens: number(),
|
|
359
361
|
output_tokens: number(),
|
|
@@ -363,17 +365,6 @@ object({
|
|
|
363
365
|
durationMs: number(),
|
|
364
366
|
costUsd: number()
|
|
365
367
|
});
|
|
366
|
-
object({
|
|
367
|
-
tokens: array(object({
|
|
368
|
-
token: string(),
|
|
369
|
-
name: string()
|
|
370
|
-
})),
|
|
371
|
-
size: number().optional(),
|
|
372
|
-
model: string().optional(),
|
|
373
|
-
timeout: number().optional(),
|
|
374
|
-
cwd: string().optional(),
|
|
375
|
-
maxCalls: number().optional()
|
|
376
|
-
});
|
|
377
368
|
object({
|
|
378
369
|
token: string(),
|
|
379
370
|
name: string()
|
|
@@ -382,8 +373,7 @@ object({ token: string() });
|
|
|
382
373
|
object({
|
|
383
374
|
token: string(),
|
|
384
375
|
name: string(),
|
|
385
|
-
requests: number()
|
|
386
|
-
active: boolean()
|
|
376
|
+
requests: number()
|
|
387
377
|
});
|
|
388
378
|
object({ authUrl: string() });
|
|
389
379
|
var RateLimit = object({
|
|
@@ -407,7 +397,6 @@ object({
|
|
|
407
397
|
});
|
|
408
398
|
object({
|
|
409
399
|
status: string(),
|
|
410
|
-
workers: number(),
|
|
411
400
|
activeTokens: number()
|
|
412
401
|
});
|
|
413
402
|
function maskToken(token) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A as decodePath, C as findRouteMatch, D as createLRUCache, E as processRouteTree, F as last, I as replaceEqualDeep, M as findLast, N as functionalUpdate$1, O as invariant, P as isPromise, S as findFlatMatch, T as processRouteMasks, _ as interpolatePath, a as Link$1, b as trimPath, c as usePrevious$1, d as useRouter, f as getRouterContext, g as cleanPath, h as isNotFound, i as createRootRouteWithContext, j as deepEqual$2, k as createControlledPromise, l as matchContext, m as rootRouteId, n as createFileRoute, p as warning, r as createLazyFileRoute, s as useLayoutEffect$3, t as lazyRouteComponent, u as useRouterState, v as joinPaths, w as findSingleMatch, x as trimPathRight, y as resolvePath } from "./assets/lazyRouteComponent-
|
|
3
|
-
import { t as require_shim } from "./assets/shim-
|
|
1
|
+
import { B as hashKey, C as require_react_dom, D as require_react, E as require_jsx_runtime, F as onlineManager, G as noop$1, I as notifyManager, K as partialMatchKey, M as infiniteQueryBehavior, N as Query, O as Mutation, Q as skipToken, U as matchMutation, V as hashQueryKeyByOptions, W as matchQuery, Y as resolveStaleTime, at as __require, b as object, d as ZodObject, f as ZodOptional, l as ZodArray, n as SUPPORTED_LOCALES, nt as Subscribable, ot as __toESM, r as setLocale, rt as __commonJSMin, t as SD, tt as focusManager, u as ZodNullable, w as QueryClientProvider, y as number, z as functionalUpdate } from "./assets/sd.generated-BZPIp4uL.js";
|
|
2
|
+
import { A as decodePath, C as findRouteMatch, D as createLRUCache, E as processRouteTree, F as last, I as replaceEqualDeep, M as findLast, N as functionalUpdate$1, O as invariant, P as isPromise, S as findFlatMatch, T as processRouteMasks, _ as interpolatePath, a as Link$1, b as trimPath, c as usePrevious$1, d as useRouter, f as getRouterContext, g as cleanPath, h as isNotFound, i as createRootRouteWithContext, j as deepEqual$2, k as createControlledPromise, l as matchContext, m as rootRouteId, n as createFileRoute, p as warning, r as createLazyFileRoute, s as useLayoutEffect$3, t as lazyRouteComponent, u as useRouterState, v as joinPaths, w as findSingleMatch, x as trimPathRight, y as resolvePath } from "./assets/lazyRouteComponent-BJmwxFyJ.js";
|
|
3
|
+
import { t as require_shim } from "./assets/shim-DGrmZkac.js";
|
|
4
4
|
//#region ../../node_modules/.pnpm/@tanstack+query-core@5.95.2/node_modules/@tanstack/query-core/build/modern/hydration.js
|
|
5
5
|
function defaultTransformerFn(data) {
|
|
6
6
|
return data;
|
|
@@ -44599,11 +44599,11 @@ function RootComponent() {
|
|
|
44599
44599
|
}
|
|
44600
44600
|
//#endregion
|
|
44601
44601
|
//#region src/routes/tokens.tsx
|
|
44602
|
-
var $$splitComponentImporter$3 = () => import("./assets/tokens-
|
|
44602
|
+
var $$splitComponentImporter$3 = () => import("./assets/tokens-CVSwt0x0.js");
|
|
44603
44603
|
var Route$3 = createFileRoute("/tokens")({ component: lazyRouteComponent($$splitComponentImporter$3, "component") });
|
|
44604
44604
|
//#endregion
|
|
44605
44605
|
//#region src/routes/logs.tsx
|
|
44606
|
-
var $$splitComponentImporter$2 = () => import("./assets/logs-
|
|
44606
|
+
var $$splitComponentImporter$2 = () => import("./assets/logs-DgIbufNf.js");
|
|
44607
44607
|
var logsSearchSchema = object({ page: number().optional().default(1) });
|
|
44608
44608
|
var Route$2 = createFileRoute("/logs")({
|
|
44609
44609
|
validateSearch: logsSearchSchema,
|
|
@@ -44611,11 +44611,11 @@ var Route$2 = createFileRoute("/logs")({
|
|
|
44611
44611
|
});
|
|
44612
44612
|
//#endregion
|
|
44613
44613
|
//#region src/routes/index.tsx
|
|
44614
|
-
var $$splitComponentImporter$1 = () => import("./assets/routes-
|
|
44614
|
+
var $$splitComponentImporter$1 = () => import("./assets/routes-x7-hqUm0.js");
|
|
44615
44615
|
var Route$1 = createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter$1, "component") });
|
|
44616
44616
|
//#endregion
|
|
44617
44617
|
//#region src/routes/requests/show.tsx
|
|
44618
|
-
var $$splitComponentImporter = () => import("./assets/show-
|
|
44618
|
+
var $$splitComponentImporter = () => import("./assets/show-Bk3NayMH.js");
|
|
44619
44619
|
var showSearchSchema = object({ id: number() });
|
|
44620
44620
|
var Route = createFileRoute("/requests/show")({
|
|
44621
44621
|
validateSearch: showSearchSchema,
|
package/package.json
CHANGED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import "../../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { QuotaError } from "./qgrid.types.js";
|
|
3
|
-
import { Worker } from "./worker.js";
|
|
4
|
-
//#region src/application/qgrid/pool.ts
|
|
5
|
-
var ClaudePool = class {
|
|
6
|
-
workers = /* @__PURE__ */ new Map();
|
|
7
|
-
tokenNames = /* @__PURE__ */ new Map();
|
|
8
|
-
quotaExhausted = /* @__PURE__ */ new Set();
|
|
9
|
-
requestCounts = /* @__PURE__ */ new Map();
|
|
10
|
-
lastUsedToken = "";
|
|
11
|
-
lastUsedWorkerIndex = 0;
|
|
12
|
-
size;
|
|
13
|
-
model;
|
|
14
|
-
timeout;
|
|
15
|
-
cwd;
|
|
16
|
-
maxCalls;
|
|
17
|
-
constructor(config) {
|
|
18
|
-
this.size = config.size ?? 3;
|
|
19
|
-
this.model = config.model ?? "sonnet";
|
|
20
|
-
this.timeout = config.timeout ?? 6e5;
|
|
21
|
-
this.cwd = config.cwd ?? "/tmp/qgrid";
|
|
22
|
-
this.maxCalls = config.maxCalls ?? 500;
|
|
23
|
-
config.tokens.forEach(({ token, name }) => {
|
|
24
|
-
this.createWorkers(token, name);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
getLastUsedWorkerName() {
|
|
28
|
-
return `${this.tokenNames.get(this.lastUsedToken) ?? "Unknown"}-${this.lastUsedWorkerIndex}`;
|
|
29
|
-
}
|
|
30
|
-
getStats() {
|
|
31
|
-
return [...this.workers.keys()].map((token) => ({
|
|
32
|
-
token,
|
|
33
|
-
name: this.tokenNames.get(token) ?? "Unknown",
|
|
34
|
-
requests: this.requestCounts.get(token) ?? 0,
|
|
35
|
-
active: !this.quotaExhausted.has(token)
|
|
36
|
-
}));
|
|
37
|
-
}
|
|
38
|
-
tokenRrIndex = 0;
|
|
39
|
-
workerRrIndexes = /* @__PURE__ */ new Map();
|
|
40
|
-
selectWorker() {
|
|
41
|
-
const availableTokens = [...this.workers.entries()].filter(([token]) => !this.quotaExhausted.has(token));
|
|
42
|
-
if (availableTokens.length === 0) return null;
|
|
43
|
-
const tokenDepths = availableTokens.map(([token, workers]) => ({
|
|
44
|
-
token,
|
|
45
|
-
workers,
|
|
46
|
-
totalDepth: workers.reduce((sum, w) => sum + w.getQueueDepth(), 0)
|
|
47
|
-
}));
|
|
48
|
-
const minTokenDepth = Math.min(...tokenDepths.map((t) => t.totalDepth));
|
|
49
|
-
const idleTokens = tokenDepths.filter((t) => t.totalDepth === minTokenDepth);
|
|
50
|
-
const selected = idleTokens[this.tokenRrIndex % idleTokens.length];
|
|
51
|
-
this.tokenRrIndex++;
|
|
52
|
-
const minDepth = Math.min(...selected.workers.map((w) => w.getQueueDepth()));
|
|
53
|
-
const idleWorkers = selected.workers.filter((w) => w.getQueueDepth() === minDepth);
|
|
54
|
-
const wrIdx = this.workerRrIndexes.get(selected.token) ?? 0;
|
|
55
|
-
const picked = idleWorkers[wrIdx % idleWorkers.length];
|
|
56
|
-
this.workerRrIndexes.set(selected.token, wrIdx + 1);
|
|
57
|
-
return picked;
|
|
58
|
-
}
|
|
59
|
-
async query(input, timeoutMs) {
|
|
60
|
-
const triedTokens = /* @__PURE__ */ new Set();
|
|
61
|
-
while (true) {
|
|
62
|
-
const worker = this.selectWorker();
|
|
63
|
-
if (!worker) throw new QuotaError("All tokens exhausted");
|
|
64
|
-
if (triedTokens.has(worker.tokenId)) throw new QuotaError("All tokens exhausted");
|
|
65
|
-
const workerName = this.tokenNames.get(worker.tokenId) ?? "Unknown";
|
|
66
|
-
const tokenWorkers = this.workers.get(worker.tokenId);
|
|
67
|
-
const workerIdx = tokenWorkers ? tokenWorkers.indexOf(worker) + 1 : 0;
|
|
68
|
-
console.log(`[qgrid] → ${workerName}-${workerIdx} (queue: ${worker.getQueueDepth()})`);
|
|
69
|
-
try {
|
|
70
|
-
const result = await worker.query(input, timeoutMs);
|
|
71
|
-
this.lastUsedToken = worker.tokenId;
|
|
72
|
-
this.lastUsedWorkerIndex = workerIdx;
|
|
73
|
-
this.requestCounts.set(worker.tokenId, (this.requestCounts.get(worker.tokenId) ?? 0) + 1);
|
|
74
|
-
return result;
|
|
75
|
-
} catch (err) {
|
|
76
|
-
if (err instanceof QuotaError) {
|
|
77
|
-
this.quotaExhausted.add(worker.tokenId);
|
|
78
|
-
triedTokens.add(worker.tokenId);
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
throw err;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
kill() {
|
|
86
|
-
[...this.workers.values()].flat().forEach((w) => {
|
|
87
|
-
w.kill();
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
createWorkers(token, name) {
|
|
91
|
-
if (this.workers.has(token)) return;
|
|
92
|
-
this.tokenNames.set(token, name);
|
|
93
|
-
const workerConfig = {
|
|
94
|
-
token,
|
|
95
|
-
model: this.model,
|
|
96
|
-
timeout: this.timeout,
|
|
97
|
-
cwd: this.cwd,
|
|
98
|
-
maxCalls: this.maxCalls
|
|
99
|
-
};
|
|
100
|
-
const workers = Array.from({ length: this.size }, () => new Worker(workerConfig));
|
|
101
|
-
this.workers.set(token, workers);
|
|
102
|
-
this.requestCounts.set(token, 0);
|
|
103
|
-
}
|
|
104
|
-
destroyWorkers(token) {
|
|
105
|
-
const workers = this.workers.get(token);
|
|
106
|
-
if (!workers) return;
|
|
107
|
-
workers.forEach((w) => {
|
|
108
|
-
w.kill();
|
|
109
|
-
});
|
|
110
|
-
this.workers.delete(token);
|
|
111
|
-
this.tokenNames.delete(token);
|
|
112
|
-
this.quotaExhausted.delete(token);
|
|
113
|
-
this.requestCounts.delete(token);
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
let pool = null;
|
|
117
|
-
function initPool(tokens) {
|
|
118
|
-
pool = new ClaudePool({ tokens });
|
|
119
|
-
return pool;
|
|
120
|
-
}
|
|
121
|
-
function getPool() {
|
|
122
|
-
if (!pool) throw new Error("Pool not initialized. Call initPool() first.");
|
|
123
|
-
return pool;
|
|
124
|
-
}
|
|
125
|
-
//#endregion
|
|
126
|
-
export { ClaudePool, getPool, initPool };
|
|
127
|
-
|
|
128
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9vbC5qcyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBwbGljYXRpb24vcWdyaWQvcG9vbC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENsYXVkZVBvb2wg4oCUIOupgO2LsCDthqDtgbAg7ZSE66Gc7IS47IqkIO2SgC5cbiAqXG4gKiAyLWxheWVyIOudvOyasO2MhTog7Yag7YGwIOyEoO2DnSAobGVhc3QtdG90YWwtZGVwdGggKyByb3VuZC1yb2Jpbikg4oaSIOybjOy7pCDshKDtg51cbiAqIC0gTWFwPHRva2VuLCBXb3JrZXJbXT7roZwg7Yag7YGw67OEIOybjOy7pCDqtIDrpqxcbiAqIC0g7Yag7YGwIOqwhCBxdW90YSDqt6Drk7Eg7IaM7KeEXG4gKi9cbmltcG9ydCB7IHR5cGUgQ2xpUmVzdWx0LCB0eXBlIFBvb2xDb25maWcsIHR5cGUgUXVlcnlJbnB1dCwgdHlwZSBUb2tlblN0YXRzIH0gZnJvbSBcIi4vcWdyaWQudHlwZXNcIjtcbmltcG9ydCB7IFF1b3RhRXJyb3IgfSBmcm9tIFwiLi9xZ3JpZC50eXBlc1wiO1xuaW1wb3J0IHsgV29ya2VyLCB0eXBlIFdvcmtlckNvbmZpZyB9IGZyb20gXCIuL3dvcmtlclwiO1xuXG5leHBvcnQgY2xhc3MgQ2xhdWRlUG9vbCB7XG4gIHdvcmtlcnMgPSBuZXcgTWFwPHN0cmluZywgV29ya2VyW10+KCk7XG4gIHRva2VuTmFtZXMgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICBxdW90YUV4aGF1c3RlZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICByZXF1ZXN0Q291bnRzID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgbGFzdFVzZWRUb2tlbiA9IFwiXCI7XG4gIGxhc3RVc2VkV29ya2VySW5kZXggPSAwO1xuICBzaXplOiBudW1iZXI7XG4gIG1vZGVsOiBzdHJpbmc7XG4gIHRpbWVvdXQ6IG51bWJlcjtcbiAgY3dkOiBzdHJpbmc7XG4gIG1heENhbGxzOiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBQb29sQ29uZmlnKSB7XG4gICAgdGhpcy5zaXplID0gY29uZmlnLnNpemUgPz8gMztcbiAgICB0aGlzLm1vZGVsID0gY29uZmlnLm1vZGVsID8/IFwic29ubmV0XCI7XG4gICAgdGhpcy50aW1lb3V0ID0gY29uZmlnLnRpbWVvdXQgPz8gNjAwXzAwMDtcbiAgICB0aGlzLmN3ZCA9IGNvbmZpZy5jd2QgPz8gXCIvdG1wL3FncmlkXCI7XG4gICAgdGhpcy5tYXhDYWxscyA9IGNvbmZpZy5tYXhDYWxscyA/PyA1MDA7XG5cbiAgICBjb25maWcudG9rZW5zLmZvckVhY2goKHsgdG9rZW4sIG5hbWUgfSkgPT4ge1xuICAgICAgdGhpcy5jcmVhdGVXb3JrZXJzKHRva2VuLCBuYW1lKTtcbiAgICB9KTtcbiAgfVxuXG4gIGdldExhc3RVc2VkV29ya2VyTmFtZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IGJhc2VOYW1lID0gdGhpcy50b2tlbk5hbWVzLmdldCh0aGlzLmxhc3RVc2VkVG9rZW4pID8/IFwiVW5rbm93blwiO1xuICAgIHJldHVybiBgJHtiYXNlTmFtZX0tJHt0aGlzLmxhc3RVc2VkV29ya2VySW5kZXh9YDtcbiAgfVxuXG4gIGdldFN0YXRzKCk6IFRva2VuU3RhdHNbXSB7XG4gICAgcmV0dXJuIFsuLi50aGlzLndvcmtlcnMua2V5cygpXS5tYXAoKHRva2VuKSA9PiAoe1xuICAgICAgdG9rZW4sXG4gICAgICBuYW1lOiB0aGlzLnRva2VuTmFtZXMuZ2V0KHRva2VuKSA/PyBcIlVua25vd25cIixcbiAgICAgIHJlcXVlc3RzOiB0aGlzLnJlcXVlc3RDb3VudHMuZ2V0KHRva2VuKSA/PyAwLFxuICAgICAgYWN0aXZlOiAhdGhpcy5xdW90YUV4aGF1c3RlZC5oYXModG9rZW4pLFxuICAgIH0pKTtcbiAgfVxuXG4gIHByaXZhdGUgdG9rZW5SckluZGV4ID0gMDtcbiAgcHJpdmF0ZSB3b3JrZXJSckluZGV4ZXMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuXG4gIHNlbGVjdFdvcmtlcigpOiBXb3JrZXIgfCBudWxsIHtcbiAgICBjb25zdCBhdmFpbGFibGVUb2tlbnMgPSBbLi4udGhpcy53b3JrZXJzLmVudHJpZXMoKV0uZmlsdGVyKFxuICAgICAgKFt0b2tlbl0pID0+ICF0aGlzLnF1b3RhRXhoYXVzdGVkLmhhcyh0b2tlbiksXG4gICAgKTtcblxuICAgIGlmIChhdmFpbGFibGVUb2tlbnMubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcblxuICAgIC8vIDHri6jqs4Q6IO2GoO2BsOuzhCDstJ0g7YGQIGRlcHRo6rCAIOqwgOyepSDrgq7snYAg7Yag7YGwIOyEoO2DnVxuICAgIGNvbnN0IHRva2VuRGVwdGhzID0gYXZhaWxhYmxlVG9rZW5zLm1hcCgoW3Rva2VuLCB3b3JrZXJzXSkgPT4gKHtcbiAgICAgIHRva2VuLFxuICAgICAgd29ya2VycyxcbiAgICAgIHRvdGFsRGVwdGg6IHdvcmtlcnMucmVkdWNlKChzdW0sIHcpID0+IHN1bSArIHcuZ2V0UXVldWVEZXB0aCgpLCAwKSxcbiAgICB9KSk7XG4gICAgY29uc3QgbWluVG9rZW5EZXB0aCA9IE1hdGgubWluKC4uLnRva2VuRGVwdGhzLm1hcCgodCkgPT4gdC50b3RhbERlcHRoKSk7XG4gICAgY29uc3QgaWRsZVRva2VucyA9IHRva2VuRGVwdGhzLmZpbHRlcigodCkgPT4gdC50b3RhbERlcHRoID09PSBtaW5Ub2tlbkRlcHRoKTtcbiAgICBjb25zdCBzZWxlY3RlZCA9IGlkbGVUb2tlbnNbdGhpcy50b2tlblJySW5kZXggJSBpZGxlVG9rZW5zLmxlbmd0aF0hO1xuICAgIHRoaXMudG9rZW5SckluZGV4Kys7XG5cbiAgICAvLyAy64uo6rOEOiDthqDtgbAg64K07JeQ7IScIGxlYXN0LWRlcHRoIOybjOy7pCwg64+Z66Wg7J2066m0IHJvdW5kLXJvYmluXG4gICAgY29uc3QgbWluRGVwdGggPSBNYXRoLm1pbiguLi5zZWxlY3RlZC53b3JrZXJzLm1hcCgodykgPT4gdy5nZXRRdWV1ZURlcHRoKCkpKTtcbiAgICBjb25zdCBpZGxlV29ya2VycyA9IHNlbGVjdGVkLndvcmtlcnMuZmlsdGVyKCh3KSA9PiB3LmdldFF1ZXVlRGVwdGgoKSA9PT0gbWluRGVwdGgpO1xuICAgIGNvbnN0IHdySWR4ID0gdGhpcy53b3JrZXJSckluZGV4ZXMuZ2V0KHNlbGVjdGVkLnRva2VuKSA/PyAwO1xuICAgIGNvbnN0IHBpY2tlZCA9IGlkbGVXb3JrZXJzW3dySWR4ICUgaWRsZVdvcmtlcnMubGVuZ3RoXSE7XG4gICAgdGhpcy53b3JrZXJSckluZGV4ZXMuc2V0KHNlbGVjdGVkLnRva2VuLCB3cklkeCArIDEpO1xuXG4gICAgcmV0dXJuIHBpY2tlZDtcbiAgfVxuXG4gIGFzeW5jIHF1ZXJ5KGlucHV0OiBRdWVyeUlucHV0LCB0aW1lb3V0TXM/OiBudW1iZXIpOiBQcm9taXNlPENsaVJlc3VsdD4ge1xuICAgIGNvbnN0IHRyaWVkVG9rZW5zID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgY29uc3Qgd29ya2VyID0gdGhpcy5zZWxlY3RXb3JrZXIoKTtcbiAgICAgIGlmICghd29ya2VyKSB7XG4gICAgICAgIHRocm93IG5ldyBRdW90YUVycm9yKFwiQWxsIHRva2VucyBleGhhdXN0ZWRcIik7XG4gICAgICB9XG5cbiAgICAgIGlmICh0cmllZFRva2Vucy5oYXMod29ya2VyLnRva2VuSWQpKSB7XG4gICAgICAgIHRocm93IG5ldyBRdW90YUVycm9yKFwiQWxsIHRva2VucyBleGhhdXN0ZWRcIik7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHdvcmtlck5hbWUgPSB0aGlzLnRva2VuTmFtZXMuZ2V0KHdvcmtlci50b2tlbklkKSA/PyBcIlVua25vd25cIjtcbiAgICAgIGNvbnN0IHRva2VuV29ya2VycyA9IHRoaXMud29ya2Vycy5nZXQod29ya2VyLnRva2VuSWQpO1xuICAgICAgY29uc3Qgd29ya2VySWR4ID0gdG9rZW5Xb3JrZXJzID8gdG9rZW5Xb3JrZXJzLmluZGV4T2Yod29ya2VyKSArIDEgOiAwO1xuICAgICAgY29uc29sZS5sb2coYFtxZ3JpZF0g4oaSICR7d29ya2VyTmFtZX0tJHt3b3JrZXJJZHh9IChxdWV1ZTogJHt3b3JrZXIuZ2V0UXVldWVEZXB0aCgpfSlgKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgd29ya2VyLnF1ZXJ5KGlucHV0LCB0aW1lb3V0TXMpO1xuICAgICAgICB0aGlzLmxhc3RVc2VkVG9rZW4gPSB3b3JrZXIudG9rZW5JZDtcbiAgICAgICAgdGhpcy5sYXN0VXNlZFdvcmtlckluZGV4ID0gd29ya2VySWR4O1xuICAgICAgICB0aGlzLnJlcXVlc3RDb3VudHMuc2V0KHdvcmtlci50b2tlbklkLCAodGhpcy5yZXF1ZXN0Q291bnRzLmdldCh3b3JrZXIudG9rZW5JZCkgPz8gMCkgKyAxKTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBRdW90YUVycm9yKSB7XG4gICAgICAgICAgdGhpcy5xdW90YUV4aGF1c3RlZC5hZGQod29ya2VyLnRva2VuSWQpO1xuICAgICAgICAgIHRyaWVkVG9rZW5zLmFkZCh3b3JrZXIudG9rZW5JZCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGtpbGwoKTogdm9pZCB7XG4gICAgWy4uLnRoaXMud29ya2Vycy52YWx1ZXMoKV0uZmxhdCgpLmZvckVhY2goKHcpID0+IHtcbiAgICAgIHcua2lsbCgpO1xuICAgIH0pO1xuICB9XG5cbiAgY3JlYXRlV29ya2Vycyh0b2tlbjogc3RyaW5nLCBuYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAodGhpcy53b3JrZXJzLmhhcyh0b2tlbikpIHJldHVybjtcblxuICAgIHRoaXMudG9rZW5OYW1lcy5zZXQodG9rZW4sIG5hbWUpO1xuICAgIGNvbnN0IHdvcmtlckNvbmZpZzogV29ya2VyQ29uZmlnID0ge1xuICAgICAgdG9rZW4sXG4gICAgICBtb2RlbDogdGhpcy5tb2RlbCxcbiAgICAgIHRpbWVvdXQ6IHRoaXMudGltZW91dCxcbiAgICAgIGN3ZDogdGhpcy5jd2QsXG4gICAgICBtYXhDYWxsczogdGhpcy5tYXhDYWxscyxcbiAgICB9O1xuICAgIGNvbnN0IHdvcmtlcnMgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiB0aGlzLnNpemUgfSwgKCkgPT4gbmV3IFdvcmtlcih3b3JrZXJDb25maWcpKTtcbiAgICB0aGlzLndvcmtlcnMuc2V0KHRva2VuLCB3b3JrZXJzKTtcbiAgICB0aGlzLnJlcXVlc3RDb3VudHMuc2V0KHRva2VuLCAwKTtcbiAgfVxuXG4gIGRlc3Ryb3lXb3JrZXJzKHRva2VuOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCB3b3JrZXJzID0gdGhpcy53b3JrZXJzLmdldCh0b2tlbik7XG4gICAgaWYgKCF3b3JrZXJzKSByZXR1cm47XG5cbiAgICB3b3JrZXJzLmZvckVhY2goKHcpID0+IHtcbiAgICAgIHcua2lsbCgpO1xuICAgIH0pO1xuICAgIHRoaXMud29ya2Vycy5kZWxldGUodG9rZW4pO1xuICAgIHRoaXMudG9rZW5OYW1lcy5kZWxldGUodG9rZW4pO1xuICAgIHRoaXMucXVvdGFFeGhhdXN0ZWQuZGVsZXRlKHRva2VuKTtcbiAgICB0aGlzLnJlcXVlc3RDb3VudHMuZGVsZXRlKHRva2VuKTtcbiAgfVxufVxuXG4vLyBQb29sIOyLseq4gO2EtCDqtIDrpqxcbmxldCBwb29sOiBDbGF1ZGVQb29sIHwgbnVsbCA9IG51bGw7XG5cbmV4cG9ydCBmdW5jdGlvbiBpbml0UG9vbCh0b2tlbnM6IHsgdG9rZW46IHN0cmluZzsgbmFtZTogc3RyaW5nIH1bXSk6IENsYXVkZVBvb2wge1xuICBwb29sID0gbmV3IENsYXVkZVBvb2woeyB0b2tlbnMgfSk7XG4gIHJldHVybiBwb29sO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbCgpOiBDbGF1ZGVQb29sIHtcbiAgaWYgKCFwb29sKSB0aHJvdyBuZXcgRXJyb3IoXCJQb29sIG5vdCBpbml0aWFsaXplZC4gQ2FsbCBpbml0UG9vbCgpIGZpcnN0LlwiKTtcbiAgcmV0dXJuIHBvb2w7XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7QUFXQSxJQUFhLGFBQWIsTUFBd0I7Q0FDdEIsMEJBQVUsSUFBSSxLQUF1QjtDQUNyQyw2QkFBYSxJQUFJLEtBQXFCO0NBQ3RDLGlDQUFpQixJQUFJLEtBQWE7Q0FDbEMsZ0NBQWdCLElBQUksS0FBcUI7Q0FDekMsZ0JBQWdCO0NBQ2hCLHNCQUFzQjtDQUN0QjtDQUNBO0NBQ0E7Q0FDQTtDQUNBO0NBRUEsWUFBWSxRQUFvQjtBQUM5QixPQUFLLE9BQU8sT0FBTyxRQUFRO0FBQzNCLE9BQUssUUFBUSxPQUFPLFNBQVM7QUFDN0IsT0FBSyxVQUFVLE9BQU8sV0FBVztBQUNqQyxPQUFLLE1BQU0sT0FBTyxPQUFPO0FBQ3pCLE9BQUssV0FBVyxPQUFPLFlBQVk7QUFFbkMsU0FBTyxPQUFPLFNBQVMsRUFBRSxPQUFPLFdBQVc7QUFDekMsUUFBSyxjQUFjLE9BQU8sS0FBSztJQUMvQjs7Q0FHSix3QkFBZ0M7QUFFOUIsU0FBTyxHQURVLEtBQUssV0FBVyxJQUFJLEtBQUssY0FBYyxJQUFJLFVBQ3pDLEdBQUcsS0FBSzs7Q0FHN0IsV0FBeUI7QUFDdkIsU0FBTyxDQUFDLEdBQUcsS0FBSyxRQUFRLE1BQU0sQ0FBQyxDQUFDLEtBQUssV0FBVztHQUM5QztHQUNBLE1BQU0sS0FBSyxXQUFXLElBQUksTUFBTSxJQUFJO0dBQ3BDLFVBQVUsS0FBSyxjQUFjLElBQUksTUFBTSxJQUFJO0dBQzNDLFFBQVEsQ0FBQyxLQUFLLGVBQWUsSUFBSSxNQUFNO0dBQ3hDLEVBQUU7O0NBR0wsZUFBdUI7Q0FDdkIsa0NBQTBCLElBQUksS0FBcUI7Q0FFbkQsZUFBOEI7RUFDNUIsTUFBTSxrQkFBa0IsQ0FBQyxHQUFHLEtBQUssUUFBUSxTQUFTLENBQUMsQ0FBQyxRQUNqRCxDQUFDLFdB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
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import "../../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { ProcessError, QuotaError, TimeoutError, maskToken } from "./qgrid.types.js";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
import { mkdirSync } from "node:fs";
|
|
5
|
-
//#region src/application/qgrid/worker.ts
|
|
6
|
-
/**
|
|
7
|
-
* Worker — Claude CLI stream-json 프로세스 하나를 관리.
|
|
8
|
-
*
|
|
9
|
-
* 기존 SocratsAI ClaudeCliService에서 추출 + 리팩터:
|
|
10
|
-
* - 토큰/모델을 생성자에서 주입
|
|
11
|
-
* - env allowlist (PATH, TMPDIR, CLAUDE_CODE_OAUTH_TOKEN + CLAUDE_CODE_DISABLE_* )
|
|
12
|
-
* - callCount 추적 + maxCalls 도달 시 프로세스 재활용
|
|
13
|
-
* - QuotaError/TimeoutError/ProcessError 구분
|
|
14
|
-
*/
|
|
15
|
-
var Worker = class {
|
|
16
|
-
tokenId;
|
|
17
|
-
config;
|
|
18
|
-
process = null;
|
|
19
|
-
buffer = "";
|
|
20
|
-
pending = null;
|
|
21
|
-
sessionId = null;
|
|
22
|
-
queue = [];
|
|
23
|
-
cwdCreated = false;
|
|
24
|
-
callCount = 0;
|
|
25
|
-
needsRecycle = false;
|
|
26
|
-
constructor(config) {
|
|
27
|
-
this.config = config;
|
|
28
|
-
this.tokenId = config.token;
|
|
29
|
-
}
|
|
30
|
-
getQueueDepth() {
|
|
31
|
-
return this.queue.length + (this.pending ? 1 : 0);
|
|
32
|
-
}
|
|
33
|
-
rejectPending(err) {
|
|
34
|
-
if (!this.pending) return;
|
|
35
|
-
this.pending.reject(err);
|
|
36
|
-
clearTimeout(this.pending.timer);
|
|
37
|
-
this.pending = null;
|
|
38
|
-
}
|
|
39
|
-
ensureProcess() {
|
|
40
|
-
if (this.process && this.process.exitCode === null && !this.needsRecycle) return this.process;
|
|
41
|
-
if (this.process && this.process.exitCode === null) {
|
|
42
|
-
this.process.kill();
|
|
43
|
-
this.process = null;
|
|
44
|
-
}
|
|
45
|
-
const env = {
|
|
46
|
-
PATH: process.env.PATH,
|
|
47
|
-
TMPDIR: process.env.TMPDIR,
|
|
48
|
-
CLAUDE_CODE_OAUTH_TOKEN: this.config.token,
|
|
49
|
-
CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1",
|
|
50
|
-
CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING: "1",
|
|
51
|
-
CLAUDE_CODE_DISABLE_1M_CONTEXT: "1"
|
|
52
|
-
};
|
|
53
|
-
const { cwd } = this.config;
|
|
54
|
-
if (!this.cwdCreated) {
|
|
55
|
-
mkdirSync(cwd, { recursive: true });
|
|
56
|
-
this.cwdCreated = true;
|
|
57
|
-
}
|
|
58
|
-
const child = spawn("claude", [
|
|
59
|
-
"-p",
|
|
60
|
-
"--input-format",
|
|
61
|
-
"stream-json",
|
|
62
|
-
"--output-format",
|
|
63
|
-
"stream-json",
|
|
64
|
-
"--verbose",
|
|
65
|
-
"--max-turns",
|
|
66
|
-
"1",
|
|
67
|
-
"--permission-mode",
|
|
68
|
-
"bypassPermissions",
|
|
69
|
-
"--setting-sources",
|
|
70
|
-
"project",
|
|
71
|
-
"--model",
|
|
72
|
-
this.config.model
|
|
73
|
-
], {
|
|
74
|
-
stdio: [
|
|
75
|
-
"pipe",
|
|
76
|
-
"pipe",
|
|
77
|
-
"ignore"
|
|
78
|
-
],
|
|
79
|
-
env,
|
|
80
|
-
cwd
|
|
81
|
-
});
|
|
82
|
-
child.stdout?.on("data", (d) => {
|
|
83
|
-
this.buffer += d.toString();
|
|
84
|
-
this.processBuffer();
|
|
85
|
-
});
|
|
86
|
-
child.on("close", () => {
|
|
87
|
-
this.process = null;
|
|
88
|
-
this.rejectPending(new ProcessError(`CLI process closed (token: ${maskToken(this.tokenId)})`));
|
|
89
|
-
this.drainQueue();
|
|
90
|
-
});
|
|
91
|
-
child.on("error", (err) => {
|
|
92
|
-
this.process = null;
|
|
93
|
-
this.rejectPending(new ProcessError(`CLI process error: ${err.message} (token: ${maskToken(this.tokenId)})`));
|
|
94
|
-
this.drainQueue();
|
|
95
|
-
});
|
|
96
|
-
this.process = child;
|
|
97
|
-
this.buffer = "";
|
|
98
|
-
this.sessionId = null;
|
|
99
|
-
this.callCount = 0;
|
|
100
|
-
this.needsRecycle = false;
|
|
101
|
-
return child;
|
|
102
|
-
}
|
|
103
|
-
processBuffer() {
|
|
104
|
-
const lines = this.buffer.split("\n");
|
|
105
|
-
this.buffer = lines.pop() ?? "";
|
|
106
|
-
lines.filter((line) => line.trim() !== "").forEach((line) => {
|
|
107
|
-
try {
|
|
108
|
-
const j = JSON.parse(line);
|
|
109
|
-
if (j.type === "system" && j.subtype === "init" && j.session_id) this.sessionId = j.session_id;
|
|
110
|
-
if (j.type === "result" && this.pending) {
|
|
111
|
-
let text = j.result ?? "";
|
|
112
|
-
text = text.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "");
|
|
113
|
-
if (text.startsWith("You've hit")) {
|
|
114
|
-
this.pending.reject(new QuotaError(`Quota exhausted (token: ${maskToken(this.tokenId)})`));
|
|
115
|
-
clearTimeout(this.pending.timer);
|
|
116
|
-
this.pending = null;
|
|
117
|
-
this.drainQueue();
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const u = j.usage ?? {};
|
|
121
|
-
this.pending.resolve({
|
|
122
|
-
text,
|
|
123
|
-
usage: {
|
|
124
|
-
input_tokens: u.input_tokens ?? 0,
|
|
125
|
-
output_tokens: u.output_tokens ?? 0,
|
|
126
|
-
cache_creation_input_tokens: u.cache_creation_input_tokens ?? 0,
|
|
127
|
-
cache_read_input_tokens: u.cache_read_input_tokens ?? 0
|
|
128
|
-
},
|
|
129
|
-
durationMs: j.duration_ms ?? 0,
|
|
130
|
-
costUsd: j.total_cost_usd ?? 0
|
|
131
|
-
});
|
|
132
|
-
clearTimeout(this.pending.timer);
|
|
133
|
-
this.pending = null;
|
|
134
|
-
this.drainQueue();
|
|
135
|
-
}
|
|
136
|
-
} catch {}
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
drainQueue() {
|
|
140
|
-
if (this.pending) return;
|
|
141
|
-
const next = this.queue.shift();
|
|
142
|
-
if (next) next();
|
|
143
|
-
}
|
|
144
|
-
async query(input, timeoutMs) {
|
|
145
|
-
if (this.pending) await new Promise((resolve) => {
|
|
146
|
-
this.queue.push(resolve);
|
|
147
|
-
});
|
|
148
|
-
const child = this.ensureProcess();
|
|
149
|
-
const timeout = timeoutMs ?? this.config.timeout;
|
|
150
|
-
this.callCount++;
|
|
151
|
-
if (this.callCount >= this.config.maxCalls) this.needsRecycle = true;
|
|
152
|
-
const prompt = input.system ? `${input.system}\n\n${input.prompt}` : input.prompt;
|
|
153
|
-
return new Promise((resolve, reject) => {
|
|
154
|
-
this.pending = {
|
|
155
|
-
resolve,
|
|
156
|
-
reject,
|
|
157
|
-
timer: setTimeout(() => {
|
|
158
|
-
this.pending = null;
|
|
159
|
-
reject(new TimeoutError(`Timeout after ${timeout / 1e3}s (token: ${maskToken(this.tokenId)})`));
|
|
160
|
-
this.kill();
|
|
161
|
-
}, timeout)
|
|
162
|
-
};
|
|
163
|
-
const msg = JSON.stringify({
|
|
164
|
-
type: "user",
|
|
165
|
-
message: {
|
|
166
|
-
role: "user",
|
|
167
|
-
content: prompt
|
|
168
|
-
},
|
|
169
|
-
session_id: this.sessionId ?? "default",
|
|
170
|
-
parent_tool_use_id: null
|
|
171
|
-
});
|
|
172
|
-
child.stdin?.write(`${msg}\n`);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
kill() {
|
|
176
|
-
if (this.process && this.process.exitCode === null) this.process.kill();
|
|
177
|
-
this.process = null;
|
|
178
|
-
this.buffer = "";
|
|
179
|
-
this.sessionId = null;
|
|
180
|
-
this.callCount = 0;
|
|
181
|
-
this.needsRecycle = false;
|
|
182
|
-
this.rejectPending(new ProcessError(`Worker killed (token: ${maskToken(this.tokenId)})`));
|
|
183
|
-
this.drainQueue();
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
//#endregion
|
|
187
|
-
export { Worker };
|
|
188
|
-
|
|
189
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyLmpzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcHBsaWNhdGlvbi9xZ3JpZC93b3JrZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBXb3JrZXIg4oCUIENsYXVkZSBDTEkgc3RyZWFtLWpzb24g7ZSE66Gc7IS47IqkIO2VmOuCmOulvCDqtIDrpqwuXG4gKlxuICog6riw7KG0IFNvY3JhdHNBSSBDbGF1ZGVDbGlTZXJ2aWNl7JeQ7IScIOy2lOy2nCArIOumrO2Mqe2EsDpcbiAqIC0g7Yag7YGwL+uqqOuNuOydhCDsg53shLHsnpDsl5DshJwg7KO87J6FXG4gKiAtIGVudiBhbGxvd2xpc3QgKFBBVEgsIFRNUERJUiwgQ0xBVURFX0NPREVfT0FVVEhfVE9LRU4gKyBDTEFVREVfQ09ERV9ESVNBQkxFXyogKVxuICogLSBjYWxsQ291bnQg7LaU7KCBICsgbWF4Q2FsbHMg64+E64usIOyLnCDtlITroZzshLjsiqQg7J6s7Zmc7JqpXG4gKiAtIFF1b3RhRXJyb3IvVGltZW91dEVycm9yL1Byb2Nlc3NFcnJvciDqtazrtoRcbiAqL1xuaW1wb3J0IHsgdHlwZSBDaGlsZFByb2Nlc3MsIHNwYXduIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgbWtkaXJTeW5jIH0gZnJvbSBcIm5vZGU6ZnNcIjtcblxuaW1wb3J0IHsgdHlwZSBDbGlSZXN1bHQsIHR5cGUgUXVlcnlJbnB1dCB9IGZyb20gXCIuL3FncmlkLnR5cGVzXCI7XG5pbXBvcnQgeyBtYXNrVG9rZW4sIFByb2Nlc3NFcnJvciwgUXVvdGFFcnJvciwgVGltZW91dEVycm9yIH0gZnJvbSBcIi4vcWdyaWQudHlwZXNcIjtcblxudHlwZSBQZW5kaW5nUmVxdWVzdCA9IHtcbiAgcmVzb2x2ZTogKHZhbHVlOiBDbGlSZXN1bHQpID0+IHZvaWQ7XG4gIHJlamVjdDogKHJlYXNvbjogRXJyb3IpID0+IHZvaWQ7XG4gIHRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0Pjtcbn07XG5cbmV4cG9ydCB0eXBlIFdvcmtlckNvbmZpZyA9IHtcbiAgdG9rZW46IHN0cmluZztcbiAgbW9kZWw6IHN0cmluZztcbiAgdGltZW91dDogbnVtYmVyO1xuICBjd2Q6IHN0cmluZztcbiAgbWF4Q2FsbHM6IG51bWJlcjtcbn07XG5cbmV4cG9ydCBjbGFzcyBXb3JrZXIge1xuICB0b2tlbklkOiBzdHJpbmc7XG4gIGNvbmZpZzogV29ya2VyQ29uZmlnO1xuICBwcm9jZXNzOiBDaGlsZFByb2Nlc3MgfCBudWxsID0gbnVsbDtcbiAgYnVmZmVyID0gXCJcIjtcbiAgcGVuZGluZzogUGVuZGluZ1JlcXVlc3QgfCBudWxsID0gbnVsbDtcbiAgc2Vzc2lvbklkOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgcXVldWU6IEFycmF5PCgpID0+IHZvaWQ+ID0gW107XG4gIGN3ZENyZWF0ZWQgPSBmYWxzZTtcbiAgY2FsbENvdW50ID0gMDtcbiAgbmVlZHNSZWN5Y2xlID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBXb3JrZXJDb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLnRva2VuSWQgPSBjb25maWcudG9rZW47XG4gIH1cblxuICBnZXRRdWV1ZURlcHRoKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucXVldWUubGVuZ3RoICsgKHRoaXMucGVuZGluZyA/IDEgOiAwKTtcbiAgfVxuXG4gIHJlamVjdFBlbmRpbmcoZXJyOiBFcnJvcik6IHZvaWQge1xuICAgIGlmICghdGhpcy5wZW5kaW5nKSByZXR1cm47XG4gICAgdGhpcy5wZW5kaW5nLnJlamVjdChlcnIpO1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnBlbmRpbmcudGltZXIpO1xuICAgIHRoaXMucGVuZGluZyA9IG51bGw7XG4gIH1cblxuICBlbnN1cmVQcm9jZXNzKCk6IENoaWxkUHJvY2VzcyB7XG4gICAgaWYgKHRoaXMucHJvY2VzcyAmJiB0aGlzLnByb2Nlc3MuZXhpdENvZGUgPT09IG51bGwgJiYgIXRoaXMubmVlZHNSZWN5Y2xlKSB7XG4gICAgICByZXR1cm4gdGhpcy5wcm9jZXNzO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnByb2Nlc3MgJiYgdGhpcy5wcm9jZXNzLmV4aXRDb2RlID09PSBudWxsKSB7XG4gICAgICB0aGlzLnByb2Nlc3Mua2lsbCgpO1xuICAgICAgdGhpcy5wcm9jZXNzID0gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBlbnY6IE5vZGVKUy5Qcm9jZXNzRW52ID0ge1xuICAgICAgUEFUSDogcHJvY2Vzcy5lbnYuUEFUSCxcbiAgICAgIFRNUERJUjogcHJvY2Vzcy5lbnYuVE1QRElSLFxuICAgICAgQ0xBVURFX0NPREVfT0FVVEhfVE9LRU46IHRoaXMuY29uZmlnLnRva2VuLFxuICAgICAgQ0xBVURFX0NPREVfRElTQUJMRV9BVVRPX01FTU9SWTogXCIxXCIsXG4gICAgICBDTEFVREVfQ09ERV9ESVNBQkxFX0FEQVBUSVZFX1RISU5LSU5HOiBcIjFcIixcbiAgICAgIENMQVVERV9DT0RFX0RJU0FCTEVfMU1fQ09OVEVYVDogXCIxXCIsXG4gICAgfTtcblxuICAgIGNvbnN0IHsgY3dkIH0gPSB0aGlzLmNvbmZpZztcbiAgICBpZiAoIXRoaXMuY3dkQ3JlYXRlZCkge1xuICAgICAgbWtkaXJTeW5jKGN3ZCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICB0aGlzLmN3ZENyZWF0ZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIGNvbnN0IGNoaWxkID0gc3Bhd24oXG4gICAgICBcImNsYXVkZVwiLFxuICAgICAgW1xuICAgICAgICBcIi1wXCIsXG4gICAgICAgIFwiLS1pbnB1dC1mb3JtYXRcIixcbiAgICAgICAgXCJzdHJlYW0tanNvblwiLFxuICAgICAgICBcIi0tb3V0cHV0LWZvcm1hdFwiLFxuICAgICAgICBcInN0cmVhbS1qc29uXCIsXG4gICAgICAgIFwiLS12ZXJib3NlXCIsXG4gICAgICAgIFwiLS1tYXgtdHVybnNcIixcbiAgICAgICAgXCIxXCIsXG4gICAgICAgIFwiLS1wZXJtaXNzaW9uLW1vZGVcIixcbiAgICAgICAgXCJieXBhc3NQZXJtaXNzaW9uc1wiLFxuICAgICAgICBcIi0tc2V0dGluZy1zb3VyY2VzXCIsXG4gICAgICAgIFwicHJvamVjdFwiLFxuICAgICAgICBcIi0tbW9kZWxcIixcbiAgICAgICAgdGhpcy5jb25maWcubW9kZWwsXG4gICAgICBdLFxuICAgICAgeyBzdGRpbzogW1wicGlwZVwiLCBcInBpcGVcIiwgXCJpZ25vcmVcIl0sIGVudiwgY3dkIH0sXG4gICAgKTtcblxuICAgIGNoaWxkLnN0ZG91dD8ub24oXCJkYXRhXCIsIChkOiBCdWZmZXIpID0+IHtcbiAgICAgIHRoaXMuYnVmZmVyICs9IGQudG9TdHJpbmcoKTtcbiAgICAgIHRoaXMucHJvY2Vzc0J1ZmZlcigpO1xuICAgIH0pO1xuXG4gICAgY2hpbGQub24oXCJjbG9zZVwiLCAoKSA9PiB7XG4gICAgICB0aGlzLnByb2Nlc3MgPSBudWxsO1xuICAgICAgdGhpcy5yZWplY3RQZW5kaW5nKFxuICAgICAgICBuZXcgUHJvY2Vzc0Vycm9yKGBDTEkgcHJvY2VzcyBjbG9zZWQgKHRva2VuOiAke21hc2tUb2tlbih0aGlzLnRva2VuSWQpfSlgKSxcbiAgICAgICk7XG4gICAgICB0aGlzLmRyYWluUXVldWUoKTtcbiAgICB9KTtcblxuICAgIGNoaWxkLm9uKFwiZXJyb3JcIiwgKGVycikgPT4ge1xuICAgICAgdGhpcy5wcm9jZXNzID0gbnVsbDtcbiAgICAgIHRoaXMucmVqZWN0UGVuZGluZyhcbiAgICAgICAgbmV3IFByb2Nlc3NFcnJvcihgQ0xJIHByb2Nlc3MgZXJyb3I6ICR7ZXJyLm1lc3NhZ2V9ICh0b2tlbjogJHttYXNrVG9rZW4odGhpcy50b2tlbklkKX0pYCksXG4gICAgICApO1xuICAgICAgdGhpcy5kcmFpblF1ZXVlKCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnByb2Nlc3MgPSBjaGlsZDtcbiAgICB0aGlzLmJ1ZmZlciA9IFwiXCI7XG4gICAgdGhpcy5zZXNzaW9uSWQgPSBudWxsO1xuICAgIHRoaXMuY2FsbENvdW50ID0gMDtcbiAgICB0aGlzLm5lZWRzUmVjeWNsZSA9IGZhbHNlO1xuICAgIHJldHVybiBjaGlsZDtcbiAgfVxuXG4gIHByb2Nlc3NCdWZmZXIoKTogdm9pZCB7XG4gICAgY29uc3QgbGluZXMgPSB0aGlzLmJ1ZmZlci5zcGxpdChcIlxcblwiKTtcbiAgICB0aGlzLmJ1ZmZlciA9IGxpbmVzLnBvcCgpID8/IFwiXCI7XG5cbiAgICBsaW5lc1xuICAgICAgLmZpbHRlcigobGluZSkgPT4gbGluZS50cmltKCkgIT09IFwiXCIpXG4gICAgICAuZm9yRWFjaCgobGluZSkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGogPSBKU09OLnBhcnNlKGxpbmUpO1xuXG4gICAgICAgICAgaWYgKGoudHlwZSA9PT0gXCJzeXN0ZW1cIiAmJiBqLnN1YnR5cGUgPT09IFwiaW5pdFwiICYmIGouc2Vzc2lvbl9pZCkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uSWQgPSBqLnNlc3Npb25faWQ7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGoudHlwZSA9PT0gXCJyZXN1bHRcIiAmJiB0aGlzLnBlbmRpbmcpIHtcbiAgICAgICAgICAgIGxldCB0ZXh0OiBzdHJpbmcgPSBqLnJlc3VsdCA/PyBcIlwiO1xuICAgICAgICAgICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXmBgYCg/Ompzb24pP1xccypcXG4/L2ksIFwiXCIpLnJlcGxhY2UoL1xcbj9gYGBcXHMqJC9pLCBcIlwiKTtcblxuICAgICAgICAgICAgaWYgKHRleHQuc3RhcnRzV2l0aChcIllvdSd2ZSBoaXRcIikpIHtcbiAgICAgICAgICAgICAgdGhpcy5wZW5kaW5nLnJlamVjdChcbiAgICAgICAgICAgICAgICBuZXcgUXVvdGFFcnJvcihgUXVvdGEgZXhoYXVzdGVkICh0b2tlbjogJHttYXNrVG9rZW4odGhpcy50b2tlbklkKX0pYCksXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnBlbmRpbmcudGltZXIpO1xuICAgICAgICAgICAgICB0aGlzLnBlbmRpbmcgPSBudWxsO1xuICAgICAgICAgICAgICB0aGlzLmRyYWluUXVldWUoKTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCB1ID0gai51c2FnZSA/PyB7fTtcbiAgICAgICAgICAgIHRoaXMucGVuZGluZy5yZXNvbHZlKHtcbiAgICAgICAgICAgICAgdGV4dCxcbiAgICAgICAgICAgICAgdXNhZ2U6IHtcbiAgICAgICAgICAgICAgICBpbnB1dF90b2tlbnM6IHUuaW5wdXRfdG9rZW5zID8/IDAsXG4gICAgICAgICAgICAgICAgb3V0cHV0X3Rva2VuczogdS5vdXRwdXRfdG9rZW5zID8/IDAsXG4gICAgICAgICAgICAgICAgY2FjaGVfY3JlYXRpb25faW5wdXRfdG9rZW5zOiB1LmNhY2hlX2NyZWF0aW9uX2lucHV0X3Rva2VucyA/PyAwLFxuICAgICAgICAgICAgICAgIGNhY2hlX3JlYWRfaW5wdXRfdG9rZW5zOiB1LmNhY2hlX3JlYWRfaW5wdXRfdG9rZW5zID8/IDAsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGR1cmF0aW9uTXM6IGouZHVyYXRpb25fbXMgPz8gMCxcbiAgICAgICAgICAgICAgY29zdFVzZDogai50b3RhbF9jb3N0X3VzZCA/PyAwLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5wZW5kaW5nLnRpbWVyKTtcbiAgICAgICAgICAgIHRoaXMucGVuZGluZyA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLmRyYWluUXVldWUoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIHNraXAgbm9uLWpzb24gbGluZXNcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICBkcmFpblF1ZXVlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnBlbmRpbmcpIHJldHVybjtcbiAgICBjb25zdCBuZXh0ID0gdGhpcy5xdWV1ZS5zaGlmdCgpO1xuICAgIGlmIChuZXh0KSBuZXh0KCk7XG4gIH1cblxuICBhc3luYyBxdWVyeShpbnB1dDogUXVlcnlJbnB1dCwgdGltZW91dE1zPzogbnVtYmVyKTogUHJvbWlzZTxDbGlSZXN1bHQ+IHtcbiAgICBpZiAodGhpcy5wZW5kaW5nKSB7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgICB0aGlzLnF1ZXVlLnB1c2gocmVzb2x2ZSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCBjaGlsZCA9IHRoaXMuZW5zdXJlUHJvY2VzcygpO1xuICAgIGNvbnN0IHRpbWVvdXQgPSB0aW1lb3V0TXMgPz8gdGhpcy5jb25maWcudGltZW91dDtcblxuICAgIHRoaXMuY2FsbENvdW50Kys7XG4gICAgaWYgKHRoaXMuY2FsbENvdW50ID49IHRoaXMuY29uZmlnLm1heENhbGxzKSB7XG4gICAgICB0aGlzLm5lZWRzUmVjeWNsZSA9IHRydWU7XG4gICAgfVxuXG4gICAgY29uc3QgcHJvbXB0ID0gaW5wdXQuc3lzdGVtID8gYCR7aW5wdXQuc3lzdGVtfVxcblxcbiR7aW5wdXQucHJvbXB0fWAgOiBpbnB1dC5wcm9tcHQ7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2U8Q2xpUmVzdWx0PigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLnBlbmRpbmcgPSBudWxsO1xuICAgICAgICByZWplY3QoXG4gICAgICAgICAgbmV3IFRpbWVvdXRFcnJvcihgVGltZW91dCBhZnRlciAke3RpbWVvdXQgLyAxMDAwfXMgKHRva2VuOiAke21hc2tUb2tlbih0aGlzLnRva2VuSWQpfSlgKSxcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5raWxsKCk7XG4gICAgICB9LCB0aW1lb3V0KTtcblxuICAgICAgdGhpcy5wZW5kaW5nID0geyByZXNvbHZlLCByZWplY3QsIHRpbWVyIH07XG5cbiAgICAgIGNvbnN0IG1zZyA9IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgdHlwZTogXCJ1c2VyXCIsXG4gICAgICAgIG1lc3NhZ2U6IHsgcm9sZTogXCJ1c2VyXCIsIGNvbnRlbnQ6IHByb21wdCB9LFxuICAgICAgICBzZXNzaW9uX2lkOiB0aGlzLnNlc3Npb25JZCA/PyBcImRlZmF1bHRcIixcbiAgICAgICAgcGFyZW50X3Rvb2xfdXNlX2lkOiBudWxsLFxuICAgICAgfSk7XG5cbiAgICAgIGNoaWxkLnN0ZGluPy53cml0ZShgJHttc2d9XFxuYCk7XG4gICAgfSk7XG4gIH1cblxuICBraWxsKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnByb2Nlc3MgJiYgdGhpcy5wcm9jZXNzLmV4aXRDb2RlID09PSBudWxsKSB7XG4gICAgICB0aGlzLnByb2Nlc3Mua2lsbCgpO1xuICAgIH1cbiAgICB0aGlzLnByb2Nlc3MgPSBudWxsO1xuICAgIHRoaXMuYnVmZmVyID0gXCJcIjtcbiAgICB0aGlzLnNlc3Npb25JZCA9IG51bGw7XG4gICAgdGhpcy5jYWxsQ291bnQgPSAwO1xuICAgIHRoaXMubmVlZHNSZWN5Y2xlID0gZmFsc2U7XG4gICAgdGhpcy5yZWplY3RQZW5kaW5nKG5ldyBQcm9jZXNzRXJyb3IoYFdvcmtlciBraWxsZWQgKHRva2VuOiAke21hc2tUb2tlbih0aGlzLnRva2VuSWQpfSlgKSk7XG4gICAgdGhpcy5kcmFpblF1ZXVlKCk7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7QUE2QkEsSUFBYSxTQUFiLE1BQW9CO0NBQ2xCO0NBQ0E7Q0FDQSxVQUErQjtDQUMvQixTQUFTO0NBQ1QsVUFBaUM7Q0FDakMsWUFBMkI7Q0FDM0IsUUFBMkIsRUFBRTtDQUM3QixhQUFhO0NBQ2IsWUFBWTtDQUNaLGVBQWU7Q0FFZixZQUFZLFFBQXNCO0FBQ2hDLE9BQUss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
|