@tekmidian/pai 1.0.2 → 1.0.4
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/.claude-plugin/plugin.json +1 -1
- package/dist/{auto-route-B4azPk4l.mjs → auto-route-21GdHL70.mjs} +2 -2
- package/dist/auto-route-C3S2W3Bc.mjs +11 -0
- package/dist/{budget-Dod6rnA9.mjs → budget-BrloTOZW.mjs} +1 -1
- package/dist/{chain-D-yvET_y.mjs → chain-D7PFur8Y.mjs} +2 -2
- package/dist/cli/index.mjs +82 -198
- package/dist/{cockpit-actions-BWunx3rY.mjs → cockpit-actions-BfRMr2sm.mjs} +6 -6
- package/dist/{cockpit-actions-C8GlTzts.mjs → cockpit-actions-OodH_vx_.mjs} +20 -18
- package/dist/{cockpit-memory-vTlFWV7F.mjs → cockpit-memory-teG9M8bG.mjs} +6 -6
- package/dist/config/defaults/config.yaml +6 -0
- package/dist/{controls-BcKFHeG1.mjs → controls-JLm6g0yP.mjs} +7 -5
- package/dist/daemon/index.mjs +23 -23
- package/dist/daemon-DeYImF1F.mjs +45 -0
- package/dist/daemon-mcp/index.mjs +21 -21
- package/dist/{daemon-ColVHwGZ.mjs → daemon-nXanenDM.mjs} +23 -19
- package/dist/{detect-9CZNO0yf.mjs → detect-BLKsUOgG.mjs} +2 -2
- package/dist/{detect-D1ziFFfA.mjs → detect-Rrimh0xc.mjs} +3 -3
- package/dist/{embed-pass-DIWjA68P.mjs → embed-pass-e64AwDCa.mjs} +1 -1
- package/dist/{endreason-C577xIQz.mjs → endreason-BC-v05H_.mjs} +17 -3
- package/dist/{factory-DjAAsqr_.mjs → factory-B7nv75rC.mjs} +2 -2
- package/dist/{factory-Bsib-qDG.mjs → factory-Bs9imVMq.mjs} +2 -2
- package/dist/{fallback-DFlItw1Z.mjs → fallback-CBWpp2F2.mjs} +227 -5
- package/dist/{health-Dnym-qcT.mjs → health-C4FQmkJn.mjs} +2 -2
- package/dist/{helpers-BD6V-p9w.mjs → helpers-DSNK_1KP.mjs} +2 -2
- package/dist/{helpers-CMGjy_0N.mjs → helpers-Dz7mjTSw.mjs} +3 -3
- package/dist/hooks/capture-all-events.mjs +21 -2
- package/dist/hooks/capture-tool-output.mjs +21 -2
- package/dist/hooks/worker-pool-host.mjs +167 -124
- package/dist/hooks/worker-status-line.mjs +34 -6
- package/dist/index.mjs +4 -4
- package/dist/{indexer-backend-_a6UNhXJ.mjs → indexer-backend-BdjeL4P8.mjs} +32 -229
- package/dist/{ipc-client-CaiGJnSM.mjs → ipc-client-CnYEF31R.mjs} +1 -1
- package/dist/{ipc-client-ZRmDKd5Z.mjs → ipc-client-DN7EvoVo.mjs} +1 -1
- package/dist/{kill-tree-EWYaEk5v.mjs → kill-tree-DleMNZX3.mjs} +2 -2
- package/dist/{kill-tree-BG7dRVtp.mjs → kill-tree-SV6hrIa3.mjs} +2 -2
- package/dist/{launch-Jh5NVeNe.mjs → launch-Di7N-J5X.mjs} +2 -2
- package/dist/{launch-CXVlZjHt.mjs → launch-DlZTKE3u.mjs} +2 -2
- package/dist/{main-config-ops-BEMpuhDz.mjs → main-config-ops-kTXR8Pyv.mjs} +1 -1
- package/dist/{main-resolver-3Ns1HPmS.mjs → main-resolver-yp_puSSb.mjs} +5 -5
- package/dist/{model-inventory-BFVSNFT3.mjs → model-inventory-h6Z9fN_o.mjs} +1 -1
- package/dist/{models-add-BtB3Se6f.mjs → models-add-TVni3A7V.mjs} +22 -22
- package/dist/{pai-marker-DurzIbw8.mjs → pai-marker-BcZyJguM.mjs} +2 -2
- package/dist/{pane-audit-BQytYa60.mjs → pane-audit-Lqy9N_Ki.mjs} +23 -5
- package/dist/{planner-BM27GBfC.mjs → planner-j77ndkBf.mjs} +14 -14
- package/dist/{pool-BRvoOkv6.mjs → pool-Dh-q3iJi.mjs} +43 -4
- package/dist/{pool-cli-B_YR8_Gl.mjs → pool-cli-BggU8GRp.mjs} +2 -2
- package/dist/{pool-cli-DkZTAlSW.mjs → pool-cli-DQ6OzRy2.mjs} +2 -2
- package/dist/{postgres-BdBNkL_l.mjs → postgres-BK4FP9Zg.mjs} +1 -1
- package/dist/{postgres-C6ti4haA.mjs → postgres-DNIOQijl.mjs} +17 -7
- package/dist/{project-setup-CfpApz5o.mjs → project-setup-CBRtFFh0.mjs} +16 -236
- package/dist/{providers-CblTFrhz.mjs → providers-C9QC0TtO.mjs} +2 -2
- package/dist/{providers-BeDiVEb-.mjs → providers-FvCLzFge.mjs} +2 -2
- package/dist/{query-feedback-BRfPtqki.mjs → query-feedback-DN52N9C5.mjs} +1 -1
- package/dist/{registrable-C7b6givx.mjs → registrable-BzH4TObg.mjs} +3 -3
- package/dist/{registrable-Uzgmfyhz.mjs → registrable-DpyTtajg.mjs} +2 -2
- package/dist/{render-Cc2j5QG9.mjs → render-B35bQTE-.mjs} +4 -4
- package/dist/{render-CwIrgxLi.mjs → render-C84BqQRC.mjs} +3 -3
- package/dist/{root-BWy0c2Lq.mjs → root-C4oXlXS_.mjs} +7 -7
- package/dist/{root-wC_6Fx0B.mjs → root-DD1xx_Vu.mjs} +16 -16
- package/dist/route-table-FEfDuhIV.mjs +15 -0
- package/dist/{routing-BAAST9vT.mjs → routing-DmkheCRH.mjs} +126 -8
- package/dist/{routing-CENt4HH1.mjs → routing-f2zulGwD.mjs} +1 -1
- package/dist/{run-6Q9kCPem.mjs → run-BwZKBJZZ.mjs} +28 -14
- package/dist/{scan-ZQWm-_se.mjs → scan-BBGvU5EB.mjs} +4 -4
- package/dist/{session-Bok2PqRS.mjs → session-BAhtXdxj.mjs} +15 -15
- package/dist/{session-DVUExUnX.mjs → session-Dn5OJXlg.mjs} +23 -23
- package/dist/{session-scan-BJI_ZO8M.mjs → session-scan-B57dNuA4.mjs} +1 -1
- package/dist/{session-scan-W-gbwJHM.mjs → session-scan-DUn10MBd.mjs} +2 -2
- package/dist/session-usage-CPvXvSkw.mjs +222 -0
- package/dist/{sources-ESUkZaWv.mjs → sources-CiE3rZek.mjs} +1 -1
- package/dist/{viewer-MWBVJP3u.mjs → viewer-DEySE4c_.mjs} +8 -8
- package/dist/{viewer-DcpJwGKE.mjs → viewer-wfKnvnrI.mjs} +6 -6
- package/dist/{worker-config-gmAq_-rI.mjs → worker-config-CO5FXLAT.mjs} +21 -21
- package/dist/{worker-config-BDYNxbYz.mjs → worker-config-eY5Qy4vl.mjs} +322 -25
- package/dist/{worktree-CrnOqTBW.mjs → worktree-CRs2gyg0.mjs} +2 -2
- package/dist/{zettelkasten-BzMm8REH.mjs → zettelkasten-_h_tUm2T.mjs} +1 -1
- package/dist/{zettelkasten-B_rRRRvD.mjs → zettelkasten-tpCRBYvH.mjs} +2 -2
- package/docs/cockpit.md +1 -0
- package/docs/images/architecture.png +0 -0
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/pai-plugin.json +1 -1
- package/plugins/context-preservation/plugin.json +1 -1
- package/plugins/core/plugin.json +1 -1
- package/plugins/creative/plugin.json +1 -1
- package/plugins/observability/plugin.json +1 -1
- package/plugins/productivity/plugin.json +1 -1
- package/plugins/semantic-search/plugin.json +1 -1
- package/plugins/ui/plugin.json +1 -1
- package/plugins/zettelkasten/plugin.json +1 -1
- package/src/hooks/ts/capture-all-events.ts +15 -3
- package/src/hooks/ts/lib/raw-capture.ts +7 -0
- package/src/hooks/ts/post-tool-use/capture-tool-output.ts +13 -3
- package/dist/auto-route-BjoMHKyI.mjs +0 -11
- package/dist/daemon-N7WhYi6I.mjs +0 -45
- package/dist/route-table-B7zpoypi.mjs +0 -15
|
@@ -2,21 +2,21 @@ import { _ as warn, a as fmtDate, c as ok, d as scaffoldProjectDirs, f as shorte
|
|
|
2
2
|
import { u as claudeProjectsDir } from "./runtime-paths-WsO9sJFc.mjs";
|
|
3
3
|
import { b as nativeOrchestratorModel, j as readWorkersSection, p as getProviderOrNative, t as ANTHROPIC_NATIVE, vt as stripModelVariant, wt as appendLedger } from "./config-XpZWOYOG.mjs";
|
|
4
4
|
import { i as ledgerPath, u as workersLogDir } from "./paths-CHifubDh.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { a as unregistrableReason } from "./registrable-
|
|
7
|
-
import { n as ensurePaiMarker } from "./pai-marker-
|
|
5
|
+
import { M as trustProjectPath } from "./pool-Dh-q3iJi.mjs";
|
|
6
|
+
import { a as unregistrableReason } from "./registrable-DpyTtajg.mjs";
|
|
7
|
+
import { n as ensurePaiMarker } from "./pai-marker-BcZyJguM.mjs";
|
|
8
8
|
import { t as STOP_WORDS } from "./stop-words-DSEYQdNe.mjs";
|
|
9
|
-
import {
|
|
9
|
+
import { dn as SESSION_NAME_ENV, fn as getProfile, x as SESSION_WORKER_PROVIDER_ENV, xt as routeVerdictLine } from "./routing-DmkheCRH.mjs";
|
|
10
10
|
import { n as OPT, t as CliError } from "./define-CjJsmq-6.mjs";
|
|
11
|
-
import { i as getRegistryBackend } from "./factory-
|
|
12
|
-
import { n as formatDetection, r as formatDetectionJson, t as detectProject } from "./detect-
|
|
13
|
-
import { a as getSessionCount, c as upsertTag$1, i as getProjectTags, n as getProject$1, o as requireProject, r as getProjectAliases, s as resolveIdentifier, t as getLastSessionDate } from "./helpers-
|
|
14
|
-
import { a as resolveHome, n as loadScanConfig } from "./scan-
|
|
15
|
-
import { n as buildLaunchPlan, o as launchableProviderNames, s as maskLaunchEnv, t as LaunchError } from "./launch-
|
|
16
|
-
import { a as colorEnabled, f as renderTable$1, i as saveBudgetSnapshot, n as readBudget, o as makeStyle, r as readBudgetSnapshot, t as providerHealth } from "./health-
|
|
17
|
-
import { d as printExitDir, i as probeResume, u as transcriptModelFor } from "./launch-
|
|
11
|
+
import { i as getRegistryBackend } from "./factory-B7nv75rC.mjs";
|
|
12
|
+
import { n as formatDetection, r as formatDetectionJson, t as detectProject } from "./detect-BLKsUOgG.mjs";
|
|
13
|
+
import { a as getSessionCount, c as upsertTag$1, i as getProjectTags, n as getProject$1, o as requireProject, r as getProjectAliases, s as resolveIdentifier, t as getLastSessionDate } from "./helpers-DSNK_1KP.mjs";
|
|
14
|
+
import { a as resolveHome, n as loadScanConfig } from "./scan-BBGvU5EB.mjs";
|
|
15
|
+
import { n as buildLaunchPlan, o as launchableProviderNames, s as maskLaunchEnv, t as LaunchError } from "./launch-Di7N-J5X.mjs";
|
|
16
|
+
import { a as colorEnabled, f as renderTable$1, i as saveBudgetSnapshot, n as readBudget, o as makeStyle, r as readBudgetSnapshot, t as providerHealth } from "./health-C4FQmkJn.mjs";
|
|
17
|
+
import { d as printExitDir, i as probeResume, u as transcriptModelFor } from "./launch-DlZTKE3u.mjs";
|
|
18
18
|
import { n as fetchLiveSessions } from "./aibroker-client-CQPGqLxL.mjs";
|
|
19
|
-
import { a as resolveSessionByNameOrId, s as scanSessions, t as fmtAge } from "./session-scan-
|
|
19
|
+
import { a as resolveSessionByNameOrId, s as scanSessions, t as fmtAge } from "./session-scan-DUn10MBd.mjs";
|
|
20
20
|
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
21
21
|
import { basename, dirname, join, resolve } from "node:path";
|
|
22
22
|
import chalk from "chalk";
|
|
@@ -1066,7 +1066,7 @@ async function getSessionTags(registryBackend, sessionId) {
|
|
|
1066
1066
|
* Session CRUD commands: list, info, rename, slug, tag, route, active, auto-route.
|
|
1067
1067
|
*/
|
|
1068
1068
|
async function cmdList(projectSlug, opts) {
|
|
1069
|
-
const { getRegistryBackend } = await import("./factory-
|
|
1069
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1070
1070
|
const registryBackend = await getRegistryBackend();
|
|
1071
1071
|
const limit = parseInt(opts.limit ?? "20", 10);
|
|
1072
1072
|
let project;
|
|
@@ -1131,7 +1131,7 @@ async function cmdList(projectSlug, opts) {
|
|
|
1131
1131
|
console.log(dim(` ${rows.length} session(s) shown (limit: ${limit})`));
|
|
1132
1132
|
}
|
|
1133
1133
|
async function cmdInfo(projectSlug, sessionNumber) {
|
|
1134
|
-
const { getRegistryBackend } = await import("./factory-
|
|
1134
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1135
1135
|
const registryBackend = await getRegistryBackend();
|
|
1136
1136
|
const project = await getProject(registryBackend, projectSlug);
|
|
1137
1137
|
if (!project) {
|
|
@@ -1155,7 +1155,7 @@ async function cmdInfo(projectSlug, sessionNumber) {
|
|
|
1155
1155
|
console.log();
|
|
1156
1156
|
}
|
|
1157
1157
|
async function cmdRename(projectSlug, numberOrLatest, newSlug) {
|
|
1158
|
-
const { getRegistryBackend } = await import("./factory-
|
|
1158
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1159
1159
|
await cmdRenameWith(await getRegistryBackend(), projectSlug, numberOrLatest, newSlug);
|
|
1160
1160
|
}
|
|
1161
1161
|
/** Strips path separators and ".." so a title can never leave the notes dir. */
|
|
@@ -1242,7 +1242,7 @@ async function cmdRenameWith(registryBackend, projectSlug, numberOrLatest, newSl
|
|
|
1242
1242
|
console.log();
|
|
1243
1243
|
}
|
|
1244
1244
|
async function cmdSlug(projectSlug, numberOrLatest, opts) {
|
|
1245
|
-
const { getRegistryBackend } = await import("./factory-
|
|
1245
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1246
1246
|
const registryBackend = await getRegistryBackend();
|
|
1247
1247
|
const project = await getProject(registryBackend, projectSlug);
|
|
1248
1248
|
if (!project) {
|
|
@@ -1272,7 +1272,7 @@ async function cmdSlug(projectSlug, numberOrLatest, opts) {
|
|
|
1272
1272
|
}
|
|
1273
1273
|
}
|
|
1274
1274
|
async function cmdTag(projectSlug, sessionNumber, rawTags) {
|
|
1275
|
-
const { getRegistryBackend } = await import("./factory-
|
|
1275
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1276
1276
|
const registryBackend = await getRegistryBackend();
|
|
1277
1277
|
const project = await getProject(registryBackend, projectSlug);
|
|
1278
1278
|
if (!project) {
|
|
@@ -1312,7 +1312,7 @@ async function cmdTag(projectSlug, sessionNumber, rawTags) {
|
|
|
1312
1312
|
console.log();
|
|
1313
1313
|
}
|
|
1314
1314
|
async function cmdRoute(projectSlug, sessionNumber, targetProjectSlug, opts) {
|
|
1315
|
-
const { getRegistryBackend } = await import("./factory-
|
|
1315
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1316
1316
|
const registryBackend = await getRegistryBackend();
|
|
1317
1317
|
const project = await getProject(registryBackend, projectSlug);
|
|
1318
1318
|
if (!project) {
|
|
@@ -1354,7 +1354,7 @@ async function cmdRoute(projectSlug, sessionNumber, targetProjectSlug, opts) {
|
|
|
1354
1354
|
console.log();
|
|
1355
1355
|
}
|
|
1356
1356
|
async function cmdActive(opts) {
|
|
1357
|
-
const { getRegistryBackend } = await import("./factory-
|
|
1357
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1358
1358
|
const registryBackend = await getRegistryBackend();
|
|
1359
1359
|
const minutes = parseInt(opts.minutes ?? "60", 10);
|
|
1360
1360
|
const cutoff = Date.now() - minutes * 60 * 1e3;
|
|
@@ -1441,8 +1441,8 @@ async function cmdActive(opts) {
|
|
|
1441
1441
|
], rows));
|
|
1442
1442
|
}
|
|
1443
1443
|
async function cmdAutoRoute(opts) {
|
|
1444
|
-
const { autoRoute, formatAutoRouteJson } = await import("./auto-route-
|
|
1445
|
-
const { getRegistryBackend, createStorageBackend } = await import("./factory-
|
|
1444
|
+
const { autoRoute, formatAutoRouteJson } = await import("./auto-route-C3S2W3Bc.mjs");
|
|
1445
|
+
const { getRegistryBackend, createStorageBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
1446
1446
|
const { loadConfig } = await import("./config-DtENJ6cL.mjs");
|
|
1447
1447
|
const config = loadConfig();
|
|
1448
1448
|
const registryBackend = await getRegistryBackend();
|
|
@@ -1854,7 +1854,7 @@ const newCommand = {
|
|
|
1854
1854
|
const name = ctx.opts.name;
|
|
1855
1855
|
const withSetup = ctx.opts.with;
|
|
1856
1856
|
if (withSetup) {
|
|
1857
|
-
const { runNewWith } = await import("./root-
|
|
1857
|
+
const { runNewWith } = await import("./root-DD1xx_Vu.mjs");
|
|
1858
1858
|
return runNewWith({
|
|
1859
1859
|
dir,
|
|
1860
1860
|
with: withSetup,
|
|
@@ -1960,4 +1960,4 @@ const renameTop = {
|
|
|
1960
1960
|
|
|
1961
1961
|
//#endregion
|
|
1962
1962
|
export { cmdAdd as A, cmdRebind as B, assertAvailable as C, execHarness as D, dryRunText as E, cmdEdit as F, cmdUnarchive as H, cmdGo as I, cmdInfo$1 as L, cmdArchive as M, cmdConsolidate as N, looksLikePath as O, cmdDetect as P, cmdList$1 as R, legacy as S, buildHarness as T, findMovedPath as U, cmdTag$1 as V, cmdList as _, newTop as a, cmdSlug as b, planOpen as c, runNewDefault as d, sessionCommand as f, cmdInfo as g, cmdAutoRoute as h, lsCommand as i, cmdAlias as j, prepareDir as k, renameTop as l, cmdActive as m, collectRows as n, oneLine as o, sessionDir as p, collectView as r, openTop as s, applyProfileChat as t, rowsTable as u, cmdRename as v, modelFor as w, cmdTag as x, cmdRoute as y, cmdMove as z };
|
|
1963
|
-
//# sourceMappingURL=session-
|
|
1963
|
+
//# sourceMappingURL=session-Dn5OJXlg.mjs.map
|
|
@@ -4,6 +4,6 @@ import "./config-Bu1_vbY8.mjs";
|
|
|
4
4
|
import "./paths-CHifubDh.mjs";
|
|
5
5
|
import "./status-ggJ7lgVg.mjs";
|
|
6
6
|
import "./scope-D-h6F6DN.mjs";
|
|
7
|
-
import { a as resolveSessionByNameOrId, c as transcriptCustomTitle, i as resolveFriendlyName, n as loadBrokerNames, o as scanCacheFilePath, r as migrateSessionScanCache, s as scanSessions, t as fmtAge } from "./session-scan-
|
|
7
|
+
import { a as resolveSessionByNameOrId, c as transcriptCustomTitle, i as resolveFriendlyName, n as loadBrokerNames, o as scanCacheFilePath, r as migrateSessionScanCache, s as scanSessions, t as fmtAge } from "./session-scan-DUn10MBd.mjs";
|
|
8
8
|
|
|
9
9
|
export { loadBrokerNames, transcriptCustomTitle };
|
|
@@ -137,7 +137,7 @@ function loadBrokerNames(registryPath = AIBROKER_REGISTRY, mapPath) {
|
|
|
137
137
|
/** Build encoded_dir → root_path map from PAI registry (authoritative cwd). */
|
|
138
138
|
async function buildRegistryRootPathMap() {
|
|
139
139
|
try {
|
|
140
|
-
const { getRegistryBackend } = await import("./factory-
|
|
140
|
+
const { getRegistryBackend } = await import("./factory-Bs9imVMq.mjs");
|
|
141
141
|
const projects = await (await getRegistryBackend()).listProjects();
|
|
142
142
|
const map = /* @__PURE__ */ new Map();
|
|
143
143
|
for (const p of projects) if (p.encoded_dir) map.set(p.encoded_dir, p.root_path);
|
|
@@ -870,4 +870,4 @@ function transcriptCustomTitle(claudeSessionId, projectsDir = CLAUDE_PROJECTS_DI
|
|
|
870
870
|
|
|
871
871
|
//#endregion
|
|
872
872
|
export { resolveSessionByNameOrId as a, transcriptCustomTitle as c, resolveFriendlyName as i, loadBrokerNames as n, scanCacheFilePath as o, migrateSessionScanCache as r, scanSessions as s, fmtAge as t };
|
|
873
|
-
//# sourceMappingURL=session-scan-
|
|
873
|
+
//# sourceMappingURL=session-scan-DUn10MBd.mjs.map
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { createReadStream, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
|
|
4
|
+
//#region src/audit/session-usage.ts
|
|
5
|
+
/**
|
|
6
|
+
* session-usage.ts — parse the usage numbers out of a Claude Code session
|
|
7
|
+
* (or subagent, or pai-worker event-mirror) JSONL transcript.
|
|
8
|
+
*
|
|
9
|
+
* All three log shapes share the same assistant-message envelope
|
|
10
|
+
* ({ type: "assistant", message: { id, model, usage } }), so one parser
|
|
11
|
+
* covers `pai audit tokens session` and the per-log readings feeding
|
|
12
|
+
* `pai audit tokens spawn`.
|
|
13
|
+
*
|
|
14
|
+
* Streaming writes one JSONL line per content block of the same logical
|
|
15
|
+
* turn, repeating message.id and usage each time — summing every line would
|
|
16
|
+
* multiply usage by the block count. Keeping only the first line seen per
|
|
17
|
+
* message.id is what the reference script (and this parser) count instead.
|
|
18
|
+
*/
|
|
19
|
+
const USAGE_KEYS = [
|
|
20
|
+
"cache_read_input_tokens",
|
|
21
|
+
"cache_creation_input_tokens",
|
|
22
|
+
"input_tokens",
|
|
23
|
+
"output_tokens"
|
|
24
|
+
];
|
|
25
|
+
function emptyTotals() {
|
|
26
|
+
return {
|
|
27
|
+
cache_read_input_tokens: 0,
|
|
28
|
+
cache_creation_input_tokens: 0,
|
|
29
|
+
input_tokens: 0,
|
|
30
|
+
output_tokens: 0
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* `type:"system"` `subtype:"compact_boundary"` lines mark a compaction.
|
|
35
|
+
* turnIndex is the count of assistant turns already folded when it fired,
|
|
36
|
+
* so it lines up with the turn numbering the text/JSON report prints.
|
|
37
|
+
*/
|
|
38
|
+
function isCompactBoundary(line) {
|
|
39
|
+
return line.type === "system" && line.subtype === "compact_boundary";
|
|
40
|
+
}
|
|
41
|
+
function parseCompactionEvent(line, turnIndex) {
|
|
42
|
+
const meta = line.compactMetadata;
|
|
43
|
+
if (!meta || typeof meta.preTokens !== "number") return null;
|
|
44
|
+
return {
|
|
45
|
+
trigger: meta.trigger ?? "unknown",
|
|
46
|
+
preTokens: meta.preTokens,
|
|
47
|
+
turnIndex
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* `type:"system"` `subtype:"model_refusal_fallback"` lines mark an
|
|
52
|
+
* automatic model switch fired by an API safety refusal (e.g. "cyber"
|
|
53
|
+
* category), not a user or config choice — worth flagging separately since
|
|
54
|
+
* it can rebuild the whole prompt cache mid-session.
|
|
55
|
+
*/
|
|
56
|
+
function isModelFallback(line) {
|
|
57
|
+
return line.type === "system" && line.subtype === "model_refusal_fallback";
|
|
58
|
+
}
|
|
59
|
+
function parseFallbackEvent(line, turnIndex) {
|
|
60
|
+
return {
|
|
61
|
+
turnIndex,
|
|
62
|
+
from: line.originalModel ?? "unknown",
|
|
63
|
+
to: line.fallbackModel ?? "unknown",
|
|
64
|
+
category: line.apiRefusalCategory ?? "unknown",
|
|
65
|
+
scope: line.scope ?? "unknown"
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Fold one already-parsed JSONL line into a report being accumulated.
|
|
70
|
+
* Exported separately so both the streaming file reader below and tests
|
|
71
|
+
* (which build fixtures as arrays of objects, not files) share one path.
|
|
72
|
+
* Returns the turn's context value when a new turn was counted, else null
|
|
73
|
+
* (non-assistant line, no usage, or a duplicate message.id already seen).
|
|
74
|
+
*/
|
|
75
|
+
function foldAssistantLine(report, seenIds, line, threshold) {
|
|
76
|
+
if (line.type !== "assistant") return null;
|
|
77
|
+
const message = line.message;
|
|
78
|
+
const usage = message?.usage;
|
|
79
|
+
if (!usage) return null;
|
|
80
|
+
const id = message?.id ?? line.uuid;
|
|
81
|
+
if (id) {
|
|
82
|
+
if (seenIds.has(id)) return null;
|
|
83
|
+
seenIds.add(id);
|
|
84
|
+
}
|
|
85
|
+
report.turns++;
|
|
86
|
+
for (const key of USAGE_KEYS) {
|
|
87
|
+
const v = usage[key];
|
|
88
|
+
if (typeof v === "number") report.totals[key] += v;
|
|
89
|
+
}
|
|
90
|
+
const context = (Number(usage.cache_read_input_tokens) || 0) + (Number(usage.cache_creation_input_tokens) || 0) + (Number(usage.input_tokens) || 0);
|
|
91
|
+
if (report.firstTurnContext === null) {
|
|
92
|
+
report.firstTurnContext = context;
|
|
93
|
+
report.firstTurnAt = line.timestamp ?? null;
|
|
94
|
+
}
|
|
95
|
+
const atMs = line.timestamp ? Date.parse(line.timestamp) : NaN;
|
|
96
|
+
if (!Number.isNaN(atMs)) {
|
|
97
|
+
if (report.lastTurnAtMs !== null && atMs - report.lastTurnAtMs > 3600 * 1e3) report.idleGapsOver60min++;
|
|
98
|
+
report.lastTurnAtMs = atMs;
|
|
99
|
+
}
|
|
100
|
+
report.lastTurnContext = context;
|
|
101
|
+
report.maxContext = report.maxContext === null ? context : Math.max(report.maxContext, context);
|
|
102
|
+
if (context > threshold) report.turnsAboveThreshold++;
|
|
103
|
+
if ((Number(usage.cache_creation_input_tokens) || 0) > 2e4) report.cacheRebuildTurns++;
|
|
104
|
+
const model = message?.model ?? "unknown";
|
|
105
|
+
report.models[model] = (report.models[model] ?? 0) + 1;
|
|
106
|
+
if (report.lastModel !== null && report.lastModel !== model) report.modelSwitches.push({
|
|
107
|
+
turnIndex: report.turns,
|
|
108
|
+
from: report.lastModel,
|
|
109
|
+
to: model,
|
|
110
|
+
cacheRead: Number(usage.cache_read_input_tokens) || 0,
|
|
111
|
+
cacheCreation: Number(usage.cache_creation_input_tokens) || 0
|
|
112
|
+
});
|
|
113
|
+
report.lastModel = model;
|
|
114
|
+
const split = usage.cache_creation;
|
|
115
|
+
if (split) {
|
|
116
|
+
report.cacheCreationSplit.ephemeral5m += Number(split.ephemeral_5m_input_tokens) || 0;
|
|
117
|
+
report.cacheCreationSplit.ephemeral1h += Number(split.ephemeral_1h_input_tokens) || 0;
|
|
118
|
+
}
|
|
119
|
+
return context;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* True for a real human-authored `type:"user"` prompt line: content is a
|
|
123
|
+
* plain string, or a content array with no `tool_result` block. Claude Code
|
|
124
|
+
* encodes tool results as `type:"user"` messages whose content array is
|
|
125
|
+
* entirely (or partly) tool_result blocks — those must not count as prompts.
|
|
126
|
+
*/
|
|
127
|
+
function isRealUserPrompt(line) {
|
|
128
|
+
if (line.type !== "user") return false;
|
|
129
|
+
if (line.isMeta) return false;
|
|
130
|
+
if (line.origin?.kind && line.origin.kind !== "human") return false;
|
|
131
|
+
const content = line.message?.content;
|
|
132
|
+
if (typeof content === "string") return true;
|
|
133
|
+
if (Array.isArray(content)) return !content.some((block) => block?.type === "tool_result");
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
/** Plain text of a real user prompt: the string content, or its first text block. */
|
|
137
|
+
function extractUserPromptText(line) {
|
|
138
|
+
const content = line.message?.content;
|
|
139
|
+
if (typeof content === "string") return content;
|
|
140
|
+
if (Array.isArray(content)) return content.find((b) => b?.type === "text")?.text ?? "";
|
|
141
|
+
return "";
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Parse a session/subagent/worker-event JSONL file into a usage report.
|
|
145
|
+
* `keepaliveWord`, when given, counts real user prompts whose text exactly
|
|
146
|
+
* matches it (trimmed) — the sessions.cacheKeepalive beat prompt — into
|
|
147
|
+
* `keepaliveBeats`; omitted, `keepaliveBeats` stays null.
|
|
148
|
+
*/
|
|
149
|
+
async function parseSessionUsage(path, threshold = 2e5, keepaliveWord) {
|
|
150
|
+
const report = {
|
|
151
|
+
path,
|
|
152
|
+
sizeBytes: existsSync(path) ? readFileSync(path).byteLength : 0,
|
|
153
|
+
turns: 0,
|
|
154
|
+
totals: emptyTotals(),
|
|
155
|
+
models: {},
|
|
156
|
+
firstTurnContext: null,
|
|
157
|
+
lastTurnContext: null,
|
|
158
|
+
cacheCreationSplit: {
|
|
159
|
+
ephemeral5m: 0,
|
|
160
|
+
ephemeral1h: 0
|
|
161
|
+
},
|
|
162
|
+
avgContext: null,
|
|
163
|
+
maxContext: null,
|
|
164
|
+
turnsAboveThreshold: 0,
|
|
165
|
+
cacheRebuildTurns: 0,
|
|
166
|
+
userPrompts: 0,
|
|
167
|
+
promptExposure: 0,
|
|
168
|
+
compactions: [],
|
|
169
|
+
firstTurnAt: null,
|
|
170
|
+
lastModel: null,
|
|
171
|
+
modelSwitches: [],
|
|
172
|
+
fallbacks: [],
|
|
173
|
+
lastTurnAtMs: null,
|
|
174
|
+
idleGapsOver60min: 0,
|
|
175
|
+
keepaliveBeats: keepaliveWord ? 0 : null
|
|
176
|
+
};
|
|
177
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
178
|
+
let contextSum = 0;
|
|
179
|
+
const rl = createInterface({
|
|
180
|
+
input: createReadStream(path, "utf8"),
|
|
181
|
+
crlfDelay: Infinity
|
|
182
|
+
});
|
|
183
|
+
for await (const raw of rl) {
|
|
184
|
+
if (!raw.trim()) continue;
|
|
185
|
+
let obj;
|
|
186
|
+
try {
|
|
187
|
+
obj = JSON.parse(raw);
|
|
188
|
+
} catch {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (obj.type === "user") {
|
|
192
|
+
if (isRealUserPrompt(obj)) {
|
|
193
|
+
report.userPrompts++;
|
|
194
|
+
if (keepaliveWord && extractUserPromptText(obj).trim() === keepaliveWord) report.keepaliveBeats = (report.keepaliveBeats ?? 0) + 1;
|
|
195
|
+
}
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (isCompactBoundary(obj)) {
|
|
199
|
+
const event = parseCompactionEvent(obj, report.turns);
|
|
200
|
+
if (event) report.compactions.push(event);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (isModelFallback(obj)) {
|
|
204
|
+
report.fallbacks.push(parseFallbackEvent(obj, report.turns));
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const context = foldAssistantLine(report, seenIds, obj, threshold);
|
|
208
|
+
if (context !== null) {
|
|
209
|
+
contextSum += context;
|
|
210
|
+
report.promptExposure += report.userPrompts;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
report.avgContext = report.turns > 0 ? Math.round(contextSum / report.turns) : null;
|
|
214
|
+
return report;
|
|
215
|
+
}
|
|
216
|
+
function totalUsageTokens(totals) {
|
|
217
|
+
return totals.cache_read_input_tokens + totals.cache_creation_input_tokens + totals.input_tokens + totals.output_tokens;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
//#endregion
|
|
221
|
+
export { totalUsageTokens as i, isRealUserPrompt as n, parseSessionUsage as r, extractUserPromptText as t };
|
|
222
|
+
//# sourceMappingURL=session-usage-CPvXvSkw.mjs.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "./config-XpZWOYOG.mjs";
|
|
2
2
|
import "./config-Bu1_vbY8.mjs";
|
|
3
3
|
import "./paths-CHifubDh.mjs";
|
|
4
|
-
import "./worktree-
|
|
4
|
+
import "./worktree-CRs2gyg0.mjs";
|
|
5
5
|
import "./status-ggJ7lgVg.mjs";
|
|
6
|
-
import "./pool-
|
|
6
|
+
import "./pool-Dh-q3iJi.mjs";
|
|
7
7
|
import "./scope-D-h6F6DN.mjs";
|
|
8
8
|
import "./tool-errors-7E13StWd.mjs";
|
|
9
9
|
import "./wait-ByV0OyMZ.mjs";
|
|
@@ -11,12 +11,12 @@ import "./local-tiers-BE4jGaMa.mjs";
|
|
|
11
11
|
import "./caller-identity-yLFb7CKq.mjs";
|
|
12
12
|
import "./capacity-DEveQdFV.mjs";
|
|
13
13
|
import "./local-candidate-DLdwQt0s.mjs";
|
|
14
|
-
import "./controls-
|
|
15
|
-
import "./endreason-
|
|
16
|
-
import "./render-
|
|
14
|
+
import "./controls-JLm6g0yP.mjs";
|
|
15
|
+
import "./endreason-BC-v05H_.mjs";
|
|
16
|
+
import "./render-C84BqQRC.mjs";
|
|
17
17
|
import "./operator-CyuB3aVw.mjs";
|
|
18
|
-
import "./kill-tree-
|
|
19
|
-
import "./pane-audit-
|
|
20
|
-
import { a as followTailOutput, c as inboxCounts, d as psOutput, f as replayOutput, g as workerEnded, h as strayWorkerProcesses, i as backfillLines, l as initialFollowState, m as statusLineOutput, n as FOLLOW_TAIL_ENTRIES, o as followWorkers, p as resumeArgv, r as applyEvent, s as gutterBody, t as BACKFILL_EVENTS, u as makeOperatorInput } from "./viewer-
|
|
18
|
+
import "./kill-tree-DleMNZX3.mjs";
|
|
19
|
+
import "./pane-audit-Lqy9N_Ki.mjs";
|
|
20
|
+
import { a as followTailOutput, c as inboxCounts, d as psOutput, f as replayOutput, g as workerEnded, h as strayWorkerProcesses, i as backfillLines, l as initialFollowState, m as statusLineOutput, n as FOLLOW_TAIL_ENTRIES, o as followWorkers, p as resumeArgv, r as applyEvent, s as gutterBody, t as BACKFILL_EVENTS, u as makeOperatorInput } from "./viewer-wfKnvnrI.mjs";
|
|
21
21
|
|
|
22
22
|
export { applyEvent, initialFollowState };
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { wt as appendLedger } from "./config-XpZWOYOG.mjs";
|
|
2
2
|
import { i as ledgerPath, r as eventsPath } from "./paths-CHifubDh.mjs";
|
|
3
|
-
import { T as worktreesStats, l as formatWorktreesStats } from "./worktree-
|
|
3
|
+
import { T as worktreesStats, l as formatWorktreesStats } from "./worktree-CRs2gyg0.mjs";
|
|
4
4
|
import { O as reconcileStatuses, _ as isTerminal, g as isLive, h as isChatPane, v as loadStatus, w as ownsPid, y as loadStatuses } from "./status-ggJ7lgVg.mjs";
|
|
5
5
|
import { a as ownerSessionName, f as workerInScope, n as currentTabKey, o as resolveSession } from "./scope-D-h6F6DN.mjs";
|
|
6
6
|
import { _ as lastCommand } from "./tool-errors-7E13StWd.mjs";
|
|
7
7
|
import { M as waitingLine, O as parseWaitOn, i as isWaitPollCommand } from "./wait-ByV0OyMZ.mjs";
|
|
8
8
|
import { a as buildsDir, l as listBuildsSync, p as renderBuildQueue, v as poolSlots } from "./caller-identity-yLFb7CKq.mjs";
|
|
9
9
|
import { l as schedLine, o as readSchedFile } from "./scheduler-CtUyWJ3O.mjs";
|
|
10
|
-
import { Bt as chatTickerRow, Ft as chatEnter, Ht as parseChatLine, It as chatInsertLine, K as renderPlanLines, Lt as chatLeave, Nt as CHAT_HELP, Pt as chatBlankRow, Rt as chatPromptRow, Ut as wrapText, V as loadPlanStatuses, Vt as holdAutoExit, _t as paneTitle, i as localIdleLine, n as markControlsHeld, qt as readInbox, s as readLocalIdle, t as clickrControlsArgv, tt as closeOwnPane, vt as writePaneTitle, yt as psTable, zt as chatScrollRegion } from "./controls-
|
|
11
|
-
import { a as endLabel } from "./endreason-
|
|
12
|
-
import { C as denialLines, _ as renderTable, b as tickerTool, c as headerLine, f as paneStatusRow, g as renderStatusLine, h as renderEvent, i as dayOf, l as intentOf, r as contextMeter, s as gutterFor, t as blankBetween, u as makeColor, y as tickerText } from "./render-
|
|
10
|
+
import { Bt as chatTickerRow, Ft as chatEnter, Ht as parseChatLine, It as chatInsertLine, K as renderPlanLines, Lt as chatLeave, Nt as CHAT_HELP, Pt as chatBlankRow, Rt as chatPromptRow, Ut as wrapText, V as loadPlanStatuses, Vt as holdAutoExit, _t as paneTitle, i as localIdleLine, n as markControlsHeld, qt as readInbox, s as readLocalIdle, t as clickrControlsArgv, tt as closeOwnPane, vt as writePaneTitle, yt as psTable, zt as chatScrollRegion } from "./controls-JLm6g0yP.mjs";
|
|
11
|
+
import { a as endLabel } from "./endreason-BC-v05H_.mjs";
|
|
12
|
+
import { C as denialLines, _ as renderTable, b as tickerTool, c as headerLine, f as paneStatusRow, g as renderStatusLine, h as renderEvent, i as dayOf, l as intentOf, r as contextMeter, s as gutterFor, t as blankBetween, u as makeColor, y as tickerText } from "./render-C84BqQRC.mjs";
|
|
13
13
|
import { r as sayToWorker } from "./operator-CyuB3aVw.mjs";
|
|
14
|
-
import { a as readAudit, d as loadPaneRunStatuses, p as renderPaneRunLines } from "./pane-audit-
|
|
14
|
+
import { a as readAudit, d as loadPaneRunStatuses, p as renderPaneRunLines } from "./pane-audit-Lqy9N_Ki.mjs";
|
|
15
15
|
import { closeSync, existsSync, openSync, readFileSync, readSync } from "node:fs";
|
|
16
16
|
import { spawn } from "node:child_process";
|
|
17
17
|
import { createInterface } from "node:readline";
|
|
@@ -909,4 +909,4 @@ function statusLineOutput(logDir, term, _cwd, claudeSession = "", now = /* @__PU
|
|
|
909
909
|
|
|
910
910
|
//#endregion
|
|
911
911
|
export { followTailOutput as a, inboxCounts as c, psOutput as d, replayOutput as f, workerEnded as g, strayWorkerProcesses as h, backfillLines as i, initialFollowState as l, statusLineOutput as m, FOLLOW_TAIL_ENTRIES as n, followWorkers as o, resumeArgv as p, applyEvent as r, gutterBody as s, BACKFILL_EVENTS as t, makeOperatorInput as u };
|
|
912
|
-
//# sourceMappingURL=viewer-
|
|
912
|
+
//# sourceMappingURL=viewer-wfKnvnrI.mjs.map
|
|
@@ -2,12 +2,12 @@ import "./utils-J2b9y8PC.mjs";
|
|
|
2
2
|
import "./config-XpZWOYOG.mjs";
|
|
3
3
|
import "./config-Bu1_vbY8.mjs";
|
|
4
4
|
import "./paths-CHifubDh.mjs";
|
|
5
|
-
import "./worktree-
|
|
5
|
+
import "./worktree-CRs2gyg0.mjs";
|
|
6
6
|
import "./status-ggJ7lgVg.mjs";
|
|
7
|
-
import "./pool-
|
|
7
|
+
import "./pool-Dh-q3iJi.mjs";
|
|
8
8
|
import "./helpers-CRuBUas3.mjs";
|
|
9
9
|
import "./scope-D-h6F6DN.mjs";
|
|
10
|
-
import "./routing-
|
|
10
|
+
import "./routing-DmkheCRH.mjs";
|
|
11
11
|
import "./tool-errors-7E13StWd.mjs";
|
|
12
12
|
import "./wait-ByV0OyMZ.mjs";
|
|
13
13
|
import "./local-tiers-BE4jGaMa.mjs";
|
|
@@ -15,27 +15,27 @@ import "./caller-identity-yLFb7CKq.mjs";
|
|
|
15
15
|
import "./capacity-DEveQdFV.mjs";
|
|
16
16
|
import "./local-instances-DOxSgT_L.mjs";
|
|
17
17
|
import "./local-candidate-DLdwQt0s.mjs";
|
|
18
|
-
import "./factory-
|
|
19
|
-
import "./postgres-
|
|
18
|
+
import "./factory-B7nv75rC.mjs";
|
|
19
|
+
import "./postgres-DNIOQijl.mjs";
|
|
20
20
|
import "./embedding-gate-6rZrWRXa.mjs";
|
|
21
21
|
import "./embeddings-BVq3esBF.mjs";
|
|
22
22
|
import "./router-CQSc3lk3.mjs";
|
|
23
|
-
import "./launch-
|
|
24
|
-
import "./health-
|
|
25
|
-
import "./run-
|
|
26
|
-
import "./controls-
|
|
27
|
-
import "./endreason-
|
|
28
|
-
import "./render-
|
|
23
|
+
import "./launch-Di7N-J5X.mjs";
|
|
24
|
+
import "./health-C4FQmkJn.mjs";
|
|
25
|
+
import "./run-BwZKBJZZ.mjs";
|
|
26
|
+
import "./controls-JLm6g0yP.mjs";
|
|
27
|
+
import "./endreason-BC-v05H_.mjs";
|
|
28
|
+
import "./render-C84BqQRC.mjs";
|
|
29
29
|
import "./operator-CyuB3aVw.mjs";
|
|
30
|
-
import "./kill-tree-
|
|
31
|
-
import "./pool-cli-
|
|
32
|
-
import "./pane-audit-
|
|
33
|
-
import "./
|
|
34
|
-
import
|
|
35
|
-
import "./
|
|
36
|
-
import "./
|
|
37
|
-
import "./
|
|
38
|
-
import "./
|
|
39
|
-
import "./
|
|
30
|
+
import "./kill-tree-DleMNZX3.mjs";
|
|
31
|
+
import "./pool-cli-BggU8GRp.mjs";
|
|
32
|
+
import "./pane-audit-Lqy9N_Ki.mjs";
|
|
33
|
+
import "./fallback-CBWpp2F2.mjs";
|
|
34
|
+
import "./providers-C9QC0TtO.mjs";
|
|
35
|
+
import { A as workerMcpCommand, C as workerBenchCommand, D as workerFallbackCommand, E as workerControlsCommand, F as workerProvidersCommand, I as workerProxyCommand, L as workerRolesCommand, M as workerOnCommand, N as workerPolicyCommand, O as workerInstallCommand, P as workerPoolCommand, R as workerRouteCommand, S as stopInstance, T as workerConfigCommand, _ as portOpen, a as collectEnv, b as startTier, c as currentInstances, d as isUp, f as killInstance, g as portListeners, h as parseCostTier, i as cliInflight, j as workerOffCommand, k as workerLocalCommand, l as fail, m as listServers, n as WORKER_CONFIG_COMMANDS, o as collectTags, p as launchDetached, r as buildClassTarget, s as controlsArgv, t as PROVIDER_EDIT_COMMANDS, u as healthOk, v as serverLine, w as workerClassesCommand, x as stopAll, y as startInstance } from "./worker-config-eY5Qy4vl.mjs";
|
|
36
|
+
import "./main-config-ops-kTXR8Pyv.mjs";
|
|
37
|
+
import "./cockpit-actions-OodH_vx_.mjs";
|
|
38
|
+
import "./ipc-client-CnYEF31R.mjs";
|
|
39
|
+
import "./embed-pass-e64AwDCa.mjs";
|
|
40
40
|
|
|
41
41
|
export { currentInstances, startInstance, startTier, stopAll, stopInstance };
|