@molecule/api-ai-tools 1.11.0 → 1.12.0
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 +166 -4
- package/dist/command-position.d.ts +37 -0
- package/dist/command-position.d.ts.map +1 -1
- package/dist/command-position.js +164 -5
- package/dist/cut-run.d.ts.map +1 -1
- package/dist/cut-run.js +10 -6
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +8 -0
- package/dist/server-command.d.ts +9 -3
- package/dist/server-command.d.ts.map +1 -1
- package/dist/server-command.js +39 -4
- package/dist/tool-catalog.d.ts +32 -0
- package/dist/tool-catalog.d.ts.map +1 -0
- package/dist/tool-catalog.js +76 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +44 -4
- package/dist/utilities.d.ts +46 -0
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js +200 -29
- 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-10-
|
|
6
|
+
Generated: 2026-10-21T20:10:49.315Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-ai-tools
|
|
@@ -105,6 +105,28 @@ interface CommandSegment {
|
|
|
105
105
|
}
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
#### `ExecutedCommand`
|
|
109
|
+
|
|
110
|
+
One command a shell command actually executes, wherever the shell runs it.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
interface ExecutedCommand {
|
|
114
|
+
/**
|
|
115
|
+
* The word in command position, its directory removed (`/usr/bin/printenv` → `printenv`) — or
|
|
116
|
+
* the launcher itself when it runs alone and nothing follows it (`x | env` → `env`).
|
|
117
|
+
*/
|
|
118
|
+
program: string
|
|
119
|
+
/**
|
|
120
|
+
* Its arguments, as written with quotes kept — the statement's own words AFTER the program,
|
|
121
|
+
* including an input redirect's path (`< /proc/self/environ`), so a reader of secret files sees
|
|
122
|
+
* the file it reads.
|
|
123
|
+
*/
|
|
124
|
+
args: readonly string[]
|
|
125
|
+
/** The program and its arguments as one line, what a pattern anchored at the program matches. */
|
|
126
|
+
text: string
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
108
130
|
#### `LocatedCommandSegment`
|
|
109
131
|
|
|
110
132
|
One statement of a shell command, with where it sits and the variables it sets for itself.
|
|
@@ -422,6 +444,35 @@ interface DiagnosisRunContext {
|
|
|
422
444
|
}
|
|
423
445
|
```
|
|
424
446
|
|
|
447
|
+
#### `DeferredToolCatalogOptions`
|
|
448
|
+
|
|
449
|
+
Options for exposing a small tool set while retaining access to other allowed tools.
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
interface DeferredToolCatalogOptions {
|
|
453
|
+
/** The caller's current permission/mode-filtered tools. Discovery never grants access. */
|
|
454
|
+
available: () => readonly AITool[]
|
|
455
|
+
/** Tools that should be offered without a discovery call. */
|
|
456
|
+
initialNames: ReadonlySet<string>
|
|
457
|
+
/** Previously loaded names, in load order; useful across turns and compaction. */
|
|
458
|
+
loadedNames?: readonly string[]
|
|
459
|
+
/** Persist names after a successful load. No tool content is passed to this callback. */
|
|
460
|
+
onLoad?: (names: string[]) => void
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
#### `DeferredToolCatalog`
|
|
465
|
+
|
|
466
|
+
A provider-independent deferred catalog. The caller still executes and authorizes tools.
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
interface DeferredToolCatalog {
|
|
470
|
+
loader: AITool
|
|
471
|
+
/** Initial tools, loader, then requested tools in stable load order. */
|
|
472
|
+
select: () => AITool[]
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
425
476
|
#### `InstalledPackageFacts`
|
|
426
477
|
|
|
427
478
|
What the filesystem says about a write target under `node_modules` — the half
|
|
@@ -1670,6 +1721,32 @@ function commandSegments(command: string): CommandSegment[]
|
|
|
1670
1721
|
|
|
1671
1722
|
**Returns:** One entry per statement or pipeline stage that runs something, in order.
|
|
1672
1723
|
|
|
1724
|
+
#### `executedCommands(command)`
|
|
1725
|
+
|
|
1726
|
+
Every command a shell command actually executes, at any depth — the statements themselves, the
|
|
1727
|
+
body of a `sh -c '<command>'`, and the body of every command substitution (`$(…)`, backticks).
|
|
1728
|
+
|
|
1729
|
+
This is the reading a policy that asks "does this command run X" needs, and it is deliberately
|
|
1730
|
+
not a text match. The command-position parser already knows what runs and what is only quoted
|
|
1731
|
+
data ({@link commandSegments}), so a pattern never reads a `|` inside a quoted grep alternation
|
|
1732
|
+
as a pipeline: `grep -E "USER CALLS|ENV|BUTTON" app.log` prints log lines, and the `ENV` in
|
|
1733
|
+
its pattern started nothing (X0 xr-molecule-flash-m331 blocked exactly that call as an
|
|
1734
|
+
environment dump). What the shell DOES run stays visible through the same walk: a bare
|
|
1735
|
+
launcher (`ls | env`), a shell string (`bash -c 'env'`), a substitution
|
|
1736
|
+
(`echo "$(printenv)"`) and a nested one (`sh -c 'x; env'`) are all commands here.
|
|
1737
|
+
|
|
1738
|
+
`commandSegments` answers what a pipeline stage runs for a caller matching a runner; this
|
|
1739
|
+
answers with the launcher left standing when it runs alone, since that is what the shell
|
|
1740
|
+
executes then.
|
|
1741
|
+
|
|
1742
|
+
```typescript
|
|
1743
|
+
function executedCommands(command: string): ExecutedCommand[]
|
|
1744
|
+
```
|
|
1745
|
+
|
|
1746
|
+
- `command` — The shell command.
|
|
1747
|
+
|
|
1748
|
+
**Returns:** Each command the shell executes, in the order the shell reaches them.
|
|
1749
|
+
|
|
1673
1750
|
#### `locatedCommandSegments(command)`
|
|
1674
1751
|
|
|
1675
1752
|
Every statement of a command, with its own assignments and where it sits — assignment-only
|
|
@@ -2183,7 +2260,8 @@ function pipelineExitCodeNote(command: string, exitCode: number, output: string)
|
|
|
2183
2260
|
Whether a command, read from its TEXT alone, starts a server that stays up in the foreground.
|
|
2184
2261
|
|
|
2185
2262
|
The over-budget reader's shape: at that point the command has already run, and only its text is
|
|
2186
|
-
left to say whether "run a smaller unit" was ever the right advice.
|
|
2263
|
+
left to say whether "run a smaller unit" was ever the right advice. Inline/stdin programs
|
|
2264
|
+
remain unclassified and use the normal bounded command runner.
|
|
2187
2265
|
|
|
2188
2266
|
```typescript
|
|
2189
2267
|
function startsServerProgram(command: string): boolean
|
|
@@ -2196,7 +2274,9 @@ function startsServerProgram(command: string): boolean
|
|
|
2196
2274
|
#### `foregroundServerCommand(command, readScript)`
|
|
2197
2275
|
|
|
2198
2276
|
A FOREGROUND command that starts a server, including one that only names a script whose SOURCE
|
|
2199
|
-
imports the app's server and calls its `create()`/`listen()`.
|
|
2277
|
+
imports the app's server and calls its `create()`/`listen()`. Inline/stdin programs
|
|
2278
|
+
(`node -e …`, `python3 -c …`) use normal bounded execution: interpreting arbitrary
|
|
2279
|
+
program text is outside this filename/script preflight's contract.
|
|
2200
2280
|
|
|
2201
2281
|
The script read is best-effort: a path the backend will not answer for is a command this reading
|
|
2202
2282
|
cannot classify, never a refusal. A backgrounded launch, a test runner and a test file are all
|
|
@@ -2491,6 +2571,24 @@ function buildAgentPrompt(ctx: PromptContext): string
|
|
|
2491
2571
|
|
|
2492
2572
|
**Returns:** Fully assembled system prompt text for the coding agent.
|
|
2493
2573
|
|
|
2574
|
+
#### `createDeferredToolCatalog(options)`
|
|
2575
|
+
|
|
2576
|
+
Offer common tools and let the model load other schemas by exact name.
|
|
2577
|
+
|
|
2578
|
+
This is ordinary allowlist selection, not semantic routing or authorization.
|
|
2579
|
+
Pass tools already filtered by the current mode and permissions. Loading never
|
|
2580
|
+
executes a tool; the caller must keep its normal execution-time guards. Loaded
|
|
2581
|
+
schemas append in request order and stay available, avoiding an LRU that changes
|
|
2582
|
+
the schema prefix on every request. Only names need persistence across turns.
|
|
2583
|
+
|
|
2584
|
+
```typescript
|
|
2585
|
+
function createDeferredToolCatalog(options: DeferredToolCatalogOptions): DeferredToolCatalog
|
|
2586
|
+
```
|
|
2587
|
+
|
|
2588
|
+
- `options` — Allowed tools, initial selection and optional durable load state.
|
|
2589
|
+
|
|
2590
|
+
**Returns:** A loader tool and the current provider-facing selection.
|
|
2591
|
+
|
|
2494
2592
|
#### `taskStopCommand(backend, taskId)`
|
|
2495
2593
|
|
|
2496
2594
|
The command that stops a running background task, read from the sandbox's own pid files.
|
|
@@ -2948,6 +3046,24 @@ function redactSecretsInCode(s: string): string
|
|
|
2948
3046
|
|
|
2949
3047
|
**Returns:** A redacted copy that preserves ordinary code verbatim.
|
|
2950
3048
|
|
|
3049
|
+
#### `addedRedactionMask(next, previous)`
|
|
3050
|
+
|
|
3051
|
+
The redaction mask `next` adds over `previous`, or null when it adds none.
|
|
3052
|
+
|
|
3053
|
+
`previous` is the file's previous content for `write_file`, and the replacement's own
|
|
3054
|
+
`old_string` for `edit_file` — an edit that carries an existing mask through (a file that
|
|
3055
|
+
already had one, read back and rewritten) adds no occurrence. A new occurrence may
|
|
3056
|
+
be copied output or intentional source; the caller declares the latter explicitly.
|
|
3057
|
+
|
|
3058
|
+
```typescript
|
|
3059
|
+
function addedRedactionMask(next: string, previous: string): string | null
|
|
3060
|
+
```
|
|
3061
|
+
|
|
3062
|
+
- `next` — The content about to be written (or the replacement's `new_string`).
|
|
3063
|
+
- `previous` — The content it replaces, already on disk (or the `old_string`).
|
|
3064
|
+
|
|
3065
|
+
**Returns:** The added mask as written (`'[REDACTED]'`, `"[REDACTED]"`, `=[REDACTED]`), or null.
|
|
3066
|
+
|
|
2951
3067
|
#### `printsOnlySource(command)`
|
|
2952
3068
|
|
|
2953
3069
|
Whether a shell command only PRINTS source files (`cat a.tsx`, `sed -n '1,40p' x.ts`,
|
|
@@ -2964,6 +3080,35 @@ function printsOnlySource(command: string): boolean
|
|
|
2964
3080
|
|
|
2965
3081
|
**Returns:** True when the command prints source files, with only literal headings and filters.
|
|
2966
3082
|
|
|
3083
|
+
#### `isReadOnlyInspection(command)`
|
|
3084
|
+
|
|
3085
|
+
Whether a shell command only INSPECTS the workspace WITHOUT printing a file's contents:
|
|
3086
|
+
it prints source files (a pure literal read, {@link printsOnlySource}), lists names
|
|
3087
|
+
(`ls`, `find`), or counts lines (`wc`) — joined by `;`, `&&` or `|`, with literal
|
|
3088
|
+
`echo`/`printf` headings and `cd`.
|
|
3089
|
+
|
|
3090
|
+
Its output is code or names, not an env dump, so it gets the code-safe redaction
|
|
3091
|
+
({@link redactSecretsInCode}) instead of the name-keyed env-dump passes. Without this,
|
|
3092
|
+
ordinary code values such as `tokenKey: 'jwtToken'` in a mixed source read and
|
|
3093
|
+
`ls | head` command would be masked by the environment-dump rules.
|
|
3094
|
+
|
|
3095
|
+
A RECURSIVE SEARCH IS NOT INSPECTION (`grep -rn x .`, `rg x src/`): its output is the
|
|
3096
|
+
content of whichever files matched, including `.env` files and JSON secret dumps, so it
|
|
3097
|
+
keeps the full grade. A path with no extension is not evidence that it is a directory —
|
|
3098
|
+
`/dev/stdin` and an ordinary `secrets` file read the same way.
|
|
3099
|
+
|
|
3100
|
+
Env dumps keep the full grade: `.env` anywhere in the command, `env`/`printenv`, a
|
|
3101
|
+
non-literal or redirecting form, and an interpreter one-liner (`node -e`, `python -c`)
|
|
3102
|
+
all return false.
|
|
3103
|
+
|
|
3104
|
+
```typescript
|
|
3105
|
+
function isReadOnlyInspection(command: string): boolean
|
|
3106
|
+
```
|
|
3107
|
+
|
|
3108
|
+
- `command` — The shell command.
|
|
3109
|
+
|
|
3110
|
+
**Returns:** True when the command only reads or lists workspace content.
|
|
3111
|
+
|
|
2967
3112
|
#### `isEnvFilePath(path)`
|
|
2968
3113
|
|
|
2969
3114
|
Whether a path is an env file, for which {@link redactSecrets}' full env-dump
|
|
@@ -3323,6 +3468,15 @@ function suiteRunPriorityLaunch(command: string, launch: string): { launch: stri
|
|
|
3323
3468
|
|
|
3324
3469
|
Check if a command is blocked for security reasons. Returns error message or null if allowed.
|
|
3325
3470
|
|
|
3471
|
+
The first check reads the commands the shell actually RUNS — the statements, a `sh -c`
|
|
3472
|
+
string's body, and every command substitution ({@link executedCommands}) — so a `|` inside a
|
|
3473
|
+
quoted grep alternation is data, not a pipeline: `grep -E "USER CALLS|ENV|BUTTON|passed|failed"
|
|
3474
|
+
app.log` prints log lines, and the `ENV` in its pattern started nothing (X0
|
|
3475
|
+
xr-molecule-flash-m331 blocked exactly that call as an environment dump, twice). What the
|
|
3476
|
+
shell DOES run stays visible through the same walk: `ls | env`, `bash -c 'env'`,
|
|
3477
|
+
`echo "$(printenv)"` and a nested `sh -c 'x; env'` are all commands, and so is `env` itself
|
|
3478
|
+
when nothing follows it.
|
|
3479
|
+
|
|
3326
3480
|
```typescript
|
|
3327
3481
|
function checkBlockedCommand(command: string): string | null
|
|
3328
3482
|
```
|
|
@@ -4253,7 +4407,10 @@ const BACKGROUNDED: RegExp
|
|
|
4253
4407
|
A program that SERVES: the scaffold's entry (`server.ts`/`server.js`), a package manager's
|
|
4254
4408
|
`start`/`dev`/`serve`/`preview` script, a Vite dev or preview server, `next start|dev`, or a
|
|
4255
4409
|
Python WSGI server. Matched against a command segment's own text, and against a script's SOURCE
|
|
4256
|
-
when the command only names the script file
|
|
4410
|
+
when the command only names the script file — but NEVER against an inline program's code
|
|
4411
|
+
(`node -e …`, `python3 -c …`), where this text is the user's program rather than a file being
|
|
4412
|
+
run: `require('…/node_modules/vite')` imports a module, it does not start a dev server
|
|
4413
|
+
(xr-molecule-flash-m391 +13:13, refused as "node starts a server" for exactly that line).
|
|
4257
4414
|
|
|
4258
4415
|
```typescript
|
|
4259
4416
|
const SERVER_PROGRAM: RegExp
|
|
@@ -4858,6 +5015,11 @@ Peer dependencies:
|
|
|
4858
5015
|
as a broken tool and routes around, taking its verification with it. Use
|
|
4859
5016
|
`guardAITool` to give tools built elsewhere the same treatment, passing
|
|
4860
5017
|
`redactError` so a thrown message is masked by your own redactor.
|
|
5018
|
+
- **Defer occasional tools** with `createDeferredToolCatalog`: pass your current
|
|
5019
|
+
permission-filtered tools and a small initial name set, offer `catalog.select()`
|
|
5020
|
+
to the model, and execute `catalog.loader` like any other tool. Loading only
|
|
5021
|
+
exposes schemas, never grants permission or runs a tool. Persist its loaded
|
|
5022
|
+
names with `onLoad` to keep them available across turns and compaction.
|
|
4861
5023
|
- **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
|
|
4862
5024
|
should not receive `write_file`/`exec_command`.
|
|
4863
5025
|
- Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
|
|
@@ -74,6 +74,43 @@ export declare function endsInBackground(command: string): boolean;
|
|
|
74
74
|
* @returns One entry per statement or pipeline stage that runs something, in order.
|
|
75
75
|
*/
|
|
76
76
|
export declare function commandSegments(command: string): CommandSegment[];
|
|
77
|
+
/** One command a shell command actually executes, wherever the shell runs it. */
|
|
78
|
+
export interface ExecutedCommand {
|
|
79
|
+
/**
|
|
80
|
+
* The word in command position, its directory removed (`/usr/bin/printenv` → `printenv`) — or
|
|
81
|
+
* the launcher itself when it runs alone and nothing follows it (`x | env` → `env`).
|
|
82
|
+
*/
|
|
83
|
+
program: string;
|
|
84
|
+
/**
|
|
85
|
+
* Its arguments, as written with quotes kept — the statement's own words AFTER the program,
|
|
86
|
+
* including an input redirect's path (`< /proc/self/environ`), so a reader of secret files sees
|
|
87
|
+
* the file it reads.
|
|
88
|
+
*/
|
|
89
|
+
args: readonly string[];
|
|
90
|
+
/** The program and its arguments as one line, what a pattern anchored at the program matches. */
|
|
91
|
+
text: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Every command a shell command actually executes, at any depth — the statements themselves, the
|
|
95
|
+
* body of a `sh -c '<command>'`, and the body of every command substitution (`$(…)`, backticks).
|
|
96
|
+
*
|
|
97
|
+
* This is the reading a policy that asks "does this command run X" needs, and it is deliberately
|
|
98
|
+
* not a text match. The command-position parser already knows what runs and what is only quoted
|
|
99
|
+
* data ({@link commandSegments}), so a pattern never reads a `|` inside a quoted grep alternation
|
|
100
|
+
* as a pipeline: `grep -E "USER CALLS|ENV|BUTTON" app.log` prints log lines, and the `ENV` in
|
|
101
|
+
* its pattern started nothing (X0 xr-molecule-flash-m331 blocked exactly that call as an
|
|
102
|
+
* environment dump). What the shell DOES run stays visible through the same walk: a bare
|
|
103
|
+
* launcher (`ls | env`), a shell string (`bash -c 'env'`), a substitution
|
|
104
|
+
* (`echo "$(printenv)"`) and a nested one (`sh -c 'x; env'`) are all commands here.
|
|
105
|
+
*
|
|
106
|
+
* `commandSegments` answers what a pipeline stage runs for a caller matching a runner; this
|
|
107
|
+
* answers with the launcher left standing when it runs alone, since that is what the shell
|
|
108
|
+
* executes then.
|
|
109
|
+
*
|
|
110
|
+
* @param command - The shell command.
|
|
111
|
+
* @returns Each command the shell executes, in the order the shell reaches them.
|
|
112
|
+
*/
|
|
113
|
+
export declare function executedCommands(command: string): ExecutedCommand[];
|
|
77
114
|
/**
|
|
78
115
|
* One statement of a shell command, with where it sits and the variables it sets for itself.
|
|
79
116
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAgSD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3D;
|
|
1
|
+
{"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAgSD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3D;AAynBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AA8GD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAIjE;AAED,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,iGAAiG;IACjG,IAAI,EAAE,MAAM,CAAA;CACb;AAmFD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,EAAE,CAGnE;AAmCD;;;;;;;;;GASG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IAC9B,0FAA0F;IAC1F,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;;;OAGG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB;;;;OAIG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,EAAE,CAE/E;AAmDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,MAAM,GAAG,IAAI,GACjB,MAAM,GAAG,IAAI,CAyDf;AA4GD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOpE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,GAC1C;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAoD7C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK/E"}
|
package/dist/command-position.js
CHANGED
|
@@ -694,14 +694,23 @@ function blankHeredocBodies(command) {
|
|
|
694
694
|
* `molecule-dev/api/src/ai/supplied-tree-guard.ts` — so a script that does not classify records
|
|
695
695
|
* no runner, and every run of it reads as nothing).
|
|
696
696
|
*
|
|
697
|
+
* The walk also RECORDS the command substitutions it enters (`$(…)` and backticks), because the
|
|
698
|
+
* shell runs those too: a reader that only saw the outer statements could not tell that
|
|
699
|
+
* `echo "$(printenv)"` prints the environment ({@link executedCommands}).
|
|
700
|
+
*
|
|
697
701
|
* @param command - The shell command.
|
|
698
702
|
* @returns Each statement's text, the offset its first character sits at, and the separator that
|
|
699
703
|
* ended it (`|`, `&&`, `;`, a newline, … — '' after the last one), in order, with empty ones
|
|
700
|
-
* dropped.
|
|
704
|
+
* dropped — and the bodies of the command substitutions this level enters, as offsets.
|
|
701
705
|
*/
|
|
702
|
-
function
|
|
706
|
+
function splitCommand(command) {
|
|
703
707
|
const source = blankHeredocBodies(command);
|
|
704
708
|
const parts = [];
|
|
709
|
+
const substitutions = [];
|
|
710
|
+
/** Where each open `$(` body starts; -1 for a bare `(` opened inside one. */
|
|
711
|
+
const subOpens = [];
|
|
712
|
+
/** Where each open backtick body starts. */
|
|
713
|
+
const tickOpens = [];
|
|
705
714
|
let buffer = '';
|
|
706
715
|
/** The offset in the command of the current buffer's first character. */
|
|
707
716
|
let bufferStart = 0;
|
|
@@ -739,6 +748,32 @@ function splitSegments(command) {
|
|
|
739
748
|
stack.pop();
|
|
740
749
|
continue;
|
|
741
750
|
}
|
|
751
|
+
// Backticks open a command substitution wherever one runs — outside quotes, inside double
|
|
752
|
+
// quotes, and inside another substitution or a parameter expansion — but never inside single
|
|
753
|
+
// quotes (handled above). Its body is a command of its own: nothing in it splits THIS command,
|
|
754
|
+
// and a `'` or `"` in it is the nested command's, not this one's.
|
|
755
|
+
if (top !== 'tick' && char === '`') {
|
|
756
|
+
stack.push('tick');
|
|
757
|
+
tickOpens.push(i + 1);
|
|
758
|
+
put(char, -1);
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (top === 'tick') {
|
|
762
|
+
if (char === '\\' && next !== undefined) {
|
|
763
|
+
// An escaped character is literal: `\`` does not close the substitution.
|
|
764
|
+
put(char + next, -1);
|
|
765
|
+
i += 1;
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
if (char === '`') {
|
|
769
|
+
stack.pop();
|
|
770
|
+
const opened = tickOpens.pop();
|
|
771
|
+
if (opened !== undefined)
|
|
772
|
+
substitutions.push({ start: opened, end: i });
|
|
773
|
+
}
|
|
774
|
+
put(char, -1);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
742
777
|
// Comments are shell syntax only in a command context, including an unquoted `$(`.
|
|
743
778
|
// Blank their bytes so quotes/operators cannot affect this walk, while every later
|
|
744
779
|
// position and depth index stays aligned with the original command. Keep the newline.
|
|
@@ -753,6 +788,7 @@ function splitSegments(command) {
|
|
|
753
788
|
// inside single quotes (handled above). The `(` is consumed here so the depth is counted once.
|
|
754
789
|
if (char === '$' && next === '(') {
|
|
755
790
|
stack.push('sub');
|
|
791
|
+
subOpens.push(i + 2);
|
|
756
792
|
put('$(', -1);
|
|
757
793
|
i += 1;
|
|
758
794
|
continue;
|
|
@@ -802,10 +838,16 @@ function splitSegments(command) {
|
|
|
802
838
|
// Inside a substitution or a subshell of one: its own parentheses nest, its `|`/`;`/`&&`
|
|
803
839
|
// belong to the nested command, and its newlines are that command's too.
|
|
804
840
|
if (top === 'sub') {
|
|
805
|
-
if (char === '(')
|
|
841
|
+
if (char === '(') {
|
|
806
842
|
stack.push('sub');
|
|
807
|
-
|
|
843
|
+
subOpens.push(-1);
|
|
844
|
+
}
|
|
845
|
+
else if (char === ')') {
|
|
808
846
|
stack.pop();
|
|
847
|
+
const opened = subOpens.pop();
|
|
848
|
+
if (opened !== undefined && opened >= 0)
|
|
849
|
+
substitutions.push({ start: opened, end: i });
|
|
850
|
+
}
|
|
809
851
|
put(char, -1);
|
|
810
852
|
continue;
|
|
811
853
|
}
|
|
@@ -861,7 +903,16 @@ function splitSegments(command) {
|
|
|
861
903
|
});
|
|
862
904
|
lastAfter = part.after;
|
|
863
905
|
}
|
|
864
|
-
return out;
|
|
906
|
+
return { parts: out, substitutions };
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* A command's statements and pipeline stages — {@link splitCommand}'s parts on their own.
|
|
910
|
+
*
|
|
911
|
+
* @param command - The shell command.
|
|
912
|
+
* @returns Each statement, in order, with empty ones dropped.
|
|
913
|
+
*/
|
|
914
|
+
function splitSegments(command) {
|
|
915
|
+
return splitCommand(command).parts;
|
|
865
916
|
}
|
|
866
917
|
/**
|
|
867
918
|
* Whether the outer shell's final statement starts a background job.
|
|
@@ -983,6 +1034,114 @@ function leadingAssignments(text) {
|
|
|
983
1034
|
export function commandSegments(command) {
|
|
984
1035
|
return locatedSegmentsOf(command, 0).flatMap((located) => located.segment === null ? [] : [located.segment]);
|
|
985
1036
|
}
|
|
1037
|
+
/**
|
|
1038
|
+
* A statement's words with its redirections taken out, so the walk that finds the program does
|
|
1039
|
+
* not read a redirect's target as the program: `env > out.txt` RUNS `env`, and `cat > f` runs
|
|
1040
|
+
* `cat` with no file argument. Each word kept carries its index in `words`, because a caller
|
|
1041
|
+
* reading the statement's ARGUMENTS wants it as written — an input redirect's path is one.
|
|
1042
|
+
*
|
|
1043
|
+
* @param words - One statement's words, quotes kept.
|
|
1044
|
+
* @returns The words that are not redirections, and each one's index in `words`.
|
|
1045
|
+
*/
|
|
1046
|
+
function withoutRedirects(words) {
|
|
1047
|
+
const kept = [];
|
|
1048
|
+
const index = [];
|
|
1049
|
+
for (let i = 0; i < words.length; i += 1) {
|
|
1050
|
+
const word = words[i] ?? '';
|
|
1051
|
+
// An operator written on its own owns the word after it (`> out.txt`, `< /proc/self/environ`).
|
|
1052
|
+
if (REDIRECT_OPERATOR.test(word)) {
|
|
1053
|
+
i += 1;
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
// An operator with its target attached (`2>&1`, `>out.txt`, `&>log`) is one word.
|
|
1057
|
+
if (REDIRECT_WORD.test(word))
|
|
1058
|
+
continue;
|
|
1059
|
+
kept.push(word);
|
|
1060
|
+
index.push(i);
|
|
1061
|
+
}
|
|
1062
|
+
return { words: kept, index };
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* The index of the last launcher a statement names (`x | env`, `sudo nice`), or null when it
|
|
1066
|
+
* names none.
|
|
1067
|
+
*
|
|
1068
|
+
* A statement that only NAMES a launcher runs that launcher: `x | env` pipes x's output into
|
|
1069
|
+
* `env`, which prints the environment, and the walk that reports what a command runs has to say
|
|
1070
|
+
* so ({@link executedCommands}).
|
|
1071
|
+
*
|
|
1072
|
+
* @param words - The statement's words, redirections already taken out.
|
|
1073
|
+
* @returns The launcher's index, or null.
|
|
1074
|
+
*/
|
|
1075
|
+
function lastLauncherIndex(words) {
|
|
1076
|
+
for (let i = words.length - 1; i >= 0; i -= 1) {
|
|
1077
|
+
if (LAUNCHERS.has(programName(words[i] ?? '')))
|
|
1078
|
+
return i;
|
|
1079
|
+
}
|
|
1080
|
+
return null;
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* {@link executedCommands}'s recursion: a statement's own `sh -c '<command>'`, and every command
|
|
1084
|
+
* substitution it carries, is a command of its own.
|
|
1085
|
+
*
|
|
1086
|
+
* @param command - The shell command, or one nested command string.
|
|
1087
|
+
* @param depth - How many nested command strings this one already sits inside.
|
|
1088
|
+
* @returns Each command the shell executes, in order.
|
|
1089
|
+
*/
|
|
1090
|
+
function executedCommandsOf(command, depth) {
|
|
1091
|
+
if (typeof command !== 'string' || depth > MAX_NESTING)
|
|
1092
|
+
return [];
|
|
1093
|
+
const out = [];
|
|
1094
|
+
const { parts, substitutions } = splitCommand(command);
|
|
1095
|
+
for (const part of parts) {
|
|
1096
|
+
const words = segmentWords(part.text);
|
|
1097
|
+
const placed = withoutRedirects(words);
|
|
1098
|
+
const start = commandStart(placed.words);
|
|
1099
|
+
// A shell's `-c '<command>'` is the command: what the shell itself does is run it.
|
|
1100
|
+
if (start.nested !== null) {
|
|
1101
|
+
out.push(...executedCommandsOf(start.nested, depth + 1));
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
const at = placed.words[start.at] === undefined ? lastLauncherIndex(placed.words) : start.at;
|
|
1105
|
+
if (at === null)
|
|
1106
|
+
continue;
|
|
1107
|
+
const program = start.program ?? programName(placed.words[at] ?? '');
|
|
1108
|
+
if (!program)
|
|
1109
|
+
continue;
|
|
1110
|
+
// Arguments from the statement as written, from the word after the program: `cat < /proc/…`
|
|
1111
|
+
// reads that file, and a reader of secret files has to see it.
|
|
1112
|
+
const args = words.slice((placed.index[at] ?? 0) + 1);
|
|
1113
|
+
out.push({ program, args, text: [program, ...args].join(' ') });
|
|
1114
|
+
}
|
|
1115
|
+
for (const substitution of substitutions) {
|
|
1116
|
+
out.push(...executedCommandsOf(command.slice(substitution.start, substitution.end), depth + 1));
|
|
1117
|
+
}
|
|
1118
|
+
return out;
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Every command a shell command actually executes, at any depth — the statements themselves, the
|
|
1122
|
+
* body of a `sh -c '<command>'`, and the body of every command substitution (`$(…)`, backticks).
|
|
1123
|
+
*
|
|
1124
|
+
* This is the reading a policy that asks "does this command run X" needs, and it is deliberately
|
|
1125
|
+
* not a text match. The command-position parser already knows what runs and what is only quoted
|
|
1126
|
+
* data ({@link commandSegments}), so a pattern never reads a `|` inside a quoted grep alternation
|
|
1127
|
+
* as a pipeline: `grep -E "USER CALLS|ENV|BUTTON" app.log` prints log lines, and the `ENV` in
|
|
1128
|
+
* its pattern started nothing (X0 xr-molecule-flash-m331 blocked exactly that call as an
|
|
1129
|
+
* environment dump). What the shell DOES run stays visible through the same walk: a bare
|
|
1130
|
+
* launcher (`ls | env`), a shell string (`bash -c 'env'`), a substitution
|
|
1131
|
+
* (`echo "$(printenv)"`) and a nested one (`sh -c 'x; env'`) are all commands here.
|
|
1132
|
+
*
|
|
1133
|
+
* `commandSegments` answers what a pipeline stage runs for a caller matching a runner; this
|
|
1134
|
+
* answers with the launcher left standing when it runs alone, since that is what the shell
|
|
1135
|
+
* executes then.
|
|
1136
|
+
*
|
|
1137
|
+
* @param command - The shell command.
|
|
1138
|
+
* @returns Each command the shell executes, in the order the shell reaches them.
|
|
1139
|
+
*/
|
|
1140
|
+
export function executedCommands(command) {
|
|
1141
|
+
if (typeof command !== 'string' || !command.trim())
|
|
1142
|
+
return [];
|
|
1143
|
+
return executedCommandsOf(command, 0);
|
|
1144
|
+
}
|
|
986
1145
|
/**
|
|
987
1146
|
* Where a statement's word sits in its own raw text, as {@link segmentWords} counts the words.
|
|
988
1147
|
*
|
package/dist/cut-run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cut-run.d.ts","sourceRoot":"","sources":["../src/cut-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAMH;;;GAGG;AACH,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAE5C,kFAAkF;AAClF,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,aAAa,CAAA;AAE1D;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,CAGhE;AAiBD;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAA;CAClB;AAkDD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA4B9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAKD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,GACb,MAAM,GAAG,IAAI,CAIf;AAED,0BAA0B;AAC1B,MAAM,MAAM,KAAK;AACf,sEAAsE;AACpE,aAAa;AACf,oDAAoD;GAClD,iBAAiB;AACnB;;;;GAIG;GACD,cAAc,CAAA;AAElB,wDAAwD;AACxD,MAAM,WAAW,MAAM;IACrB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAA;IACf,kFAAkF;IAClF,SAAS,EAAE,KAAK,CAAA;IAChB;;;;;;OAMG;IACH,UAAU,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB;;;OAGG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,qCAAqC;IACrC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,yEAAyE;IACzE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAsDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,aAAa,SAAI,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"cut-run.d.ts","sourceRoot":"","sources":["../src/cut-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAMH;;;GAGG;AACH,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAE5C,kFAAkF;AAClF,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,aAAa,CAAA;AAE1D;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,CAGhE;AAiBD;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAA;CAClB;AAkDD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA4B9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAKD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,GACb,MAAM,GAAG,IAAI,CAIf;AAED,0BAA0B;AAC1B,MAAM,MAAM,KAAK;AACf,sEAAsE;AACpE,aAAa;AACf,oDAAoD;GAClD,iBAAiB;AACnB;;;;GAIG;GACD,cAAc,CAAA;AAElB,wDAAwD;AACxD,MAAM,WAAW,MAAM;IACrB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAA;IACf,kFAAkF;IAClF,SAAS,EAAE,KAAK,CAAA;IAChB;;;;;;OAMG;IACH,UAAU,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB;;;OAGG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,qCAAqC;IACrC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,yEAAyE;IACzE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAsDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,aAAa,SAAI,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAgGf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAmB1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAyClD"}
|
package/dist/cut-run.js
CHANGED
|
@@ -345,12 +345,16 @@ export function commandCutRun(command, result, elapsedMs, budgetSeconds = 0, raw
|
|
|
345
345
|
inlineScript,
|
|
346
346
|
};
|
|
347
347
|
}
|
|
348
|
-
//
|
|
349
|
-
// bound above fired: the process was stopped from
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
|
|
348
|
+
// A runner's summary that does not account for the total it announced, in a command that
|
|
349
|
+
// actually RUNS that runner, and neither bound above fired: the process was stopped from
|
|
350
|
+
// outside the run. The command must run the runner — a reader of a LIVE run's log prints the
|
|
351
|
+
// same announcement and partial tally as text it copies, and reporting that as a stopped run
|
|
352
|
+
// told the executor a suite it had only grepped had been killed (X0 xr-molecule-flash-m345,
|
|
353
|
+
// +50:00: `grep -B2 -A12 … /tmp/mol-bg-….log | head -40` came back `stoppedBy: process-stop`
|
|
354
|
+
// after 1 s). A run that used the whole budget is the backend's deadline (which sits just past
|
|
355
|
+
// it); anything else is a stop this tool does not own. Either way the summary counts are all
|
|
356
|
+
// that ran, and a pipeline's 0 is not the run's code — the run never reached its own verdict.
|
|
357
|
+
if (suite && summary !== null && summary.announced !== null) {
|
|
354
358
|
const usedBudget = budgetSeconds > 0 && elapsedMs >= atBoundMs(budgetSeconds);
|
|
355
359
|
return {
|
|
356
360
|
seconds: usedBudget ? budgetSeconds : Math.max(1, Math.round(elapsedMs / 1000)),
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,11 @@
|
|
|
70
70
|
* as a broken tool and routes around, taking its verification with it. Use
|
|
71
71
|
* `guardAITool` to give tools built elsewhere the same treatment, passing
|
|
72
72
|
* `redactError` so a thrown message is masked by your own redactor.
|
|
73
|
+
* - **Defer occasional tools** with `createDeferredToolCatalog`: pass your current
|
|
74
|
+
* permission-filtered tools and a small initial name set, offer `catalog.select()`
|
|
75
|
+
* to the model, and execute `catalog.loader` like any other tool. Loading only
|
|
76
|
+
* exposes schemas, never grants permission or runs a tool. Persist its loaded
|
|
77
|
+
* names with `onLoad` to keep them available across turns and compaction.
|
|
73
78
|
* - **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
|
|
74
79
|
* should not receive `write_file`/`exec_command`.
|
|
75
80
|
* - Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
|
|
@@ -147,6 +152,7 @@ export * from './server-command.js';
|
|
|
147
152
|
export * from './sleep-peek.js';
|
|
148
153
|
export * from './suite-overlap.js';
|
|
149
154
|
export * from './system-prompt.js';
|
|
155
|
+
export * from './tool-catalog.js';
|
|
150
156
|
export * from './tools.js';
|
|
151
157
|
export * from './trace-artifacts.js';
|
|
152
158
|
export * from './types.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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuIG;AAEH,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,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,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"}
|
package/dist/index.js
CHANGED
|
@@ -70,6 +70,11 @@
|
|
|
70
70
|
* as a broken tool and routes around, taking its verification with it. Use
|
|
71
71
|
* `guardAITool` to give tools built elsewhere the same treatment, passing
|
|
72
72
|
* `redactError` so a thrown message is masked by your own redactor.
|
|
73
|
+
* - **Defer occasional tools** with `createDeferredToolCatalog`: pass your current
|
|
74
|
+
* permission-filtered tools and a small initial name set, offer `catalog.select()`
|
|
75
|
+
* to the model, and execute `catalog.loader` like any other tool. Loading only
|
|
76
|
+
* exposes schemas, never grants permission or runs a tool. Persist its loaded
|
|
77
|
+
* names with `onLoad` to keep them available across turns and compaction.
|
|
73
78
|
* - **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
|
|
74
79
|
* should not receive `write_file`/`exec_command`.
|
|
75
80
|
* - Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
|
|
@@ -147,6 +152,7 @@ export * from './server-command.js';
|
|
|
147
152
|
export * from './sleep-peek.js';
|
|
148
153
|
export * from './suite-overlap.js';
|
|
149
154
|
export * from './system-prompt.js';
|
|
155
|
+
export * from './tool-catalog.js';
|
|
150
156
|
export * from './tools.js';
|
|
151
157
|
export * from './trace-artifacts.js';
|
|
152
158
|
export * from './types.js';
|
package/dist/schemas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAwW1C,CAAA"}
|
package/dist/schemas.js
CHANGED
|
@@ -71,6 +71,10 @@ export const TOOL_SCHEMAS = {
|
|
|
71
71
|
parameters: {
|
|
72
72
|
type: 'object',
|
|
73
73
|
properties: {
|
|
74
|
+
intentional_redaction_placeholder: {
|
|
75
|
+
type: 'boolean',
|
|
76
|
+
description: 'Set true only when intentionally authoring a literal [REDACTED] placeholder. Default false: newly copied output placeholders are refused. This never disables secret-output masking.',
|
|
77
|
+
},
|
|
74
78
|
path: {
|
|
75
79
|
type: 'string',
|
|
76
80
|
description: 'Path to the file to write.',
|
|
@@ -89,6 +93,10 @@ export const TOOL_SCHEMAS = {
|
|
|
89
93
|
parameters: {
|
|
90
94
|
type: 'object',
|
|
91
95
|
properties: {
|
|
96
|
+
intentional_redaction_placeholder: {
|
|
97
|
+
type: 'boolean',
|
|
98
|
+
description: 'Set true only when intentionally authoring a literal [REDACTED] placeholder. Default false: newly copied output placeholders are refused. This never disables secret-output masking.',
|
|
99
|
+
},
|
|
92
100
|
path: {
|
|
93
101
|
type: 'string',
|
|
94
102
|
description: 'Path to the file to edit.',
|