@odla-ai/harness 0.11.17 → 0.11.19
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/{chunk-T2IW7MYQ.js → chunk-4TG55ATB.js} +2 -2
- package/dist/{chunk-RDCU4PIP.js → chunk-7NP3YOMY.js} +37 -9
- package/dist/chunk-7NP3YOMY.js.map +1 -0
- package/dist/{chunk-3ON6UAOV.js → chunk-A5B3CEK2.js} +3 -3
- package/dist/{chunk-EXSEQEZ6.js → chunk-M6BNH25Z.js} +4 -4
- package/dist/{chunk-ONYW2VSB.js → chunk-O4QLHUGO.js} +1 -1
- package/dist/chunk-O4QLHUGO.js.map +1 -0
- package/dist/{chunk-6T26HEWI.js → chunk-SMN2FWQE.js} +17 -3
- package/dist/{chunk-6T26HEWI.js.map → chunk-SMN2FWQE.js.map} +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/code-runtime-cli.cjs +46 -7
- package/dist/code-runtime-cli.cjs.map +1 -1
- package/dist/code-runtime-cli.js +5 -5
- package/dist/code-session-event-data-C6mQB76s.d.cts +134 -0
- package/dist/code-session-event-data-wCQc2py3.d.ts +134 -0
- package/dist/index.cjs +19 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +46 -7
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +23 -7
- package/dist/node.d.ts +23 -7
- package/dist/node.js +6 -6
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/{types-D-Kv1svf.d.ts → types-DM-UgoBN.d.cts} +2 -118
- package/dist/{types-D-Kv1svf.d.cts → types-DM-UgoBN.d.ts} +2 -118
- package/package.json +1 -1
- package/dist/chunk-ONYW2VSB.js.map +0 -1
- package/dist/chunk-RDCU4PIP.js.map +0 -1
- /package/dist/{chunk-T2IW7MYQ.js.map → chunk-4TG55ATB.js.map} +0 -0
- /package/dist/{chunk-3ON6UAOV.js.map → chunk-A5B3CEK2.js.map} +0 -0
- /package/dist/{chunk-EXSEQEZ6.js.map → chunk-M6BNH25Z.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { g as HarnessToolBroker, h as HarnessToolResponse, i as HarnessAgentInput, b as HarnessEventInput, j as HarnessAgentOutput, H as HarnessControlPlane, k as HarnessAiConnection } from './types-DM-UgoBN.js';
|
|
2
|
+
export { D as DEFAULT_AI_ROUTE, l as HARNESS_PROTOCOL_VERSION, m as HarnessActor, n as HarnessAttemptStatus, o as HarnessAttemptSummary, c as HarnessCompletion, p as HarnessEvent, d as HarnessInferenceRequest, e as HarnessInferenceResponse, a as HarnessLease, q as HarnessPolicy, r as HarnessRunnerView, s as HarnessTaskDetail, t as HarnessTaskSpec, u as HarnessTaskStatus, v as HarnessTaskSummary, f as HarnessToolName, w as HarnessToolRequest } from './types-DM-UgoBN.js';
|
|
3
|
+
import { C as CodeSessionEventData } from './code-session-event-data-wCQc2py3.js';
|
|
4
|
+
export { a as CodeSessionEvent, b as CodeToolLocationPreview, c as CodeToolPresentation } from './code-session-event-data-wCQc2py3.js';
|
|
3
5
|
import { Ai } from '@odla-ai/ai';
|
|
4
6
|
|
|
5
7
|
/** Longest failure reason forwarded onto a session event. A reason is a short
|
|
@@ -11,16 +13,25 @@ declare const MAX_FAILURE_REASON = 240;
|
|
|
11
13
|
* failed and could never see why — which is what made an 84% apply_patch
|
|
12
14
|
* failure rate undiagnosable (PM bugs 515655ec and 38d92f1d). */
|
|
13
15
|
declare function toolFailureReason(response: HarnessToolResponse): string | undefined;
|
|
16
|
+
/** Longest serialized tool input, and longest tool output, a verbose stream carries. */
|
|
17
|
+
declare const MAX_VERBOSE_TOOL_BYTES = 4096;
|
|
18
|
+
/** A tool input as a verbose watcher sees it: the object when it fits, else a
|
|
19
|
+
* marker saying how large it was. A stream must never carry a whole file. */
|
|
20
|
+
declare function boundedToolInput(value: Record<string, unknown>): Record<string, unknown>;
|
|
21
|
+
/** A tool output as a verbose watcher sees it, bounded. */
|
|
22
|
+
declare function boundedToolOutput(content: string): string;
|
|
14
23
|
/** Wrap `broker` so every effect reports its start and its finish.
|
|
15
24
|
*
|
|
16
25
|
* `emit` is the engine's own event sink; it already swallows its own errors, so
|
|
17
|
-
* reporting can never fail the effect it is reporting on.
|
|
26
|
+
* reporting can never fail the effect it is reporting on. With `detail:
|
|
27
|
+
* "verbose"` each event also carries the bounded input and output.
|
|
18
28
|
*/
|
|
19
29
|
declare function observedBroker(input: {
|
|
20
30
|
broker: HarnessToolBroker;
|
|
21
31
|
operationIdFor: (requestId: string) => string;
|
|
22
32
|
emit: (event: CodeSessionEventData) => Promise<void>;
|
|
23
33
|
now?: () => number;
|
|
34
|
+
detail?: "standard" | "verbose";
|
|
24
35
|
}): HarnessToolBroker;
|
|
25
36
|
|
|
26
37
|
/** Error raised when an agent emits malformed, oversized, or unsupported protocol data. */
|
|
@@ -62,4 +73,4 @@ declare function createOdlaAiConnection(ai: Pick<Ai, "chat">, options?: {
|
|
|
62
73
|
policyVersion?: number;
|
|
63
74
|
}): HarnessAiConnection;
|
|
64
75
|
|
|
65
|
-
export { CodeSessionEventData, HarnessAgentInput, HarnessAgentOutput, HarnessAiConnection, type HarnessControlClientOptions, HarnessControlError, HarnessControlPlane, HarnessEventInput, HarnessProtocolError, HarnessToolBroker, HarnessToolResponse, MAX_FAILURE_REASON, createHarnessControlClient, createOdlaAiConnection, encodeAgentInput, makeHarnessEvent, observedBroker, parseAgentOutput, toolFailureReason };
|
|
76
|
+
export { CodeSessionEventData, HarnessAgentInput, HarnessAgentOutput, HarnessAiConnection, type HarnessControlClientOptions, HarnessControlError, HarnessControlPlane, HarnessEventInput, HarnessProtocolError, HarnessToolBroker, HarnessToolResponse, MAX_FAILURE_REASON, MAX_VERBOSE_TOOL_BYTES, boundedToolInput, boundedToolOutput, createHarnessControlClient, createOdlaAiConnection, encodeAgentInput, makeHarnessEvent, observedBroker, parseAgentOutput, toolFailureReason };
|
package/dist/index.js
CHANGED
|
@@ -4,19 +4,22 @@ import {
|
|
|
4
4
|
} from "./chunk-PTXZVYD4.js";
|
|
5
5
|
import {
|
|
6
6
|
MAX_FAILURE_REASON,
|
|
7
|
+
MAX_VERBOSE_TOOL_BYTES,
|
|
8
|
+
boundedToolInput,
|
|
9
|
+
boundedToolOutput,
|
|
7
10
|
observedBroker,
|
|
8
11
|
toolFailureReason
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SMN2FWQE.js";
|
|
10
13
|
import {
|
|
11
14
|
HarnessProtocolError,
|
|
12
15
|
encodeAgentInput,
|
|
13
16
|
makeHarnessEvent,
|
|
14
17
|
parseAgentOutput
|
|
15
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-4TG55ATB.js";
|
|
16
19
|
import {
|
|
17
20
|
DEFAULT_AI_ROUTE,
|
|
18
21
|
HARNESS_PROTOCOL_VERSION
|
|
19
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-O4QLHUGO.js";
|
|
20
23
|
|
|
21
24
|
// src/ai.ts
|
|
22
25
|
function createOdlaAiConnection(ai, options = {}) {
|
|
@@ -43,6 +46,9 @@ export {
|
|
|
43
46
|
HarnessControlError,
|
|
44
47
|
HarnessProtocolError,
|
|
45
48
|
MAX_FAILURE_REASON,
|
|
49
|
+
MAX_VERBOSE_TOOL_BYTES,
|
|
50
|
+
boundedToolInput,
|
|
51
|
+
boundedToolOutput,
|
|
46
52
|
createHarnessControlClient,
|
|
47
53
|
createOdlaAiConnection,
|
|
48
54
|
encodeAgentInput,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai.ts"],"sourcesContent":["import type { Ai } from \"@odla-ai/ai\";\nimport type { HarnessAiConnection, HarnessInferenceRequest, HarnessInferenceResponse } from \"./types\";\n\n/**\n * Adapt the normalized odla AI chat surface to a harness connection.\n * Provider credentials remain in the process that owns `ai`; only normalized\n * requests and responses cross the container protocol.\n */\nexport function createOdlaAiConnection(\n ai: Pick<Ai, \"chat\">,\n options: { model?: string; policyVersion?: number } = {},\n): HarnessAiConnection {\n return {\n async infer(request: HarnessInferenceRequest): Promise<HarnessInferenceResponse> {\n const response = await ai.chat({ ...request.call, ...(options.model ? { model: options.model } : {}) });\n return {\n requestId: request.requestId,\n response,\n receipt: {\n provider: response.provider,\n model: response.model,\n policyVersion: options.policyVersion ?? 1,\n inputTokens: response.usage.inputTokens ?? 0,\n outputTokens: response.usage.outputTokens ?? 0,\n },\n };\n },\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/ai.ts"],"sourcesContent":["import type { Ai } from \"@odla-ai/ai\";\nimport type { HarnessAiConnection, HarnessInferenceRequest, HarnessInferenceResponse } from \"./types\";\n\n/**\n * Adapt the normalized odla AI chat surface to a harness connection.\n * Provider credentials remain in the process that owns `ai`; only normalized\n * requests and responses cross the container protocol.\n */\nexport function createOdlaAiConnection(\n ai: Pick<Ai, \"chat\">,\n options: { model?: string; policyVersion?: number } = {},\n): HarnessAiConnection {\n return {\n async infer(request: HarnessInferenceRequest): Promise<HarnessInferenceResponse> {\n const response = await ai.chat({ ...request.call, ...(options.model ? { model: options.model } : {}) });\n return {\n requestId: request.requestId,\n response,\n receipt: {\n provider: response.provider,\n model: response.model,\n policyVersion: options.policyVersion ?? 1,\n inputTokens: response.usage.inputTokens ?? 0,\n outputTokens: response.usage.outputTokens ?? 0,\n },\n };\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAQO,SAAS,uBACd,IACA,UAAsD,CAAC,GAClC;AACrB,SAAO;AAAA,IACL,MAAM,MAAM,SAAqE;AAC/E,YAAM,WAAW,MAAM,GAAG,KAAK,EAAE,GAAG,QAAQ,MAAM,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC,EAAG,CAAC;AACtG,aAAO;AAAA,QACL,WAAW,QAAQ;AAAA,QACnB;AAAA,QACA,SAAS;AAAA,UACP,UAAU,SAAS;AAAA,UACnB,OAAO,SAAS;AAAA,UAChB,eAAe,QAAQ,iBAAiB;AAAA,UACxC,aAAa,SAAS,MAAM,eAAe;AAAA,UAC3C,cAAc,SAAS,MAAM,gBAAgB;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/dist/node.cjs
CHANGED
|
@@ -1446,7 +1446,7 @@ var CodeRuntimeReconciler = class {
|
|
|
1446
1446
|
};
|
|
1447
1447
|
|
|
1448
1448
|
// src/code-runtime.ts
|
|
1449
|
-
var CODE_RUNTIME_PROTOCOL_VERSION =
|
|
1449
|
+
var CODE_RUNTIME_PROTOCOL_VERSION = 4;
|
|
1450
1450
|
async function runCodeRuntimeHeartbeatLoop(options) {
|
|
1451
1451
|
const heartbeatMs = options.heartbeatMs ?? 15e3;
|
|
1452
1452
|
if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1e3 || heartbeatMs > 3e5) {
|
|
@@ -2334,13 +2334,13 @@ function codeCommandMetadata(payload, resume) {
|
|
|
2334
2334
|
const title = payload.title;
|
|
2335
2335
|
const prompt = payload.prompt;
|
|
2336
2336
|
const maxTokensPerInteraction = payload.maxTokensPerInteraction ?? 32e3;
|
|
2337
|
-
if (role !== "coding" && role !== "review" || typeof title !== "string" || typeof prompt !== "string") {
|
|
2337
|
+
if (role !== "coding" && role !== "review" && role !== "planning" || typeof title !== "string" || typeof prompt !== "string") {
|
|
2338
2338
|
throw new TypeError(`invalid Code ${resume ? "resume" : "start"} metadata`);
|
|
2339
2339
|
}
|
|
2340
2340
|
if (payload.readOnly !== void 0 && typeof payload.readOnly !== "boolean") {
|
|
2341
2341
|
throw new TypeError(`invalid Code ${resume ? "resume" : "start"} read-only capability`);
|
|
2342
2342
|
}
|
|
2343
|
-
const readOnly = role
|
|
2343
|
+
const readOnly = role !== "coding" || payload.readOnly === true;
|
|
2344
2344
|
const planning = trusted?.planningInputDigest;
|
|
2345
2345
|
const attestation = trusted?.attestationDigest;
|
|
2346
2346
|
const repository = trusted?.repository;
|
|
@@ -2353,11 +2353,16 @@ function codeCommandMetadata(payload, resume) {
|
|
|
2353
2353
|
if (!Number.isSafeInteger(maxTokensPerInteraction) || Number(maxTokensPerInteraction) < 4e3 || Number(maxTokensPerInteraction) > 2e5) {
|
|
2354
2354
|
throw new TypeError(`invalid Code ${resume ? "resume" : "start"} interaction token limit`);
|
|
2355
2355
|
}
|
|
2356
|
+
const eventDetail = payload.eventDetail ?? "standard";
|
|
2357
|
+
if (eventDetail !== "standard" && eventDetail !== "verbose") {
|
|
2358
|
+
throw new TypeError(`invalid Code ${resume ? "resume" : "start"} event detail`);
|
|
2359
|
+
}
|
|
2356
2360
|
return {
|
|
2357
2361
|
role,
|
|
2358
2362
|
readOnly,
|
|
2359
2363
|
title,
|
|
2360
2364
|
prompt,
|
|
2365
|
+
eventDetail,
|
|
2361
2366
|
proof: codeCommandProof(payload.proof, resume),
|
|
2362
2367
|
maxTokensPerInteraction: Number(maxTokensPerInteraction),
|
|
2363
2368
|
planningInputDigest: typeof planning === "string" && /^sha256:[0-9a-f]{64}$/.test(planning) ? planning : null,
|
|
@@ -3306,6 +3311,20 @@ async function sessionSkillsFor(options, command) {
|
|
|
3306
3311
|
|
|
3307
3312
|
// src/code-runtime-inference.ts
|
|
3308
3313
|
var inferWithBackoff = (infer, wait2, onRetry) => withOverloadRetry(infer, wait2, (cause, delayMs) => onRetry(cause, delayMs), transientControlFailure);
|
|
3314
|
+
var MAX_VERBOSE_TEXT = 4e3;
|
|
3315
|
+
var clip = (text2) => text2.length <= MAX_VERBOSE_TEXT ? text2 : `${text2.slice(0, MAX_VERBOSE_TEXT - 1)}\u2026`;
|
|
3316
|
+
function verboseTurnEvents(response2, durationMs) {
|
|
3317
|
+
const events = [];
|
|
3318
|
+
const interim = response2.response.stopReason === "tool_use";
|
|
3319
|
+
for (const block of response2.response.content) {
|
|
3320
|
+
if (block.type === "thinking" && block.thinking.trim()) {
|
|
3321
|
+
events.push({ type: "thinking", available: true, durationMs, text: clip(block.thinking.trim()) });
|
|
3322
|
+
} else if (block.type === "text" && interim && block.text.trim()) {
|
|
3323
|
+
events.push({ type: "text", text: clip(block.text.trim()) });
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
return events;
|
|
3327
|
+
}
|
|
3309
3328
|
async function handleCodeRuntimeInference(input) {
|
|
3310
3329
|
const { command, request, state } = input;
|
|
3311
3330
|
const startedAt = Date.now();
|
|
@@ -3323,6 +3342,11 @@ async function handleCodeRuntimeInference(input) {
|
|
|
3323
3342
|
message: `Code control plane overloaded (${cause.code}); retrying the model call in ${delayMs / 1e3}s`
|
|
3324
3343
|
}).catch(() => void 0)
|
|
3325
3344
|
);
|
|
3345
|
+
if (input.metadata.eventDetail === "verbose") {
|
|
3346
|
+
for (const event of verboseTurnEvents(response2, Date.now() - startedAt)) {
|
|
3347
|
+
await input.event(event).catch(() => void 0);
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3326
3350
|
state.tokens += response2.receipt.inputTokens + response2.receipt.outputTokens;
|
|
3327
3351
|
const { costUsd } = response2.receipt;
|
|
3328
3352
|
if (costUsd === void 0) state.costKnown = false;
|
|
@@ -3517,8 +3541,17 @@ var DEFAULT_FAILURE_REASON = {
|
|
|
3517
3541
|
"tool denied by CaMeL policy": "tool denied by CaMeL policy",
|
|
3518
3542
|
"review sessions are read-only": "review session is read-only; workspace changes are not permitted"
|
|
3519
3543
|
};
|
|
3544
|
+
var MAX_VERBOSE_TOOL_BYTES = 4096;
|
|
3545
|
+
function boundedToolInput(value) {
|
|
3546
|
+
const serialized = JSON.stringify(value);
|
|
3547
|
+
return serialized.length <= MAX_VERBOSE_TOOL_BYTES ? value : { truncated: true, bytes: serialized.length, keys: Object.keys(value).slice(0, 20) };
|
|
3548
|
+
}
|
|
3549
|
+
function boundedToolOutput(content) {
|
|
3550
|
+
return content.length <= MAX_VERBOSE_TOOL_BYTES ? content : `${content.slice(0, MAX_VERBOSE_TOOL_BYTES - 1)}\u2026`;
|
|
3551
|
+
}
|
|
3520
3552
|
function observedBroker(input) {
|
|
3521
3553
|
const now = input.now ?? Date.now;
|
|
3554
|
+
const verbose = input.detail === "verbose";
|
|
3522
3555
|
return {
|
|
3523
3556
|
execute: async (context, request) => {
|
|
3524
3557
|
const startedAt = now();
|
|
@@ -3529,7 +3562,8 @@ function observedBroker(input) {
|
|
|
3529
3562
|
phase: "started",
|
|
3530
3563
|
tool: request.tool,
|
|
3531
3564
|
operationId,
|
|
3532
|
-
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
3565
|
+
...startedPresentation ? { presentation: startedPresentation } : {},
|
|
3566
|
+
...verbose ? { input: boundedToolInput(request.input) } : {}
|
|
3533
3567
|
});
|
|
3534
3568
|
const response2 = await input.broker.execute(context, request);
|
|
3535
3569
|
const completedPresentation = codeToolResultPresentation(request, response2);
|
|
@@ -3542,7 +3576,8 @@ function observedBroker(input) {
|
|
|
3542
3576
|
durationMs: now() - startedAt,
|
|
3543
3577
|
operationId,
|
|
3544
3578
|
...failureReason ? { failureReason } : {},
|
|
3545
|
-
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
3579
|
+
...completedPresentation ? { presentation: completedPresentation } : {},
|
|
3580
|
+
...verbose ? { output: boundedToolOutput(response2.content) } : {}
|
|
3546
3581
|
});
|
|
3547
3582
|
return response2;
|
|
3548
3583
|
}
|
|
@@ -4435,7 +4470,7 @@ function createCodeRuntimeToolBroker(input, lease, role) {
|
|
|
4435
4470
|
"sandbox.who_touches",
|
|
4436
4471
|
"sandbox.run_recipe"
|
|
4437
4472
|
]);
|
|
4438
|
-
return role
|
|
4473
|
+
return role !== "review" ? broker : { execute: (context, request) => reviewTools.has(request.tool) ? broker.execute(context, request) : Promise.resolve({ requestId: request.requestId, ok: false, content: "review sessions are read-only" }) };
|
|
4439
4474
|
}
|
|
4440
4475
|
|
|
4441
4476
|
// src/code-runtime-events.ts
|
|
@@ -5022,6 +5057,7 @@ var TheseusRuntimeEngine = class {
|
|
|
5022
5057
|
buildPolicyDigest: resolvedRecipes.buildPolicyDigest,
|
|
5023
5058
|
role: metadata.role,
|
|
5024
5059
|
readOnly: metadata.readOnly,
|
|
5060
|
+
eventDetail: metadata.eventDetail,
|
|
5025
5061
|
title: metadata.title,
|
|
5026
5062
|
proof: metadata.proof,
|
|
5027
5063
|
maxTokensPerInteraction: metadata.maxTokensPerInteraction,
|
|
@@ -5089,6 +5125,7 @@ var TheseusRuntimeEngine = class {
|
|
|
5089
5125
|
prompt,
|
|
5090
5126
|
proof: active.proof,
|
|
5091
5127
|
maxTokensPerInteraction: active.maxTokensPerInteraction,
|
|
5128
|
+
eventDetail: active.eventDetail,
|
|
5092
5129
|
planningInputDigest: active.planningInputDigest,
|
|
5093
5130
|
attestationDigest: "pursue",
|
|
5094
5131
|
repository: active.repository,
|
|
@@ -5133,6 +5170,7 @@ var TheseusRuntimeEngine = class {
|
|
|
5133
5170
|
prompt,
|
|
5134
5171
|
proof: active.proof,
|
|
5135
5172
|
maxTokensPerInteraction: active.maxTokensPerInteraction,
|
|
5173
|
+
eventDetail: active.eventDetail,
|
|
5136
5174
|
planningInputDigest: active.planningInputDigest,
|
|
5137
5175
|
attestationDigest: "follow-up",
|
|
5138
5176
|
repository: active.repository,
|
|
@@ -5216,7 +5254,8 @@ var TheseusRuntimeEngine = class {
|
|
|
5216
5254
|
return observedBroker({
|
|
5217
5255
|
broker,
|
|
5218
5256
|
operationIdFor: (requestId) => digestRuntimeValue(`${command.commandId}:${requestId}`),
|
|
5219
|
-
emit: (event) => this.#event(command, event, active.conversationRefs).catch(() => void 0)
|
|
5257
|
+
emit: (event) => this.#event(command, event, active.conversationRefs).catch(() => void 0),
|
|
5258
|
+
detail: active.eventDetail
|
|
5220
5259
|
});
|
|
5221
5260
|
}
|
|
5222
5261
|
async #checkpoint(command) {
|