@molecule/api-ai-tools 1.16.6 → 1.16.8
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/README.md +167 -5
- package/dist/backends/sandbox-file-operations.d.ts +11 -0
- package/dist/backends/sandbox-file-operations.d.ts.map +1 -0
- package/dist/backends/sandbox-file-operations.js +100 -0
- package/dist/backends/sandbox.d.ts +3 -3
- package/dist/backends/sandbox.d.ts.map +1 -1
- package/dist/backends/sandbox.js +6 -4
- package/dist/command-plan.d.ts +71 -0
- package/dist/command-plan.d.ts.map +1 -0
- package/dist/command-plan.js +116 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/suite-overlap.d.ts.map +1 -1
- package/dist/suite-overlap.js +2 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +101 -39
- package/dist/trace-artifacts.d.ts.map +1 -1
- package/dist/trace-artifacts.js +2 -1
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utilities.d.ts +4 -1
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js +14 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-11-
|
|
6
|
+
Generated: 2026-11-06T03:40:01.617Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-ai-tools
|
|
@@ -80,6 +80,36 @@ interface ForegroundBrowserProbe extends BrowserProbeLeak {
|
|
|
80
80
|
}
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
#### `CommandPlanStep`
|
|
84
|
+
|
|
85
|
+
One sequential command, with boundaries emitted by its launcher around execution.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
interface CommandPlanStep {
|
|
89
|
+
/** Launcher's stable step identity. */
|
|
90
|
+
id: string
|
|
91
|
+
/** The logical command actually executed, including launch rewrites. */
|
|
92
|
+
command: string
|
|
93
|
+
/** Printed on its own line immediately before this step runs. */
|
|
94
|
+
startMarker: string
|
|
95
|
+
/** Printed on its own line after this step settles. */
|
|
96
|
+
endMarker: string
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### `CommandPlan`
|
|
101
|
+
|
|
102
|
+
A wrapper's ordered commands; metadata describes execution, never proof or completion.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
interface CommandPlan {
|
|
106
|
+
/** Per-launch boundary identity, preventing ordinary suite output from matching a boundary. */
|
|
107
|
+
id: string
|
|
108
|
+
/** Steps execute in this order. */
|
|
109
|
+
steps: CommandPlanStep[]
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
83
113
|
#### `CommandSegment`
|
|
84
114
|
|
|
85
115
|
One statement or pipeline stage of a shell command: what it runs, and with what.
|
|
@@ -1188,6 +1218,30 @@ interface ExecutionBackend {
|
|
|
1188
1218
|
/** Write content to a file. Creates parent directories as needed. */
|
|
1189
1219
|
writeFile(path: string, content: string): Promise<void>
|
|
1190
1220
|
|
|
1221
|
+
/**
|
|
1222
|
+
* Optional single-call path check and bounded text read for write/edit tools.
|
|
1223
|
+
* `realPath` must be resolved before reading; never read outside `symlinkRoot`.
|
|
1224
|
+
* Null `content` means missing; omit it for a native read (large/unreadable text).
|
|
1225
|
+
* Returned text must match readFile's decoding and honor any host file-method wrappers.
|
|
1226
|
+
* Implementations must use this backend's `run` so host command wrappers still apply.
|
|
1227
|
+
*/
|
|
1228
|
+
readFileForUpdate?(
|
|
1229
|
+
path: string,
|
|
1230
|
+
symlinkRoot?: string,
|
|
1231
|
+
): Promise<{ realPath: string; content?: string | null }>
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* Optional write followed by the supplied parse command in one transport call.
|
|
1235
|
+
* Null means unsupported BEFORE a successful write; the caller uses writeFile/run.
|
|
1236
|
+
* Never retry a transport error after a write may have landed. After-write and
|
|
1237
|
+
* file-change hooks use the ordinary path so their ordering before parsing stays intact.
|
|
1238
|
+
*/
|
|
1239
|
+
writeFileAndCheck?(
|
|
1240
|
+
path: string,
|
|
1241
|
+
content: string,
|
|
1242
|
+
command: string,
|
|
1243
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number } | null>
|
|
1244
|
+
|
|
1191
1245
|
/** Delete a file. */
|
|
1192
1246
|
deleteFile(path: string): Promise<void>
|
|
1193
1247
|
|
|
@@ -1710,8 +1764,8 @@ function createLocalBackend(projectRoot: string): ExecutionBackend
|
|
|
1710
1764
|
|
|
1711
1765
|
#### `createSandboxBackend(sandbox, projectRoot)`
|
|
1712
1766
|
|
|
1713
|
-
Create an ExecutionBackend that delegates to
|
|
1714
|
-
The sandbox.exec method
|
|
1767
|
+
Create an ExecutionBackend that delegates to an isolated sandbox instance.
|
|
1768
|
+
The sandbox.exec method runs inside the provider's isolated environment.
|
|
1715
1769
|
|
|
1716
1770
|
```typescript
|
|
1717
1771
|
function createSandboxBackend(sandbox: SandboxLike, projectRoot?: string): ExecutionBackend
|
|
@@ -1774,6 +1828,94 @@ function browserProbeOverBudgetAdvice(probe: ForegroundBrowserProbe): string
|
|
|
1774
1828
|
|
|
1775
1829
|
**Returns:** The sentence the cut result carries.
|
|
1776
1830
|
|
|
1831
|
+
#### `createCommandPlan(steps)`
|
|
1832
|
+
|
|
1833
|
+
Give already-prepared logical commands unique log boundaries.
|
|
1834
|
+
|
|
1835
|
+
```typescript
|
|
1836
|
+
function createCommandPlan(steps: { id: string; command: string }[]): CommandPlan
|
|
1837
|
+
```
|
|
1838
|
+
|
|
1839
|
+
- `steps` — Commands in execution order.
|
|
1840
|
+
|
|
1841
|
+
**Returns:** Metadata for the wrapper and the launcher that executes its steps.
|
|
1842
|
+
|
|
1843
|
+
#### `commandWithPlan(command, plan)`
|
|
1844
|
+
|
|
1845
|
+
Preserve a wrapper's typed logical plan in its durable shell script, including across restarts.
|
|
1846
|
+
Shell comments keep this independent of the wrapper's executable, arguments and payload format.
|
|
1847
|
+
|
|
1848
|
+
```typescript
|
|
1849
|
+
function commandWithPlan(command: string, plan: CommandPlan): string
|
|
1850
|
+
```
|
|
1851
|
+
|
|
1852
|
+
- `command` — Executed wrapper.
|
|
1853
|
+
- `plan` — Commands the launcher will actually execute and delimit.
|
|
1854
|
+
|
|
1855
|
+
**Returns:** A shell command with a passive metadata header.
|
|
1856
|
+
|
|
1857
|
+
#### `commandPlan(command)`
|
|
1858
|
+
|
|
1859
|
+
Read the shared descriptor, never a launcher's private wrapper format.
|
|
1860
|
+
|
|
1861
|
+
```typescript
|
|
1862
|
+
function commandPlan(command: string): CommandPlan | null
|
|
1863
|
+
```
|
|
1864
|
+
|
|
1865
|
+
- `command` — Command or recovered task script.
|
|
1866
|
+
|
|
1867
|
+
**Returns:** A valid logical plan, or null for an ordinary command.
|
|
1868
|
+
|
|
1869
|
+
#### `logicalCommandText(command)`
|
|
1870
|
+
|
|
1871
|
+
Commands a wrapper will run, for static classification; live diagnostics use commandStepView.
|
|
1872
|
+
|
|
1873
|
+
```typescript
|
|
1874
|
+
function logicalCommandText(command: string): string
|
|
1875
|
+
```
|
|
1876
|
+
|
|
1877
|
+
- `command` — Executed command.
|
|
1878
|
+
|
|
1879
|
+
**Returns:** Logical commands in order, or the direct command unchanged.
|
|
1880
|
+
|
|
1881
|
+
#### `commandStepView(command, output)`
|
|
1882
|
+
|
|
1883
|
+
Select only the step that owns the latest log boundary. Completed steps cannot supply a live
|
|
1884
|
+
failure, target, retry policy, file selection or rerun. Before the first boundary and between
|
|
1885
|
+
steps the live command is unknown; no diagnostic is permitted.
|
|
1886
|
+
|
|
1887
|
+
```typescript
|
|
1888
|
+
function commandStepView(
|
|
1889
|
+
command: string,
|
|
1890
|
+
output: string,
|
|
1891
|
+
): {
|
|
1892
|
+
command: string
|
|
1893
|
+
output: string
|
|
1894
|
+
complete: boolean
|
|
1895
|
+
/** Unique execution step, including when adjacent steps run identical commands. */
|
|
1896
|
+
stepKey?: string
|
|
1897
|
+
}
|
|
1898
|
+
```
|
|
1899
|
+
|
|
1900
|
+
- `command` — Wrapper or direct command.
|
|
1901
|
+
- `output` — Whole log, or the boundary-preserving bounded read.
|
|
1902
|
+
|
|
1903
|
+
**Returns:** Active command and its output, plus whether the entire step's output is available.
|
|
1904
|
+
|
|
1905
|
+
#### `commandPlanLogRead(plan, limit)`
|
|
1906
|
+
|
|
1907
|
+
AWK program for a bounded read that retains the active boundary even after a long step and
|
|
1908
|
+
discards prior steps. A truncated step cannot establish a universal failure across its history.
|
|
1909
|
+
|
|
1910
|
+
```typescript
|
|
1911
|
+
function commandPlanLogRead(plan: CommandPlan, limit: number): string
|
|
1912
|
+
```
|
|
1913
|
+
|
|
1914
|
+
- `plan` — Logical plan whose boundaries the launcher emits.
|
|
1915
|
+
- `limit` — Maximum output characters retained for diagnosis.
|
|
1916
|
+
|
|
1917
|
+
**Returns:** An AWK program; callers shell-quote it like every other argument.
|
|
1918
|
+
|
|
1777
1919
|
#### `durationSeconds(word)`
|
|
1778
1920
|
|
|
1779
1921
|
The seconds a duration word stands for.
|
|
@@ -4432,7 +4574,7 @@ function failureBlocks(s: string): string[]
|
|
|
4432
4574
|
|
|
4433
4575
|
**Returns:** Each block, in order (empty when there are none).
|
|
4434
4576
|
|
|
4435
|
-
#### `runningOutputSliceCommand(log, own)`
|
|
4577
|
+
#### `runningOutputSliceCommand(log, own, command)`
|
|
4436
4578
|
|
|
4437
4579
|
The shell command whose stdout is the interesting part of a log that is still being written:
|
|
4438
4580
|
the failure lines so far (capped at {@link RUNNING_FAILURE_LINES}), then the end of the log.
|
|
@@ -4449,6 +4591,7 @@ function runningOutputSliceCommand(log: string, own?: string): string
|
|
|
4449
4591
|
|
|
4450
4592
|
- `log` — The task log path.
|
|
4451
4593
|
- `own` — A file the command redirects its own output to, if any.
|
|
4594
|
+
- `command` — Executed command, whose logical plan supplies live step boundaries if present.
|
|
4452
4595
|
|
|
4453
4596
|
**Returns:** The shell command, safe to hand to the execution backend as-is.
|
|
4454
4597
|
|
|
@@ -4464,7 +4607,7 @@ a duration — three bodies do not fit, and the repeat is invisible. This read i
|
|
|
4464
4607
|
anyone; it is parsed.
|
|
4465
4608
|
|
|
4466
4609
|
```typescript
|
|
4467
|
-
function runningCauseCommand(log: string, own?: string): string
|
|
4610
|
+
function runningCauseCommand(log: string, own?: string, command?: string): string
|
|
4468
4611
|
```
|
|
4469
4612
|
|
|
4470
4613
|
- `log` — The task log path.
|
|
@@ -5522,6 +5665,14 @@ Bytes of a running log a repeating-cause look reads back.
|
|
|
5522
5665
|
const REPEATING_CAUSE_TAIL_BYTES: 40000
|
|
5523
5666
|
```
|
|
5524
5667
|
|
|
5668
|
+
#### `COMMAND_PLAN_LOG_CHARS`
|
|
5669
|
+
|
|
5670
|
+
Whole-step history retained for wrapped plans; ordinary diagnostic logs fit inside this bound.
|
|
5671
|
+
|
|
5672
|
+
```typescript
|
|
5673
|
+
const COMMAND_PLAN_LOG_CHARS: 4000000
|
|
5674
|
+
```
|
|
5675
|
+
|
|
5525
5676
|
#### `RUNNING_LOG_READ_BYTES`
|
|
5526
5677
|
|
|
5527
5678
|
Bytes of a running log a diagnostic note reads back: one {@link REPEATING_CAUSE_TAIL_BYTES} window.
|
|
@@ -5654,6 +5805,12 @@ Peer dependencies:
|
|
|
5654
5805
|
|
|
5655
5806
|
- `@molecule/api-ai`
|
|
5656
5807
|
|
|
5808
|
+
- **Opaque command plans:** prepare each logical step with `streamingBackgroundCommand`,
|
|
5809
|
+
call `createCommandPlan`, and attach it to the executed wrapper with `commandWithPlan`.
|
|
5810
|
+
The launcher prints each step's `startMarker` and `endMarker` on their own lines around
|
|
5811
|
+
execution. `commandStepView` reads the active step for diagnostics; `logicalCommandText`
|
|
5812
|
+
exposes the planned commands for static classification. Preserve the descriptor when
|
|
5813
|
+
wrapping again. The metadata is advisory and never establishes a completed test result.
|
|
5657
5814
|
- **`yieldOnFirstFailureFor`** can yield one still-running deployed task's concrete diagnostic; callers opt out after a prior wait result or unknown history.
|
|
5658
5815
|
- **`wait_for_task` state probes report current progress without guessing log growth.**
|
|
5659
5816
|
A call shorter than one normal two-second poll omits both growth and no-growth
|
|
@@ -5723,6 +5880,11 @@ Peer dependencies:
|
|
|
5723
5880
|
to the model, and execute `catalog.loader` like any other tool. Loading only
|
|
5724
5881
|
exposes schemas, never grants permission or runs a tool. Persist its loaded
|
|
5725
5882
|
names with `onLoad` to keep them available across turns and compaction.
|
|
5883
|
+
- **Sandbox writes batch transport work.** The optional backend operations
|
|
5884
|
+
`readFileForUpdate` and `writeFileAndCheck` combine path safety with the old-text
|
|
5885
|
+
read, then the write with its parse check. Diff tracking and redaction checks
|
|
5886
|
+
stay in the tools. Format and change hooks retain their ordering before parsing;
|
|
5887
|
+
large files and backends without these operations use the native file APIs.
|
|
5726
5888
|
- **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
|
|
5727
5889
|
should not receive `write_file`/`exec_command`.
|
|
5728
5890
|
- Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Bounded file/command batching for sandbox transports; native file APIs remain the fallback. */
|
|
2
|
+
import type { ExecutionBackend } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Batch sandbox filesystem work through the backend's current command wrapper.
|
|
5
|
+
* Keeping `this.run` preserves a host's environment and module-resolution prelude.
|
|
6
|
+
*
|
|
7
|
+
* @param native - Original file delegates; host overrides must not be bypassed.
|
|
8
|
+
* @returns Optional backend operations that retain native fallbacks for large files.
|
|
9
|
+
*/
|
|
10
|
+
export declare function sandboxFileOperations(native: Pick<ExecutionBackend, 'readFile' | 'writeFile'>): Pick<ExecutionBackend, 'readFileForUpdate' | 'writeFileAndCheck'>;
|
|
11
|
+
//# sourceMappingURL=sandbox-file-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-file-operations.d.ts","sourceRoot":"","sources":["../../src/backends/sandbox-file-operations.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAElG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAenD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,WAAW,CAAC,GACvD,IAAI,CAAC,gBAAgB,EAAE,mBAAmB,GAAG,mBAAmB,CAAC,CA2FnE"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** Bounded file/command batching for sandbox transports; native file APIs remain the fallback. */
|
|
2
|
+
import { shellQuote } from '../utilities.js';
|
|
3
|
+
// envd may truncate command output; Docker also caps a shell argument at 128 KiB.
|
|
4
|
+
// Keep both envelopes small, and accept a read only after its complete JSON arrives.
|
|
5
|
+
const MAX_ENVELOPE = 24_000;
|
|
6
|
+
const WRITE_MARK = 'MOL_FILE_WRITTEN\n';
|
|
7
|
+
const NO_WRITE_MARK = 'MOL_FILE_NOT_WRITTEN\n';
|
|
8
|
+
// Native text APIs may strip an initial UTF-8 BOM (Response.text), whereas
|
|
9
|
+
// command envelopes preserve it. Keep that provider-specific decoding on the native path.
|
|
10
|
+
const READ_SCRIPT = `const fs=require('fs'),cp=require('child_process');const p=process.argv[1],root=process.argv[2];let realPath='';if(root){const r=cp.spawnSync('readlink',['-f',p],{encoding:'utf8'});realPath=(r.status===0?r.stdout:p).trim()}let out={realPath};if(!root||!realPath||realPath===root||realPath.startsWith(root==='/'?'/':root+'/')){try{if(fs.statSync(p).size<=24000){const content=fs.readFileSync(p,'utf8');if(content.charCodeAt(0)!==65279&&Buffer.byteLength(JSON.stringify({realPath,content}))<=24000)out={realPath,content}}}catch(e){if(e.code==='ENOENT'||e.code==='ENOTDIR')out.content=null;/* other errors use the native API */}}process.stdout.write(JSON.stringify(out))`;
|
|
11
|
+
const WRITE_SCRIPT = `const fs=require('fs'),cp=require('child_process'),path=require('path');const r=JSON.parse(Buffer.from(process.argv[1],'base64').toString('utf8'));try{fs.mkdirSync(path.dirname(r.path),{recursive:true});fs.writeFileSync(r.path,r.content,'utf8')}catch(e){process.stdout.write('MOL_FILE_NOT_WRITTEN\\n');process.exit(1)}process.stdout.write('MOL_FILE_WRITTEN\\n');const c=cp.spawnSync('sh',['-c',r.command],{cwd:path.dirname(r.path),encoding:'utf8',timeout:15000,maxBuffer:10*1024*1024});process.stdout.write(JSON.stringify({stdout:c.stdout||'',stderr:c.stderr||'',exitCode:c.status??1}))`;
|
|
12
|
+
/**
|
|
13
|
+
* Batch sandbox filesystem work through the backend's current command wrapper.
|
|
14
|
+
* Keeping `this.run` preserves a host's environment and module-resolution prelude.
|
|
15
|
+
*
|
|
16
|
+
* @param native - Original file delegates; host overrides must not be bypassed.
|
|
17
|
+
* @returns Optional backend operations that retain native fallbacks for large files.
|
|
18
|
+
*/
|
|
19
|
+
export function sandboxFileOperations(native) {
|
|
20
|
+
let supported = false;
|
|
21
|
+
const { readFile, writeFile } = native;
|
|
22
|
+
return {
|
|
23
|
+
async readFileForUpdate(path, symlinkRoot) {
|
|
24
|
+
const q = shellQuote(path);
|
|
25
|
+
// The native API may resolve relative paths against a different base than exec.
|
|
26
|
+
if (!path.startsWith('/') || this.readFile !== readFile) {
|
|
27
|
+
if (!symlinkRoot)
|
|
28
|
+
return { realPath: '' };
|
|
29
|
+
const checked = await this.run(`readlink -f ${q} 2>/dev/null || echo ${q}`, {
|
|
30
|
+
timeout: 5000,
|
|
31
|
+
});
|
|
32
|
+
return { realPath: checked.stdout.trim() };
|
|
33
|
+
}
|
|
34
|
+
const result = await this.run(`node -e ${shellQuote(READ_SCRIPT)} ${q} ${shellQuote(symlinkRoot ?? '')}`, {
|
|
35
|
+
timeout: 5000,
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
const body = JSON.parse(result.stdout);
|
|
39
|
+
if (body &&
|
|
40
|
+
typeof body === 'object' &&
|
|
41
|
+
'realPath' in body &&
|
|
42
|
+
typeof body.realPath === 'string') {
|
|
43
|
+
supported = true;
|
|
44
|
+
if ('content' in body && (typeof body.content === 'string' || body.content === null))
|
|
45
|
+
return { realPath: body.realPath, content: body.content };
|
|
46
|
+
return { realPath: body.realPath };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (_error) {
|
|
50
|
+
// Missing Node or truncated/malformed stdout cannot supply file contents.
|
|
51
|
+
}
|
|
52
|
+
supported = false;
|
|
53
|
+
if (!symlinkRoot)
|
|
54
|
+
return { realPath: '' };
|
|
55
|
+
// Native path verification still decides safety when batching is unavailable.
|
|
56
|
+
const checked = await this.run(`readlink -f ${q} 2>/dev/null || echo ${q}`, { timeout: 5000 });
|
|
57
|
+
return { realPath: checked.stdout.trim() };
|
|
58
|
+
},
|
|
59
|
+
async writeFileAndCheck(path, content, command) {
|
|
60
|
+
if (!path.startsWith('/') || !supported || this.writeFile !== writeFile)
|
|
61
|
+
return null;
|
|
62
|
+
const request = Buffer.from(JSON.stringify({ path, content, command })).toString('base64');
|
|
63
|
+
if (request.length > MAX_ENVELOPE)
|
|
64
|
+
return null;
|
|
65
|
+
const result = await this.run(`node -e ${shellQuote(WRITE_SCRIPT)} ${shellQuote(request)}`, {
|
|
66
|
+
// The target's parent may be created by this very write. The child parse
|
|
67
|
+
// command enters it only after mkdir/write have succeeded.
|
|
68
|
+
cwd: this.projectRoot,
|
|
69
|
+
timeout: 20_000,
|
|
70
|
+
});
|
|
71
|
+
if (!result.stdout.startsWith(WRITE_MARK)) {
|
|
72
|
+
// No successful write acknowledged (e.g. no Node or a filesystem error).
|
|
73
|
+
// The native API retains its provider-specific error and directory behavior.
|
|
74
|
+
if (result.stdout.startsWith(NO_WRITE_MARK) ||
|
|
75
|
+
(result.exitCode === 127 && /node.*not found/.test(result.stderr)))
|
|
76
|
+
return null;
|
|
77
|
+
throw new Error('Sandbox file write returned no completion acknowledgement; not retrying an uncertain write');
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const check = JSON.parse(result.stdout.slice(WRITE_MARK.length));
|
|
81
|
+
if (typeof check.stdout === 'string' &&
|
|
82
|
+
typeof check.stderr === 'string' &&
|
|
83
|
+
typeof check.exitCode === 'number')
|
|
84
|
+
return check;
|
|
85
|
+
}
|
|
86
|
+
catch (_error) {
|
|
87
|
+
// The write succeeded, but its check output was truncated. Recheck only;
|
|
88
|
+
// never replay an acknowledged write or a failed transport.
|
|
89
|
+
}
|
|
90
|
+
return this.run(command, {
|
|
91
|
+
cwd: path.slice(0, path.lastIndexOf('/')) || '/',
|
|
92
|
+
timeout: 15_000,
|
|
93
|
+
}).catch((_error) => {
|
|
94
|
+
// Like the ordinary post-write check, an unavailable parser adds no syntax note.
|
|
95
|
+
// The write was acknowledged above, so only the best-effort check failed here.
|
|
96
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -14,12 +14,12 @@ interface SandboxLike {
|
|
|
14
14
|
name: string;
|
|
15
15
|
type: 'file' | 'directory';
|
|
16
16
|
}>>;
|
|
17
|
-
/** Sandbox command execution — already
|
|
17
|
+
/** Sandbox command execution — already isolated by the provider. */
|
|
18
18
|
[key: string]: any;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Create an ExecutionBackend that delegates to
|
|
22
|
-
* The sandbox.exec method
|
|
21
|
+
* Create an ExecutionBackend that delegates to an isolated sandbox instance.
|
|
22
|
+
* The sandbox.exec method runs inside the provider's isolated environment.
|
|
23
23
|
*
|
|
24
24
|
* @param sandbox - A running Sandbox instance from `@molecule/api-code-sandbox`
|
|
25
25
|
* @param projectRoot - Root directory inside the sandbox (default: '/workspace')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/backends/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/backends/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAInD,sFAAsF;AACtF,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC,CAAA;IACnF,oEAAoE;IAEpE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EACpB,WAAW,SAAe,GACzB,gBAAgB,CAuDlB"}
|
package/dist/backends/sandbox.js
CHANGED
|
@@ -5,16 +5,17 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
import { shellQuote } from '../utilities.js';
|
|
8
|
+
import { sandboxFileOperations } from './sandbox-file-operations.js';
|
|
8
9
|
/**
|
|
9
|
-
* Create an ExecutionBackend that delegates to
|
|
10
|
-
* The sandbox.exec method
|
|
10
|
+
* Create an ExecutionBackend that delegates to an isolated sandbox instance.
|
|
11
|
+
* The sandbox.exec method runs inside the provider's isolated environment.
|
|
11
12
|
*
|
|
12
13
|
* @param sandbox - A running Sandbox instance from `@molecule/api-code-sandbox`
|
|
13
14
|
* @param projectRoot - Root directory inside the sandbox (default: '/workspace')
|
|
14
15
|
* @returns A backend that proxies all filesystem calls into the sandbox.
|
|
15
16
|
*/
|
|
16
17
|
export function createSandboxBackend(sandbox, projectRoot = '/workspace') {
|
|
17
|
-
|
|
18
|
+
const backend = {
|
|
18
19
|
projectRoot,
|
|
19
20
|
readFile(path) {
|
|
20
21
|
return sandbox.readFile(path);
|
|
@@ -54,9 +55,10 @@ export function createSandboxBackend(sandbox, projectRoot = '/workspace') {
|
|
|
54
55
|
const fullCommand = budgetSeconds
|
|
55
56
|
? `o=$(mktemp); e=$(mktemp); timeout -k 5 ${budgetSeconds} bash -c ${shellQuote(anchored)} > "$o" 2> "$e" < /dev/null; c=$?; cat "$o"; cat "$e" >&2; rm -f "$o" "$e"; exit $c`
|
|
56
57
|
: anchored;
|
|
57
|
-
// sandbox.exec is the Sandbox interface method — runs inside
|
|
58
|
+
// sandbox.exec is the Sandbox interface method — runs inside the provider's isolated environment
|
|
58
59
|
const result = await sandbox.exec(fullCommand, { timeout: opts?.timeout });
|
|
59
60
|
return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode };
|
|
60
61
|
},
|
|
61
62
|
};
|
|
63
|
+
return Object.assign(backend, typeof sandbox.exec === 'function' ? sandboxFileOperations(backend) : {});
|
|
62
64
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** One sequential command, with boundaries emitted by its launcher around execution. */
|
|
2
|
+
export interface CommandPlanStep {
|
|
3
|
+
/** Launcher's stable step identity. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** The logical command actually executed, including launch rewrites. */
|
|
6
|
+
command: string;
|
|
7
|
+
/** Printed on its own line immediately before this step runs. */
|
|
8
|
+
startMarker: string;
|
|
9
|
+
/** Printed on its own line after this step settles. */
|
|
10
|
+
endMarker: string;
|
|
11
|
+
}
|
|
12
|
+
/** A wrapper's ordered commands; metadata describes execution, never proof or completion. */
|
|
13
|
+
export interface CommandPlan {
|
|
14
|
+
/** Per-launch boundary identity, preventing ordinary suite output from matching a boundary. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Steps execute in this order. */
|
|
17
|
+
steps: CommandPlanStep[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Give already-prepared logical commands unique log boundaries.
|
|
21
|
+
* @param steps - Commands in execution order.
|
|
22
|
+
* @returns Metadata for the wrapper and the launcher that executes its steps.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createCommandPlan(steps: {
|
|
25
|
+
id: string;
|
|
26
|
+
command: string;
|
|
27
|
+
}[]): CommandPlan;
|
|
28
|
+
/**
|
|
29
|
+
* Preserve a wrapper's typed logical plan in its durable shell script, including across restarts.
|
|
30
|
+
* Shell comments keep this independent of the wrapper's executable, arguments and payload format.
|
|
31
|
+
* @param command - Executed wrapper.
|
|
32
|
+
* @param plan - Commands the launcher will actually execute and delimit.
|
|
33
|
+
* @returns A shell command with a passive metadata header.
|
|
34
|
+
*/
|
|
35
|
+
export declare function commandWithPlan(command: string, plan: CommandPlan): string;
|
|
36
|
+
/**
|
|
37
|
+
* Read the shared descriptor, never a launcher's private wrapper format.
|
|
38
|
+
* @param command - Command or recovered task script.
|
|
39
|
+
* @returns A valid logical plan, or null for an ordinary command.
|
|
40
|
+
*/
|
|
41
|
+
export declare function commandPlan(command: string): CommandPlan | null;
|
|
42
|
+
/**
|
|
43
|
+
* Commands a wrapper will run, for static classification; live diagnostics use commandStepView.
|
|
44
|
+
* @param command - Executed command.
|
|
45
|
+
* @returns Logical commands in order, or the direct command unchanged.
|
|
46
|
+
*/
|
|
47
|
+
export declare function logicalCommandText(command: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Select only the step that owns the latest log boundary. Completed steps cannot supply a live
|
|
50
|
+
* failure, target, retry policy, file selection or rerun. Before the first boundary and between
|
|
51
|
+
* steps the live command is unknown; no diagnostic is permitted.
|
|
52
|
+
* @param command - Wrapper or direct command.
|
|
53
|
+
* @param output - Whole log, or the boundary-preserving bounded read.
|
|
54
|
+
* @returns Active command and its output, plus whether the entire step's output is available.
|
|
55
|
+
*/
|
|
56
|
+
export declare function commandStepView(command: string, output: string): {
|
|
57
|
+
command: string;
|
|
58
|
+
output: string;
|
|
59
|
+
complete: boolean;
|
|
60
|
+
/** Unique execution step, including when adjacent steps run identical commands. */
|
|
61
|
+
stepKey?: string;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* AWK program for a bounded read that retains the active boundary even after a long step and
|
|
65
|
+
* discards prior steps. A truncated step cannot establish a universal failure across its history.
|
|
66
|
+
* @param plan - Logical plan whose boundaries the launcher emits.
|
|
67
|
+
* @param limit - Maximum output characters retained for diagnosis.
|
|
68
|
+
* @returns An AWK program; callers shell-quote it like every other argument.
|
|
69
|
+
*/
|
|
70
|
+
export declare function commandPlanLogRead(plan: CommandPlan, limit: number): string;
|
|
71
|
+
//# sourceMappingURL=command-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-plan.d.ts","sourceRoot":"","sources":["../src/command-plan.ts"],"names":[],"mappings":"AAIA,wFAAwF;AACxF,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAA;IACV,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAA;IACnB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,6FAA6F;AAC7F,MAAM,WAAW,WAAW;IAC1B,+FAA+F;IAC/F,EAAE,EAAE,MAAM,CAAA;IACV,mCAAmC;IACnC,KAAK,EAAE,eAAe,EAAE,CAAA;CACzB;AAKD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,WAAW,CAUvF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,CAE1E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CA4B/D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb;IACD,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAsBA;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ3E"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** Logical commands and ordered log boundaries for launchers that execute opaque wrappers. */
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { gunzipSync, gzipSync } from 'node:zlib';
|
|
4
|
+
const HEADER = '# mol-command-plan-v1 ';
|
|
5
|
+
const TRUNCATED = '__MOL_COMMAND_LOG_TRUNCATED__';
|
|
6
|
+
/**
|
|
7
|
+
* Give already-prepared logical commands unique log boundaries.
|
|
8
|
+
* @param steps - Commands in execution order.
|
|
9
|
+
* @returns Metadata for the wrapper and the launcher that executes its steps.
|
|
10
|
+
*/
|
|
11
|
+
export function createCommandPlan(steps) {
|
|
12
|
+
const id = randomUUID();
|
|
13
|
+
return {
|
|
14
|
+
id,
|
|
15
|
+
steps: steps.map((step, index) => ({
|
|
16
|
+
...step,
|
|
17
|
+
startMarker: `__MOL_COMMAND_STEP_${id}_${index}_START__`,
|
|
18
|
+
endMarker: `__MOL_COMMAND_STEP_${id}_${index}_END__`,
|
|
19
|
+
})),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Preserve a wrapper's typed logical plan in its durable shell script, including across restarts.
|
|
24
|
+
* Shell comments keep this independent of the wrapper's executable, arguments and payload format.
|
|
25
|
+
* @param command - Executed wrapper.
|
|
26
|
+
* @param plan - Commands the launcher will actually execute and delimit.
|
|
27
|
+
* @returns A shell command with a passive metadata header.
|
|
28
|
+
*/
|
|
29
|
+
export function commandWithPlan(command, plan) {
|
|
30
|
+
return `${HEADER}${gzipSync(JSON.stringify(plan)).toString('base64')}\n${command}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Read the shared descriptor, never a launcher's private wrapper format.
|
|
34
|
+
* @param command - Command or recovered task script.
|
|
35
|
+
* @returns A valid logical plan, or null for an ordinary command.
|
|
36
|
+
*/
|
|
37
|
+
export function commandPlan(command) {
|
|
38
|
+
const header = command.split('\n').find((line) => line.startsWith(HEADER));
|
|
39
|
+
if (!header || header.length > 1024 * 1024)
|
|
40
|
+
return null;
|
|
41
|
+
try {
|
|
42
|
+
const plan = JSON.parse(gunzipSync(Buffer.from(header.slice(HEADER.length), 'base64'), {
|
|
43
|
+
maxOutputLength: 1024 * 1024,
|
|
44
|
+
}).toString('utf8'));
|
|
45
|
+
if (!plan ||
|
|
46
|
+
!/^[a-f0-9-]{36}$/.test(plan.id) ||
|
|
47
|
+
!Array.isArray(plan.steps) ||
|
|
48
|
+
plan.steps.length === 0 ||
|
|
49
|
+
!plan.steps.every((step, index) => typeof step?.id === 'string' &&
|
|
50
|
+
typeof step.command === 'string' &&
|
|
51
|
+
step.startMarker === `__MOL_COMMAND_STEP_${plan.id}_${index}_START__` &&
|
|
52
|
+
step.endMarker === `__MOL_COMMAND_STEP_${plan.id}_${index}_END__`))
|
|
53
|
+
return null;
|
|
54
|
+
return plan;
|
|
55
|
+
}
|
|
56
|
+
catch (_error) {
|
|
57
|
+
// Metadata is advisory. An absent or malformed descriptor supplies no logical commands.
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Commands a wrapper will run, for static classification; live diagnostics use commandStepView.
|
|
63
|
+
* @param command - Executed command.
|
|
64
|
+
* @returns Logical commands in order, or the direct command unchanged.
|
|
65
|
+
*/
|
|
66
|
+
export function logicalCommandText(command) {
|
|
67
|
+
return (commandPlan(command)
|
|
68
|
+
?.steps.map((step) => step.command)
|
|
69
|
+
.join(';\n') ?? command);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Select only the step that owns the latest log boundary. Completed steps cannot supply a live
|
|
73
|
+
* failure, target, retry policy, file selection or rerun. Before the first boundary and between
|
|
74
|
+
* steps the live command is unknown; no diagnostic is permitted.
|
|
75
|
+
* @param command - Wrapper or direct command.
|
|
76
|
+
* @param output - Whole log, or the boundary-preserving bounded read.
|
|
77
|
+
* @returns Active command and its output, plus whether the entire step's output is available.
|
|
78
|
+
*/
|
|
79
|
+
export function commandStepView(command, output) {
|
|
80
|
+
const plan = commandPlan(command);
|
|
81
|
+
if (!plan)
|
|
82
|
+
return { command, output, complete: true };
|
|
83
|
+
let at = -1;
|
|
84
|
+
let selected;
|
|
85
|
+
let offset = 0;
|
|
86
|
+
for (const line of output.split('\n')) {
|
|
87
|
+
for (const step of plan.steps) {
|
|
88
|
+
if (line === step.startMarker || line === step.endMarker) {
|
|
89
|
+
at = offset + line.length + 1;
|
|
90
|
+
selected = line === step.startMarker ? step : undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
offset += line.length + 1;
|
|
94
|
+
}
|
|
95
|
+
const text = selected && at >= 0 ? output.slice(at) : '';
|
|
96
|
+
return {
|
|
97
|
+
stepKey: selected?.startMarker,
|
|
98
|
+
command: selected?.command ?? '',
|
|
99
|
+
output: text.replace(`${TRUNCATED}\n`, ''),
|
|
100
|
+
complete: !text.startsWith(TRUNCATED),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* AWK program for a bounded read that retains the active boundary even after a long step and
|
|
105
|
+
* discards prior steps. A truncated step cannot establish a universal failure across its history.
|
|
106
|
+
* @param plan - Logical plan whose boundaries the launcher emits.
|
|
107
|
+
* @param limit - Maximum output characters retained for diagnosis.
|
|
108
|
+
* @returns An AWK program; callers shell-quote it like every other argument.
|
|
109
|
+
*/
|
|
110
|
+
export function commandPlanLogRead(plan, limit) {
|
|
111
|
+
const markers = plan.steps.flatMap((step) => [step.startMarker, step.endMarker]);
|
|
112
|
+
return (`BEGIN { ${markers.map((marker) => `marks["${marker}"]=1`).join('; ')} }\n` +
|
|
113
|
+
'$0 in marks { marker=$0; text=""; cut=0; next }\n' +
|
|
114
|
+
`{ text=text $0 "\\n"; if(length(text)>${limit}) { text=substr(text,length(text)-${limit}+1); cut=1 } }\n` +
|
|
115
|
+
`END { if(marker!="") { print marker; if(cut) print "${TRUNCATED}"; printf "%s",text } }`);
|
|
116
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
* (identity, tool listing, project docs, discovered skills).
|
|
13
13
|
*
|
|
14
14
|
* @remarks
|
|
15
|
+
* - **Opaque command plans:** prepare each logical step with `streamingBackgroundCommand`,
|
|
16
|
+
* call `createCommandPlan`, and attach it to the executed wrapper with `commandWithPlan`.
|
|
17
|
+
* The launcher prints each step's `startMarker` and `endMarker` on their own lines around
|
|
18
|
+
* execution. `commandStepView` reads the active step for diagnostics; `logicalCommandText`
|
|
19
|
+
* exposes the planned commands for static classification. Preserve the descriptor when
|
|
20
|
+
* wrapping again. The metadata is advisory and never establishes a completed test result.
|
|
15
21
|
* - **`yieldOnFirstFailureFor`** can yield one still-running deployed task's concrete diagnostic; callers opt out after a prior wait result or unknown history.
|
|
16
22
|
* - **`wait_for_task` state probes report current progress without guessing log growth.**
|
|
17
23
|
* A call shorter than one normal two-second poll omits both growth and no-growth
|
|
@@ -81,6 +87,11 @@
|
|
|
81
87
|
* to the model, and execute `catalog.loader` like any other tool. Loading only
|
|
82
88
|
* exposes schemas, never grants permission or runs a tool. Persist its loaded
|
|
83
89
|
* names with `onLoad` to keep them available across turns and compaction.
|
|
90
|
+
* - **Sandbox writes batch transport work.** The optional backend operations
|
|
91
|
+
* `readFileForUpdate` and `writeFileAndCheck` combine path safety with the old-text
|
|
92
|
+
* read, then the write with its parse check. Diff tracking and redaction checks
|
|
93
|
+
* stay in the tools. Format and change hooks retain their ordering before parsing;
|
|
94
|
+
* large files and backends without these operations use the native file APIs.
|
|
84
95
|
* - **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
|
|
85
96
|
* should not receive `write_file`/`exec_command`.
|
|
86
97
|
* - Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
|
|
@@ -144,6 +155,7 @@ export * from './backends/local.js';
|
|
|
144
155
|
export * from './backends/sandbox.js';
|
|
145
156
|
export * from './browser-guard.js';
|
|
146
157
|
export * from './browser-probe.js';
|
|
158
|
+
export * from './command-plan.js';
|
|
147
159
|
export * from './command-position.js';
|
|
148
160
|
export * from './cut-run.js';
|
|
149
161
|
export * from './failure-kind.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwJG;AAEH,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA;AAC1B,cAAc,sBAAsB,CAAA;AACpC,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|