@aiden-ade/sandbox-agent 0.1.22 → 0.1.23
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/index.cjs +183 -33
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4855,6 +4855,7 @@ function resolveCommand(args, env) {
|
|
|
4855
4855
|
}
|
|
4856
4856
|
|
|
4857
4857
|
// src/daemon.ts
|
|
4858
|
+
var import_node_child_process3 = require("child_process");
|
|
4858
4859
|
var import_node_crypto2 = require("crypto");
|
|
4859
4860
|
var import_node_fs4 = require("fs");
|
|
4860
4861
|
var import_node_http = __toESM(require("http"), 1);
|
|
@@ -7234,12 +7235,13 @@ var Encoder = class {
|
|
|
7234
7235
|
var Decoder = class _Decoder extends Emitter {
|
|
7235
7236
|
/**
|
|
7236
7237
|
* Decoder constructor
|
|
7237
|
-
*
|
|
7238
|
-
* @param {function} reviver - custom reviver to pass down to JSON.stringify
|
|
7239
7238
|
*/
|
|
7240
|
-
constructor(
|
|
7239
|
+
constructor(opts) {
|
|
7241
7240
|
super();
|
|
7242
|
-
this.
|
|
7241
|
+
this.opts = Object.assign({
|
|
7242
|
+
reviver: void 0,
|
|
7243
|
+
maxAttachments: 10
|
|
7244
|
+
}, typeof opts === "function" ? { reviver: opts } : opts);
|
|
7243
7245
|
}
|
|
7244
7246
|
/**
|
|
7245
7247
|
* Decodes an encoded packet string into packet JSON.
|
|
@@ -7299,7 +7301,13 @@ var Decoder = class _Decoder extends Emitter {
|
|
|
7299
7301
|
if (buf != Number(buf) || str.charAt(i) !== "-") {
|
|
7300
7302
|
throw new Error("Illegal attachments");
|
|
7301
7303
|
}
|
|
7302
|
-
|
|
7304
|
+
const n = Number(buf);
|
|
7305
|
+
if (!isInteger(n) || n < 0) {
|
|
7306
|
+
throw new Error("Illegal attachments");
|
|
7307
|
+
} else if (n > this.opts.maxAttachments) {
|
|
7308
|
+
throw new Error("too many attachments");
|
|
7309
|
+
}
|
|
7310
|
+
p.attachments = n;
|
|
7303
7311
|
}
|
|
7304
7312
|
if ("/" === str.charAt(i + 1)) {
|
|
7305
7313
|
const start = i + 1;
|
|
@@ -7341,7 +7349,7 @@ var Decoder = class _Decoder extends Emitter {
|
|
|
7341
7349
|
}
|
|
7342
7350
|
tryParse(str) {
|
|
7343
7351
|
try {
|
|
7344
|
-
return JSON.parse(str, this.reviver);
|
|
7352
|
+
return JSON.parse(str, this.opts.reviver);
|
|
7345
7353
|
} catch (e) {
|
|
7346
7354
|
return false;
|
|
7347
7355
|
}
|
|
@@ -9524,22 +9532,6 @@ var STATUS_OPTIONS = [
|
|
|
9524
9532
|
dotClass: "text-amber-700 dark:text-amber-400",
|
|
9525
9533
|
headerBg: "bg-amber-400/15"
|
|
9526
9534
|
},
|
|
9527
|
-
{
|
|
9528
|
-
value: "running",
|
|
9529
|
-
label: "Running",
|
|
9530
|
-
color: CATEGORICAL_COLORS.indigo,
|
|
9531
|
-
group: "active",
|
|
9532
|
-
dotClass: "text-indigo-500 dark:text-indigo-400",
|
|
9533
|
-
headerBg: "bg-indigo-400/15"
|
|
9534
|
-
},
|
|
9535
|
-
{
|
|
9536
|
-
value: "waiting",
|
|
9537
|
-
label: "Waiting",
|
|
9538
|
-
color: CATEGORICAL_COLORS.orangeDeep,
|
|
9539
|
-
group: "active",
|
|
9540
|
-
dotClass: "text-orange-500/80 dark:text-orange-400/80",
|
|
9541
|
-
headerBg: "bg-orange-400/15"
|
|
9542
|
-
},
|
|
9543
9535
|
{
|
|
9544
9536
|
value: "in_review",
|
|
9545
9537
|
label: "In Review",
|
|
@@ -11141,8 +11133,8 @@ function parseDroidStructuredLine(line, context, state) {
|
|
|
11141
11133
|
break;
|
|
11142
11134
|
}
|
|
11143
11135
|
}
|
|
11144
|
-
function droidExecPermissionArgs(
|
|
11145
|
-
if (
|
|
11136
|
+
function droidExecPermissionArgs(config) {
|
|
11137
|
+
if (shouldUseReadOnlyRuntimePermissions(config)) return [];
|
|
11146
11138
|
return ["--auto", "high"];
|
|
11147
11139
|
}
|
|
11148
11140
|
function createDroidCliBackend(command = "droid", defaultArgs = []) {
|
|
@@ -11165,7 +11157,7 @@ function createDroidCliBackend(command = "droid", defaultArgs = []) {
|
|
|
11165
11157
|
"exec",
|
|
11166
11158
|
"--output-format",
|
|
11167
11159
|
"stream-json",
|
|
11168
|
-
...droidExecPermissionArgs(ctx.config
|
|
11160
|
+
...droidExecPermissionArgs(ctx.config),
|
|
11169
11161
|
...defaultArgs
|
|
11170
11162
|
];
|
|
11171
11163
|
const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
|
|
@@ -11309,7 +11301,7 @@ function createGeminiCliBackend(command = "gemini", defaultArgs = []) {
|
|
|
11309
11301
|
buildArgs: (ctx) => {
|
|
11310
11302
|
const args = ["-p", "", "--output-format", "stream-json"];
|
|
11311
11303
|
const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
|
|
11312
|
-
const approvalMode = ctx.config
|
|
11304
|
+
const approvalMode = shouldUseReadOnlyRuntimePermissions(ctx.config) ? "plan" : "yolo";
|
|
11313
11305
|
args.push("--approval-mode", approvalMode);
|
|
11314
11306
|
if (resumeId) args.push("--resume", resumeId);
|
|
11315
11307
|
if (ctx.config.selectedModel?.trim())
|
|
@@ -11438,6 +11430,21 @@ function createKimiCliBackend(command = "kimi-cli", defaultArgs = []) {
|
|
|
11438
11430
|
}
|
|
11439
11431
|
};
|
|
11440
11432
|
}
|
|
11433
|
+
function getRecord(value2) {
|
|
11434
|
+
return typeof value2 === "object" && value2 !== null ? value2 : null;
|
|
11435
|
+
}
|
|
11436
|
+
function getString(value2) {
|
|
11437
|
+
return typeof value2 === "string" ? value2.trim() : "";
|
|
11438
|
+
}
|
|
11439
|
+
function getOpenCodeToolError(parsed, part) {
|
|
11440
|
+
const state = getRecord(part?.state) ?? getRecord(parsed.state);
|
|
11441
|
+
const error = getRecord(part?.error) ?? getRecord(parsed.error) ?? getRecord(state?.error);
|
|
11442
|
+
return getString(part?.error) || getString(state?.error) || getString(error?.message) || getString(parsed.error);
|
|
11443
|
+
}
|
|
11444
|
+
function isOpenCodeToolError(parsed, part) {
|
|
11445
|
+
const state = getRecord(part?.state) ?? getRecord(parsed.state);
|
|
11446
|
+
return part?.is_error === true || part?.isError === true || state?.status === "error" || Boolean(getOpenCodeToolError(parsed, part));
|
|
11447
|
+
}
|
|
11441
11448
|
function parseOpencodeStructuredLine(line, context, state) {
|
|
11442
11449
|
const presenter = context.presenter;
|
|
11443
11450
|
let parsed = null;
|
|
@@ -11468,16 +11475,44 @@ function parseOpencodeStructuredLine(line, context, state) {
|
|
|
11468
11475
|
}
|
|
11469
11476
|
case "tool_use":
|
|
11470
11477
|
case "tool.execute": {
|
|
11471
|
-
const toolName = part && typeof part.name === "string" ? part.name : "
|
|
11478
|
+
const toolName = getString(parsed.tool) || (part && typeof part.name === "string" ? part.name : "") || getString(parsed.name) || (part && typeof part.tool === "string" ? part.tool : "") || "Tool";
|
|
11472
11479
|
const toolId = part && typeof part.id === "string" ? part.id : `opencode-tool-${Date.now()}`;
|
|
11473
11480
|
void presenter.onToolUse(toolName, part ?? {}, toolId);
|
|
11474
11481
|
break;
|
|
11475
11482
|
}
|
|
11483
|
+
case "tool": {
|
|
11484
|
+
const stateRecord = getRecord(parsed.state);
|
|
11485
|
+
const toolName = getString(parsed.tool) || (part && typeof part.name === "string" ? part.name : "") || getString(parsed.name) || (part && typeof part.tool === "string" ? part.tool : "") || "Tool";
|
|
11486
|
+
const toolId = getString(parsed.id) || getString(parsed.callID) || `opencode-tool-${Date.now()}`;
|
|
11487
|
+
state.opencodeToolUseIds ??= /* @__PURE__ */ new Set();
|
|
11488
|
+
if (!state.opencodeToolUseIds.has(toolId)) {
|
|
11489
|
+
state.opencodeToolUseIds.add(toolId);
|
|
11490
|
+
void presenter.onToolUse(toolName, stateRecord?.input ?? part ?? parsed, toolId);
|
|
11491
|
+
}
|
|
11492
|
+
const status = getString(stateRecord?.status);
|
|
11493
|
+
if (status === "completed" || status === "error") {
|
|
11494
|
+
const toolError = isOpenCodeToolError(parsed, part);
|
|
11495
|
+
const output = getString(stateRecord?.output) || getString(stateRecord?.error) || JSON.stringify(stateRecord ?? part ?? parsed);
|
|
11496
|
+
void presenter.onToolResult?.(toolId, output, toolError);
|
|
11497
|
+
if (toolError && !state.error) {
|
|
11498
|
+
const message = getOpenCodeToolError(parsed, part) || "OpenCode tool call failed.";
|
|
11499
|
+
state.error = message;
|
|
11500
|
+
void presenter.onError(message);
|
|
11501
|
+
}
|
|
11502
|
+
}
|
|
11503
|
+
break;
|
|
11504
|
+
}
|
|
11476
11505
|
case "tool_result":
|
|
11477
11506
|
case "tool.result": {
|
|
11478
11507
|
const toolId = part && typeof part.id === "string" ? part.id : `opencode-tool-${Date.now()}`;
|
|
11479
11508
|
const output = part && typeof part.output === "string" ? part.output : JSON.stringify(part);
|
|
11480
|
-
|
|
11509
|
+
const toolError = isOpenCodeToolError(parsed, part);
|
|
11510
|
+
void presenter.onToolResult?.(toolId, output, toolError);
|
|
11511
|
+
if (toolError && !state.error) {
|
|
11512
|
+
const message = getOpenCodeToolError(parsed, part) || "OpenCode tool call failed.";
|
|
11513
|
+
state.error = message;
|
|
11514
|
+
void presenter.onError(message);
|
|
11515
|
+
}
|
|
11481
11516
|
break;
|
|
11482
11517
|
}
|
|
11483
11518
|
case "step_finish": {
|
|
@@ -11533,6 +11568,36 @@ function parseOpencodeStructuredLine(line, context, state) {
|
|
|
11533
11568
|
break;
|
|
11534
11569
|
}
|
|
11535
11570
|
}
|
|
11571
|
+
var AUTONOMOUS_OPENCODE_CONFIG_CONTENT = JSON.stringify({
|
|
11572
|
+
$schema: "https://opencode.ai/config.json",
|
|
11573
|
+
permission: "allow"
|
|
11574
|
+
});
|
|
11575
|
+
function buildAutonomousOpenCodeConfigContent(existing) {
|
|
11576
|
+
if (!existing?.trim()) return AUTONOMOUS_OPENCODE_CONFIG_CONTENT;
|
|
11577
|
+
try {
|
|
11578
|
+
const parsed = JSON.parse(existing);
|
|
11579
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
11580
|
+
return JSON.stringify({
|
|
11581
|
+
...parsed,
|
|
11582
|
+
permission: "allow"
|
|
11583
|
+
});
|
|
11584
|
+
}
|
|
11585
|
+
} catch {
|
|
11586
|
+
}
|
|
11587
|
+
return AUTONOMOUS_OPENCODE_CONFIG_CONTENT;
|
|
11588
|
+
}
|
|
11589
|
+
function withAutonomousOpenCodePermissions(context) {
|
|
11590
|
+
if (shouldUseReadOnlyRuntimePermissions(context.config)) return context;
|
|
11591
|
+
return {
|
|
11592
|
+
...context,
|
|
11593
|
+
env: {
|
|
11594
|
+
...context.env,
|
|
11595
|
+
OPENCODE_CONFIG_CONTENT: buildAutonomousOpenCodeConfigContent(
|
|
11596
|
+
context.env.OPENCODE_CONFIG_CONTENT
|
|
11597
|
+
)
|
|
11598
|
+
}
|
|
11599
|
+
};
|
|
11600
|
+
}
|
|
11536
11601
|
function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
|
|
11537
11602
|
return {
|
|
11538
11603
|
kind: "opencode_cli",
|
|
@@ -11543,6 +11608,7 @@ function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
|
|
|
11543
11608
|
context.cwd
|
|
11544
11609
|
);
|
|
11545
11610
|
try {
|
|
11611
|
+
const runContext = withAutonomousOpenCodePermissions(context);
|
|
11546
11612
|
return await createGenericCliBackend({
|
|
11547
11613
|
kind: "opencode_cli",
|
|
11548
11614
|
supportTier: "structured",
|
|
@@ -11550,6 +11616,9 @@ function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
|
|
|
11550
11616
|
args: [],
|
|
11551
11617
|
buildArgs: (ctx, prompt) => {
|
|
11552
11618
|
const args = ["run", "--format", "json"];
|
|
11619
|
+
if (!shouldUseReadOnlyRuntimePermissions(ctx.config)) {
|
|
11620
|
+
args.push("--dangerously-skip-permissions");
|
|
11621
|
+
}
|
|
11553
11622
|
const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
|
|
11554
11623
|
if (resumeId) args.push("--session", resumeId);
|
|
11555
11624
|
const model = ctx.config.selectedModel?.trim();
|
|
@@ -11565,7 +11634,7 @@ function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
|
|
|
11565
11634
|
return ctx.config.mode === "plan" ? buildPlanModePrefix(base) : base;
|
|
11566
11635
|
},
|
|
11567
11636
|
parseStructuredLine: parseOpencodeStructuredLine
|
|
11568
|
-
}).run(
|
|
11637
|
+
}).run(runContext);
|
|
11569
11638
|
} finally {
|
|
11570
11639
|
cleanup();
|
|
11571
11640
|
}
|
|
@@ -11744,6 +11813,7 @@ function expandSkillInvocationPrompt(text, cwd) {
|
|
|
11744
11813
|
}
|
|
11745
11814
|
var DEFAULT_MODEL = "claude-sonnet-4-6";
|
|
11746
11815
|
var DROID_DEFAULT_MODEL = "claude-opus-4-7";
|
|
11816
|
+
var AGENT_ACTIVITY_HEARTBEAT_MS = 1e4;
|
|
11747
11817
|
function defaultSelectedModelForBackend(backendKind) {
|
|
11748
11818
|
switch (backendKind) {
|
|
11749
11819
|
case "claude_cli":
|
|
@@ -11754,6 +11824,8 @@ function defaultSelectedModelForBackend(backendKind) {
|
|
|
11754
11824
|
return "claude-sonnet-4.5";
|
|
11755
11825
|
case "kimi_cli":
|
|
11756
11826
|
return void 0;
|
|
11827
|
+
case "opencode_cli":
|
|
11828
|
+
return void 0;
|
|
11757
11829
|
case "supatest_cli":
|
|
11758
11830
|
return "medium";
|
|
11759
11831
|
default:
|
|
@@ -11857,6 +11929,26 @@ var BaseMachineAgent = class _BaseMachineAgent {
|
|
|
11857
11929
|
buildPromptText(config) {
|
|
11858
11930
|
return buildPromptWithFiles(config.task, config.files);
|
|
11859
11931
|
}
|
|
11932
|
+
getActivityHeartbeatIntervalMs() {
|
|
11933
|
+
return AGENT_ACTIVITY_HEARTBEAT_MS;
|
|
11934
|
+
}
|
|
11935
|
+
async runBackendWithActivityHeartbeat(backend, context) {
|
|
11936
|
+
const intervalMs = this.getActivityHeartbeatIntervalMs();
|
|
11937
|
+
let heartbeat = null;
|
|
11938
|
+
if (this.presenter.onActivity && intervalMs > 0) {
|
|
11939
|
+
void this.presenter.onActivity("background_work");
|
|
11940
|
+
heartbeat = setInterval(() => {
|
|
11941
|
+
if (!context.abortController.signal.aborted) {
|
|
11942
|
+
void this.presenter.onActivity?.("background_work");
|
|
11943
|
+
}
|
|
11944
|
+
}, intervalMs);
|
|
11945
|
+
}
|
|
11946
|
+
try {
|
|
11947
|
+
return await backend.run(context);
|
|
11948
|
+
} finally {
|
|
11949
|
+
if (heartbeat) clearInterval(heartbeat);
|
|
11950
|
+
}
|
|
11951
|
+
}
|
|
11860
11952
|
// ── Shared helpers ─────────────────────────────────────────────────────
|
|
11861
11953
|
abort() {
|
|
11862
11954
|
this.abortController?.abort();
|
|
@@ -11941,7 +12033,7 @@ Prefer relative paths and keep your work scoped to this project.`
|
|
|
11941
12033
|
let lastResult = null;
|
|
11942
12034
|
for (let attempt = 0; attempt <= _BaseMachineAgent.MAX_RETRIES; attempt++) {
|
|
11943
12035
|
if (this.abortController?.signal.aborted) break;
|
|
11944
|
-
const result = await
|
|
12036
|
+
const result = await this.runBackendWithActivityHeartbeat(backend, {
|
|
11945
12037
|
presenter: this.presenter,
|
|
11946
12038
|
config: runtimeConfig,
|
|
11947
12039
|
abortController: this.abortController,
|
|
@@ -11974,7 +12066,7 @@ Prefer relative paths and keep your work scoped to this project.`
|
|
|
11974
12066
|
runtimeSessionId: void 0,
|
|
11975
12067
|
providerSessionId: void 0
|
|
11976
12068
|
};
|
|
11977
|
-
const retryResult = await
|
|
12069
|
+
const retryResult = await this.runBackendWithActivityHeartbeat(backend, {
|
|
11978
12070
|
presenter: this.presenter,
|
|
11979
12071
|
config: runtimeConfig,
|
|
11980
12072
|
abortController: this.abortController,
|
|
@@ -12508,9 +12600,16 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName) {
|
|
|
12508
12600
|
}
|
|
12509
12601
|
|
|
12510
12602
|
// src/version.ts
|
|
12511
|
-
var AGENT_VERSION = "0.1.
|
|
12603
|
+
var AGENT_VERSION = "0.1.23";
|
|
12512
12604
|
|
|
12513
12605
|
// src/daemon.ts
|
|
12606
|
+
var OPENCODE_FREE_MODEL_IDS = [
|
|
12607
|
+
"opencode/north-mini-code-free",
|
|
12608
|
+
"opencode/nemotron-3-ultra-free",
|
|
12609
|
+
"opencode/deepseek-v4-flash-free",
|
|
12610
|
+
"opencode/mimo-v2.5-free",
|
|
12611
|
+
"opencode/big-pickle"
|
|
12612
|
+
];
|
|
12514
12613
|
var PRODUCTION_API_URL = "https://api.aiden-platform.com";
|
|
12515
12614
|
var PRODUCTION_WS_URL = "wss://ws.aiden-platform.com";
|
|
12516
12615
|
var LOCAL_API_URL = "http://localhost:8400";
|
|
@@ -12604,6 +12703,57 @@ function normalizeBackendKind(backendKind) {
|
|
|
12604
12703
|
if (backendKind === "codex") return "codex_app_server";
|
|
12605
12704
|
return backendKind;
|
|
12606
12705
|
}
|
|
12706
|
+
function readModelId(value2) {
|
|
12707
|
+
if (typeof value2 === "string") {
|
|
12708
|
+
const trimmed = value2.trim();
|
|
12709
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
12710
|
+
}
|
|
12711
|
+
if (!value2 || typeof value2 !== "object") return null;
|
|
12712
|
+
const record = value2;
|
|
12713
|
+
return readModelId(record.id) ?? readModelId(record.model) ?? readModelId(record.name) ?? readModelId(record.value);
|
|
12714
|
+
}
|
|
12715
|
+
function extractModelIdsFromJson(value2) {
|
|
12716
|
+
if (Array.isArray(value2)) {
|
|
12717
|
+
return [...new Set(value2.map(readModelId).filter((model) => Boolean(model)))];
|
|
12718
|
+
}
|
|
12719
|
+
if (!value2 || typeof value2 !== "object") return [];
|
|
12720
|
+
const record = value2;
|
|
12721
|
+
for (const key of ["models", "data", "items"]) {
|
|
12722
|
+
const nested = extractModelIdsFromJson(record[key]);
|
|
12723
|
+
if (nested.length > 0) return nested;
|
|
12724
|
+
}
|
|
12725
|
+
const byProvider = record.opencode ?? record.providers;
|
|
12726
|
+
if (byProvider) {
|
|
12727
|
+
const nested = extractModelIdsFromJson(byProvider);
|
|
12728
|
+
if (nested.length > 0) return nested;
|
|
12729
|
+
}
|
|
12730
|
+
return [];
|
|
12731
|
+
}
|
|
12732
|
+
function discoverOpenCodeModels(executable, env) {
|
|
12733
|
+
for (const args of [
|
|
12734
|
+
["models", "--json"],
|
|
12735
|
+
["models", "list", "--json"],
|
|
12736
|
+
["model", "list", "--json"]
|
|
12737
|
+
]) {
|
|
12738
|
+
const result = (0, import_node_child_process3.spawnSync)(executable, args, {
|
|
12739
|
+
encoding: "utf8",
|
|
12740
|
+
timeout: 5e3,
|
|
12741
|
+
env,
|
|
12742
|
+
windowsHide: true
|
|
12743
|
+
});
|
|
12744
|
+
if (!result || result.error || result.status !== 0 || !result.stdout.trim()) continue;
|
|
12745
|
+
try {
|
|
12746
|
+
const models = extractModelIdsFromJson(JSON.parse(result.stdout));
|
|
12747
|
+
if (models.length > 0) return models;
|
|
12748
|
+
} catch {
|
|
12749
|
+
}
|
|
12750
|
+
}
|
|
12751
|
+
return OPENCODE_FREE_MODEL_IDS;
|
|
12752
|
+
}
|
|
12753
|
+
function discoverProviderModels(provider, executable, env) {
|
|
12754
|
+
if (provider === "opencode_cli") return discoverOpenCodeModels(executable, env);
|
|
12755
|
+
return [];
|
|
12756
|
+
}
|
|
12607
12757
|
function discoverCapabilities() {
|
|
12608
12758
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12609
12759
|
const env = getDaemonCliEnvironment();
|
|
@@ -12613,7 +12763,7 @@ function discoverCapabilities() {
|
|
|
12613
12763
|
return {
|
|
12614
12764
|
provider,
|
|
12615
12765
|
available: Boolean(executable),
|
|
12616
|
-
models: [],
|
|
12766
|
+
models: executable ? discoverProviderModels(provider, executable, env) : [],
|
|
12617
12767
|
lastCheckedAt: now
|
|
12618
12768
|
};
|
|
12619
12769
|
}),
|