@opengoat/core 2026.2.18-2 → 2026.2.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/core/agents/application/agent.service.d.ts +2 -0
- package/dist/core/agents/application/agent.service.js +32 -9
- package/dist/core/agents/application/agent.service.js.map +1 -1
- package/dist/core/boards/application/board.service.d.ts +5 -1
- package/dist/core/boards/application/board.service.js +115 -29
- package/dist/core/boards/application/board.service.js.map +1 -1
- package/dist/core/boards/domain/board.d.ts +1 -2
- package/dist/core/opengoat/application/opengoat.service.d.ts +6 -1
- package/dist/core/opengoat/application/opengoat.service.helpers.d.ts +52 -0
- package/dist/core/opengoat/application/opengoat.service.helpers.js +129 -3
- package/dist/core/opengoat/application/opengoat.service.helpers.js.map +1 -1
- package/dist/core/opengoat/application/opengoat.service.js +229 -45
- package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
- package/dist/core/orchestration/application/orchestration.service.js +6 -1
- package/dist/core/orchestration/application/orchestration.service.js.map +1 -1
- package/dist/core/providers/application/provider.service.d.ts +3 -0
- package/dist/core/providers/application/provider.service.js +126 -0
- package/dist/core/providers/application/provider.service.js.map +1 -1
- package/dist/core/providers/cli-provider.d.ts +1 -0
- package/dist/core/providers/cli-provider.js +11 -8
- package/dist/core/providers/cli-provider.js.map +1 -1
- package/dist/core/providers/openclaw-gateway-rpc.js +70 -17
- package/dist/core/providers/openclaw-gateway-rpc.js.map +1 -1
- package/dist/core/providers/providers/codex/provider.d.ts +1 -0
- package/dist/core/providers/providers/codex/provider.js +24 -0
- package/dist/core/providers/providers/codex/provider.js.map +1 -1
- package/dist/core/providers/types.d.ts +1 -0
- package/dist/core/templates/assets/skills/og-board-manager/SKILL.md +3 -6
- package/package.json +1 -1
|
@@ -10,11 +10,12 @@ import { ProviderCommandNotFoundError, createDefaultProviderRegistry, } from "..
|
|
|
10
10
|
import { dirname, resolve as resolvePath } from "node:path";
|
|
11
11
|
import { SessionService, } from "../../sessions/index.js";
|
|
12
12
|
import { SkillService, } from "../../skills/index.js";
|
|
13
|
-
import { assertAgentExists, buildBlockedTaskMessage, buildInactiveAgentsMessage, buildNotificationSessionRef, buildPendingTaskMessage, buildReporteeStats, buildTodoTaskMessage, collectAllReportees, containsAgentNotFoundMessage, containsAlreadyExistsMessage, extractManagedSkillsDir, extractOpenClawAgents, isSpawnPermissionOrMissing, pathIsWithin, pathMatches, prepareOpenClawCommandEnv,
|
|
13
|
+
import { assertAgentExists, buildBlockedTaskMessage, buildDoingTaskMessage, buildInactiveAgentsMessage, buildNotificationSessionRef, buildPendingTaskMessage, buildReporteeStats, buildTopDownTaskDelegationMessage, buildTodoTaskMessage, collectAllReportees, containsAgentNotFoundMessage, containsAlreadyExistsMessage, extractManagedSkillsDir, extractOpenClawAgents, isSpawnPermissionOrMissing, pathIsWithin, pathMatches, prepareOpenClawCommandEnv, resolveInProgressTimeoutMinutes, resolveBottomUpTaskDelegationStrategy, resolveTopDownTaskDelegationStrategy, resolveMaxParallelFlows, toErrorMessage, } from "./opengoat.service.helpers.js";
|
|
14
14
|
const OPENCLAW_PROVIDER_ID = "openclaw";
|
|
15
15
|
const OPENCLAW_DEFAULT_AGENT_ID = "main";
|
|
16
16
|
const OPENCLAW_AGENT_SANDBOX_MODE = "off";
|
|
17
17
|
const OPENCLAW_AGENT_TOOLS_ALLOW_ALL_JSON = "[\"*\"]";
|
|
18
|
+
const OPENCLAW_AGENT_SKIP_BOOTSTRAP = true;
|
|
18
19
|
const OPENCLAW_OPENGOAT_PLUGIN_ID = "openclaw-plugin";
|
|
19
20
|
const OPENCLAW_OPENGOAT_PLUGIN_ROOT_ID = "opengoat-plugin";
|
|
20
21
|
const OPENCLAW_OPENGOAT_PLUGIN_LEGACY_PACK_ID = "openclaw-plugin-pack";
|
|
@@ -205,23 +206,31 @@ export class OpenGoatService {
|
|
|
205
206
|
warnings.push(`OpenClaw role skill assignment sync for "ceo" failed: ${toErrorMessage(error)}`);
|
|
206
207
|
}
|
|
207
208
|
let openClawAgentEntriesById;
|
|
209
|
+
let openClawInventoryAvailable = false;
|
|
208
210
|
try {
|
|
209
211
|
openClawAgentEntriesById = new Map((await this.listOpenClawAgents(paths)).map((entry) => [entry.id, entry]));
|
|
212
|
+
openClawInventoryAvailable = true;
|
|
210
213
|
}
|
|
211
214
|
catch (error) {
|
|
212
215
|
warnings.push(`OpenClaw startup inventory check failed: ${toErrorMessage(error)}`);
|
|
213
216
|
}
|
|
214
217
|
try {
|
|
215
218
|
localAgents = await this.agentService.listAgents(paths);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
219
|
+
if (!openClawInventoryAvailable) {
|
|
220
|
+
warnings.push("OpenClaw startup registration sync skipped because agent inventory is unavailable.");
|
|
221
|
+
ceoSynced = localAgents.some((agent) => agent.id === DEFAULT_AGENT_ID);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
for (const agent of localAgents) {
|
|
225
|
+
const sync = await this.syncOpenClawAgentRegistration(paths, {
|
|
226
|
+
descriptor: agent,
|
|
227
|
+
existingEntry: openClawAgentEntriesById?.get(agent.id),
|
|
228
|
+
});
|
|
229
|
+
warnings.push(...sync.warnings);
|
|
230
|
+
if (agent.id === DEFAULT_AGENT_ID) {
|
|
231
|
+
ceoSynced = sync.synced;
|
|
232
|
+
ceoSyncCode = sync.code;
|
|
233
|
+
}
|
|
225
234
|
}
|
|
226
235
|
}
|
|
227
236
|
}
|
|
@@ -308,24 +317,23 @@ export class OpenGoatService {
|
|
|
308
317
|
throw new Error(`OpenClaw agent location sync failed for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
309
318
|
}
|
|
310
319
|
await this.syncOpenClawAgentExecutionPolicies(paths, [created.agent.id]);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (!created.alreadyExisted) {
|
|
320
|
+
if (!created.alreadyExisted) {
|
|
321
|
+
try {
|
|
322
|
+
const workspaceBootstrap = await this.agentService.ensureAgentWorkspaceBootstrap(paths, {
|
|
323
|
+
agentId: created.agent.id,
|
|
324
|
+
displayName: created.agent.displayName,
|
|
325
|
+
role: options.role?.trim() ?? "",
|
|
326
|
+
}, {
|
|
327
|
+
syncBootstrapMarkdown: false,
|
|
328
|
+
});
|
|
329
|
+
created.createdPaths.push(...workspaceBootstrap.createdPaths);
|
|
330
|
+
created.skippedPaths.push(...workspaceBootstrap.skippedPaths);
|
|
331
|
+
created.skippedPaths.push(...workspaceBootstrap.removedPaths);
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
326
334
|
await this.agentService.removeAgent(paths, created.agent.id);
|
|
335
|
+
throw new Error(`Failed to update workspace bootstrap for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
327
336
|
}
|
|
328
|
-
throw new Error(`Failed to update workspace bootstrap for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
329
337
|
}
|
|
330
338
|
return {
|
|
331
339
|
...created,
|
|
@@ -555,18 +563,23 @@ export class OpenGoatService {
|
|
|
555
563
|
const paths = this.pathsProvider.getPaths();
|
|
556
564
|
const ranAt = this.resolveNowIso();
|
|
557
565
|
const manifests = await this.agentManifestService.listManifests(paths);
|
|
558
|
-
const
|
|
559
|
-
const
|
|
560
|
-
const
|
|
566
|
+
const inProgressMinutes = resolveInProgressTimeoutMinutes(options.inProgressMinutes);
|
|
567
|
+
const topDownStrategy = resolveTopDownTaskDelegationStrategy(options);
|
|
568
|
+
const bottomUpStrategy = resolveBottomUpTaskDelegationStrategy(options);
|
|
561
569
|
const maxParallelFlows = resolveMaxParallelFlows(options.maxParallelFlows);
|
|
562
|
-
const inactiveCandidates =
|
|
563
|
-
? await this.collectInactiveAgents(paths, manifests, inactiveMinutes, notificationTarget)
|
|
570
|
+
const inactiveCandidates = bottomUpStrategy.enabled
|
|
571
|
+
? await this.collectInactiveAgents(paths, manifests, bottomUpStrategy.inactiveMinutes, bottomUpStrategy.notificationTarget)
|
|
564
572
|
: [];
|
|
565
573
|
const tasks = await this.boardService.listTasks(paths, { limit: 10_000 });
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
574
|
+
const topDownDispatches = topDownStrategy.enabled
|
|
575
|
+
? await this.dispatchTopDownTaskDelegationAutomations(paths, tasks, manifests, topDownStrategy.openTasksThreshold, ranAt, maxParallelFlows)
|
|
576
|
+
: [];
|
|
577
|
+
const pendingTaskIds = new Set(await this.boardService.listPendingTaskIdsOlderThan(paths, bottomUpStrategy.inactiveMinutes));
|
|
578
|
+
const doingTaskIds = new Set(await this.boardService.listDoingTaskIdsOlderThan(paths, inProgressMinutes));
|
|
579
|
+
const taskStatusDispatch = await this.dispatchTaskStatusAutomations(paths, tasks, manifests, doingTaskIds, pendingTaskIds, inProgressMinutes, bottomUpStrategy.inactiveMinutes, ranAt, maxParallelFlows);
|
|
580
|
+
const inactiveDispatches = await this.dispatchInactiveAgentAutomations(paths, inactiveCandidates, bottomUpStrategy.inactiveMinutes, ranAt, maxParallelFlows);
|
|
569
581
|
const dispatches = [
|
|
582
|
+
...topDownDispatches,
|
|
570
583
|
...taskStatusDispatch.dispatches,
|
|
571
584
|
...inactiveDispatches,
|
|
572
585
|
];
|
|
@@ -575,6 +588,7 @@ export class OpenGoatService {
|
|
|
575
588
|
ranAt,
|
|
576
589
|
scannedTasks: tasks.length,
|
|
577
590
|
todoTasks: taskStatusDispatch.todoTasks,
|
|
591
|
+
doingTasks: taskStatusDispatch.doingTasks,
|
|
578
592
|
blockedTasks: taskStatusDispatch.blockedTasks,
|
|
579
593
|
inactiveAgents: inactiveCandidates.length,
|
|
580
594
|
sent: dispatches.length - failed,
|
|
@@ -582,10 +596,67 @@ export class OpenGoatService {
|
|
|
582
596
|
dispatches,
|
|
583
597
|
};
|
|
584
598
|
}
|
|
585
|
-
async
|
|
599
|
+
async dispatchTopDownTaskDelegationAutomations(paths, tasks, manifests, openTasksThreshold, notificationTimestamp, maxParallelFlows = 1) {
|
|
600
|
+
const openTasks = tasks
|
|
601
|
+
.filter((task) => task.status.trim().toLowerCase() !== "done")
|
|
602
|
+
.sort((left, right) => {
|
|
603
|
+
const leftTimestamp = Date.parse(left.updatedAt);
|
|
604
|
+
const rightTimestamp = Date.parse(right.updatedAt);
|
|
605
|
+
if (Number.isFinite(leftTimestamp) && Number.isFinite(rightTimestamp)) {
|
|
606
|
+
return rightTimestamp - leftTimestamp;
|
|
607
|
+
}
|
|
608
|
+
if (Number.isFinite(rightTimestamp)) {
|
|
609
|
+
return 1;
|
|
610
|
+
}
|
|
611
|
+
if (Number.isFinite(leftTimestamp)) {
|
|
612
|
+
return -1;
|
|
613
|
+
}
|
|
614
|
+
return right.taskId.localeCompare(left.taskId);
|
|
615
|
+
});
|
|
616
|
+
if (openTasks.length > openTasksThreshold) {
|
|
617
|
+
return [];
|
|
618
|
+
}
|
|
619
|
+
const managerAgents = manifests.filter((manifest) => manifest.metadata.type === "manager").length;
|
|
620
|
+
const ceoDirectReportees = manifests.filter((manifest) => normalizeAgentId(manifest.metadata.reportsTo ?? "") === DEFAULT_AGENT_ID).length;
|
|
621
|
+
const sessionRef = buildNotificationSessionRef(DEFAULT_AGENT_ID);
|
|
622
|
+
const message = buildTopDownTaskDelegationMessage({
|
|
623
|
+
openTasksThreshold,
|
|
624
|
+
openTasksCount: openTasks.length,
|
|
625
|
+
totalAgents: manifests.length,
|
|
626
|
+
managerAgents,
|
|
627
|
+
ceoDirectReportees,
|
|
628
|
+
openTasks: openTasks.map((task) => ({
|
|
629
|
+
taskId: task.taskId,
|
|
630
|
+
title: task.title,
|
|
631
|
+
status: task.status,
|
|
632
|
+
assignedTo: task.assignedTo,
|
|
633
|
+
})),
|
|
634
|
+
notificationTimestamp,
|
|
635
|
+
});
|
|
636
|
+
const requests = [
|
|
637
|
+
{
|
|
638
|
+
targetAgentId: DEFAULT_AGENT_ID,
|
|
639
|
+
sessionRef,
|
|
640
|
+
message,
|
|
641
|
+
},
|
|
642
|
+
];
|
|
643
|
+
return runWithConcurrencyByKey(requests, maxParallelFlows, (request) => request.targetAgentId, async (request) => {
|
|
644
|
+
const result = await this.dispatchAutomationMessage(paths, request.targetAgentId, request.sessionRef, request.message);
|
|
645
|
+
return {
|
|
646
|
+
kind: "topdown",
|
|
647
|
+
targetAgentId: request.targetAgentId,
|
|
648
|
+
sessionRef: request.sessionRef,
|
|
649
|
+
message: request.message,
|
|
650
|
+
ok: result.ok,
|
|
651
|
+
error: result.error,
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
async dispatchTaskStatusAutomations(paths, tasks, manifests, doingTaskIds, pendingTaskIds, doingMinutes, pendingMinutes, notificationTimestamp, maxParallelFlows) {
|
|
586
656
|
const manifestsById = new Map(manifests.map((manifest) => [manifest.agentId, manifest]));
|
|
587
657
|
const requests = [];
|
|
588
658
|
let todoTasks = 0;
|
|
659
|
+
let doingTasks = 0;
|
|
589
660
|
let pendingTasks = 0;
|
|
590
661
|
let blockedTasks = 0;
|
|
591
662
|
for (const task of tasks) {
|
|
@@ -606,6 +677,27 @@ export class OpenGoatService {
|
|
|
606
677
|
});
|
|
607
678
|
continue;
|
|
608
679
|
}
|
|
680
|
+
if (task.status === "doing") {
|
|
681
|
+
if (!doingTaskIds.has(task.taskId)) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
doingTasks += 1;
|
|
685
|
+
const targetAgentId = task.assignedTo;
|
|
686
|
+
const sessionRef = buildNotificationSessionRef(targetAgentId);
|
|
687
|
+
const message = buildDoingTaskMessage({
|
|
688
|
+
task,
|
|
689
|
+
doingMinutes,
|
|
690
|
+
notificationTimestamp,
|
|
691
|
+
});
|
|
692
|
+
requests.push({
|
|
693
|
+
kind: "doing",
|
|
694
|
+
targetAgentId,
|
|
695
|
+
sessionRef,
|
|
696
|
+
taskId: task.taskId,
|
|
697
|
+
message,
|
|
698
|
+
});
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
609
701
|
if (task.status === "pending") {
|
|
610
702
|
if (!pendingTaskIds.has(task.taskId)) {
|
|
611
703
|
continue;
|
|
@@ -658,9 +750,17 @@ export class OpenGoatService {
|
|
|
658
750
|
error: result.error,
|
|
659
751
|
};
|
|
660
752
|
});
|
|
753
|
+
const notifiedDoingTaskIds = dedupeStrings(dispatches
|
|
754
|
+
.filter((dispatch) => dispatch.kind === "doing" && dispatch.ok)
|
|
755
|
+
.map((dispatch) => dispatch.taskId)
|
|
756
|
+
.filter((taskId) => typeof taskId === "string"));
|
|
757
|
+
await Promise.all(notifiedDoingTaskIds.map(async (taskId) => {
|
|
758
|
+
await this.boardService.resetTaskStatusTimeout(paths, taskId, "doing");
|
|
759
|
+
}));
|
|
661
760
|
return {
|
|
662
761
|
dispatches,
|
|
663
762
|
todoTasks,
|
|
763
|
+
doingTasks,
|
|
664
764
|
pendingTasks,
|
|
665
765
|
blockedTasks,
|
|
666
766
|
};
|
|
@@ -795,9 +895,9 @@ export class OpenGoatService {
|
|
|
795
895
|
getPaths() {
|
|
796
896
|
return this.pathsProvider.getPaths();
|
|
797
897
|
}
|
|
798
|
-
async dispatchAutomationMessage(
|
|
898
|
+
async dispatchAutomationMessage(_paths, agentId, sessionRef, message, options = {}) {
|
|
799
899
|
try {
|
|
800
|
-
const result = await this.
|
|
900
|
+
const result = await this.runAgent(agentId, {
|
|
801
901
|
message,
|
|
802
902
|
sessionRef,
|
|
803
903
|
disableSession: options.disableSession ?? false,
|
|
@@ -1162,6 +1262,12 @@ export class OpenGoatService {
|
|
|
1162
1262
|
warnings.push(`OpenClaw tools policy sync failed for "${agentId}" (code ${toolsSet.code}). ${toolsSet.stderr.trim() || toolsSet.stdout.trim() || ""}`.trim());
|
|
1163
1263
|
}
|
|
1164
1264
|
}
|
|
1265
|
+
if (readAgentSkipBootstrap(entry) !== OPENCLAW_AGENT_SKIP_BOOTSTRAP) {
|
|
1266
|
+
const bootstrapSet = await this.runOpenClaw(["config", "set", `agents.list[${index}].skipBootstrap`, "true"], { env });
|
|
1267
|
+
if (bootstrapSet.code !== 0) {
|
|
1268
|
+
warnings.push(`OpenClaw bootstrap policy sync failed for "${agentId}" (code ${bootstrapSet.code}). ${bootstrapSet.stderr.trim() || bootstrapSet.stdout.trim() || ""}`.trim());
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1165
1271
|
}
|
|
1166
1272
|
return warnings;
|
|
1167
1273
|
}
|
|
@@ -1376,6 +1482,22 @@ function hasAgentToolsAllowAll(entry) {
|
|
|
1376
1482
|
}
|
|
1377
1483
|
return allow.some((value) => typeof value === "string" && value.trim() === "*");
|
|
1378
1484
|
}
|
|
1485
|
+
function readAgentSkipBootstrap(entry) {
|
|
1486
|
+
const value = entry.skipBootstrap;
|
|
1487
|
+
if (typeof value === "boolean") {
|
|
1488
|
+
return value;
|
|
1489
|
+
}
|
|
1490
|
+
if (typeof value === "string") {
|
|
1491
|
+
const normalized = value.trim().toLowerCase();
|
|
1492
|
+
if (normalized === "true") {
|
|
1493
|
+
return true;
|
|
1494
|
+
}
|
|
1495
|
+
if (normalized === "false") {
|
|
1496
|
+
return false;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
return undefined;
|
|
1500
|
+
}
|
|
1379
1501
|
function readStringArray(value) {
|
|
1380
1502
|
if (!Array.isArray(value)) {
|
|
1381
1503
|
return [];
|
|
@@ -1431,11 +1553,15 @@ function parseLooseJson(raw) {
|
|
|
1431
1553
|
if (!trimmed) {
|
|
1432
1554
|
return undefined;
|
|
1433
1555
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1556
|
+
const exact = tryParseJson(trimmed);
|
|
1557
|
+
if (exact !== undefined) {
|
|
1558
|
+
return exact;
|
|
1436
1559
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1560
|
+
for (const line of trimmed.split(/\r?\n/)) {
|
|
1561
|
+
const parsedLine = tryParseJson(line.trim());
|
|
1562
|
+
if (parsedLine !== undefined) {
|
|
1563
|
+
return parsedLine;
|
|
1564
|
+
}
|
|
1439
1565
|
}
|
|
1440
1566
|
const starts = dedupeNumbers([
|
|
1441
1567
|
trimmed.indexOf("{"),
|
|
@@ -1448,11 +1574,69 @@ function parseLooseJson(raw) {
|
|
|
1448
1574
|
if (!candidate) {
|
|
1449
1575
|
continue;
|
|
1450
1576
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1577
|
+
const parsedCandidate = tryParseJson(candidate);
|
|
1578
|
+
if (parsedCandidate !== undefined) {
|
|
1579
|
+
return parsedCandidate;
|
|
1453
1580
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1581
|
+
const balancedCandidate = extractBalancedJsonCandidate(trimmed, startIndex);
|
|
1582
|
+
if (!balancedCandidate) {
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
const parsedBalancedCandidate = tryParseJson(balancedCandidate);
|
|
1586
|
+
if (parsedBalancedCandidate !== undefined) {
|
|
1587
|
+
return parsedBalancedCandidate;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return undefined;
|
|
1591
|
+
}
|
|
1592
|
+
function tryParseJson(raw) {
|
|
1593
|
+
if (!raw) {
|
|
1594
|
+
return undefined;
|
|
1595
|
+
}
|
|
1596
|
+
try {
|
|
1597
|
+
return JSON.parse(raw);
|
|
1598
|
+
}
|
|
1599
|
+
catch {
|
|
1600
|
+
return undefined;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
function extractBalancedJsonCandidate(raw, startIndex) {
|
|
1604
|
+
const opening = raw[startIndex];
|
|
1605
|
+
if (opening !== "{" && opening !== "[") {
|
|
1606
|
+
return undefined;
|
|
1607
|
+
}
|
|
1608
|
+
const closing = opening === "{" ? "}" : "]";
|
|
1609
|
+
let depth = 0;
|
|
1610
|
+
let inString = false;
|
|
1611
|
+
let escaping = false;
|
|
1612
|
+
for (let index = startIndex; index < raw.length; index += 1) {
|
|
1613
|
+
const char = raw[index];
|
|
1614
|
+
if (inString) {
|
|
1615
|
+
if (escaping) {
|
|
1616
|
+
escaping = false;
|
|
1617
|
+
}
|
|
1618
|
+
else if (char === "\\") {
|
|
1619
|
+
escaping = true;
|
|
1620
|
+
}
|
|
1621
|
+
else if (char === "\"") {
|
|
1622
|
+
inString = false;
|
|
1623
|
+
}
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
if (char === "\"") {
|
|
1627
|
+
inString = true;
|
|
1628
|
+
continue;
|
|
1629
|
+
}
|
|
1630
|
+
if (char === opening) {
|
|
1631
|
+
depth += 1;
|
|
1632
|
+
continue;
|
|
1633
|
+
}
|
|
1634
|
+
if (char !== closing) {
|
|
1635
|
+
continue;
|
|
1636
|
+
}
|
|
1637
|
+
depth -= 1;
|
|
1638
|
+
if (depth === 0) {
|
|
1639
|
+
return raw.slice(startIndex, index + 1).trim();
|
|
1456
1640
|
}
|
|
1457
1641
|
}
|
|
1458
1642
|
return undefined;
|