@warlock.js/ai-workspace 5.29.0 → 5.31.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/CHANGELOG.md +68 -0
- package/README.md +40 -21
- package/cjs/index.cjs +3295 -360
- package/cjs/index.cjs.map +1 -1
- package/esm/backends/local.d.mts +1 -1
- package/esm/backends/local.d.mts.map +1 -1
- package/esm/backends/local.mjs +199 -31
- package/esm/backends/local.mjs.map +1 -1
- package/esm/backends/mock.d.mts +12 -6
- package/esm/backends/mock.d.mts.map +1 -1
- package/esm/backends/mock.mjs +45 -3
- package/esm/backends/mock.mjs.map +1 -1
- package/esm/contracts/index.d.mts +3 -3
- package/esm/contracts/tool-io.type.d.mts +248 -11
- package/esm/contracts/tool-io.type.d.mts.map +1 -1
- package/esm/contracts/workspace-backend.contract.d.mts +78 -2
- package/esm/contracts/workspace-backend.contract.d.mts.map +1 -1
- package/esm/contracts/workspace-ops.contract.d.mts +41 -16
- package/esm/contracts/workspace-ops.contract.d.mts.map +1 -1
- package/esm/contracts/workspace-policy.type.d.mts +142 -14
- package/esm/contracts/workspace-policy.type.d.mts.map +1 -1
- package/esm/contracts/workspace.contract.d.mts +75 -22
- package/esm/contracts/workspace.contract.d.mts.map +1 -1
- package/esm/errors.d.mts +80 -6
- package/esm/errors.d.mts.map +1 -1
- package/esm/errors.mjs +23 -2
- package/esm/errors.mjs.map +1 -1
- package/esm/index.d.mts +13 -5
- package/esm/index.mjs +10 -2
- package/esm/ops.d.mts +22 -3
- package/esm/ops.d.mts.map +1 -1
- package/esm/ops.mjs +341 -82
- package/esm/ops.mjs.map +1 -1
- package/esm/policy/jail.mjs +73 -0
- package/esm/policy/jail.mjs.map +1 -0
- package/esm/policy/policy.d.mts +26 -16
- package/esm/policy/policy.d.mts.map +1 -1
- package/esm/policy/policy.mjs +62 -86
- package/esm/policy/policy.mjs.map +1 -1
- package/esm/policy/shell-check.d.mts +64 -0
- package/esm/policy/shell-check.d.mts.map +1 -0
- package/esm/policy/shell-check.mjs +627 -0
- package/esm/policy/shell-check.mjs.map +1 -0
- package/esm/policy/shell-parser.mjs +802 -0
- package/esm/policy/shell-parser.mjs.map +1 -0
- package/esm/policy/tokenize-command.d.mts +63 -0
- package/esm/policy/tokenize-command.d.mts.map +1 -0
- package/esm/policy/tokenize-command.mjs +76 -24
- package/esm/policy/tokenize-command.mjs.map +1 -1
- package/esm/shell-jobs.d.mts +45 -0
- package/esm/shell-jobs.d.mts.map +1 -0
- package/esm/shell-jobs.mjs +247 -0
- package/esm/shell-jobs.mjs.map +1 -0
- package/esm/todos.d.mts +22 -0
- package/esm/todos.d.mts.map +1 -0
- package/esm/todos.mjs +73 -0
- package/esm/todos.mjs.map +1 -0
- package/esm/tools/edit-file.d.mts +1 -1
- package/esm/tools/edit-file.d.mts.map +1 -1
- package/esm/tools/edit-file.mjs +3 -2
- package/esm/tools/edit-file.mjs.map +1 -1
- package/esm/tools/glob.d.mts +1 -1
- package/esm/tools/glob.d.mts.map +1 -1
- package/esm/tools/glob.mjs +3 -2
- package/esm/tools/glob.mjs.map +1 -1
- package/esm/tools/grep.d.mts +1 -1
- package/esm/tools/grep.d.mts.map +1 -1
- package/esm/tools/grep.mjs +3 -2
- package/esm/tools/grep.mjs.map +1 -1
- package/esm/tools/json-schemas.mjs +175 -0
- package/esm/tools/json-schemas.mjs.map +1 -0
- package/esm/tools/list-dir.d.mts +32 -0
- package/esm/tools/list-dir.d.mts.map +1 -0
- package/esm/tools/list-dir.mjs +50 -0
- package/esm/tools/list-dir.mjs.map +1 -0
- package/esm/tools/multi-edit.d.mts +38 -0
- package/esm/tools/multi-edit.d.mts.map +1 -0
- package/esm/tools/multi-edit.mjs +121 -0
- package/esm/tools/multi-edit.mjs.map +1 -0
- package/esm/tools/read-file.d.mts +5 -5
- package/esm/tools/read-file.d.mts.map +1 -1
- package/esm/tools/read-file.mjs +10 -20
- package/esm/tools/read-file.mjs.map +1 -1
- package/esm/tools/run-shell.d.mts +39 -13
- package/esm/tools/run-shell.d.mts.map +1 -1
- package/esm/tools/run-shell.mjs +60 -47
- package/esm/tools/run-shell.mjs.map +1 -1
- package/esm/tools/run-tests.d.mts +11 -2
- package/esm/tools/run-tests.d.mts.map +1 -1
- package/esm/tools/run-tests.mjs +15 -7
- package/esm/tools/run-tests.mjs.map +1 -1
- package/esm/tools/schema.mjs +24 -19
- package/esm/tools/schema.mjs.map +1 -1
- package/esm/tools/shell-kill.d.mts +25 -0
- package/esm/tools/shell-kill.d.mts.map +1 -0
- package/esm/tools/shell-kill.mjs +36 -0
- package/esm/tools/shell-kill.mjs.map +1 -0
- package/esm/tools/shell-output.d.mts +30 -0
- package/esm/tools/shell-output.d.mts.map +1 -0
- package/esm/tools/shell-output.mjs +49 -0
- package/esm/tools/shell-output.mjs.map +1 -0
- package/esm/tools/todo.d.mts +43 -0
- package/esm/tools/todo.d.mts.map +1 -0
- package/esm/tools/todo.mjs +126 -0
- package/esm/tools/todo.mjs.map +1 -0
- package/esm/tools/write-file.d.mts +1 -1
- package/esm/tools/write-file.d.mts.map +1 -1
- package/esm/tools/write-file.mjs +3 -2
- package/esm/tools/write-file.mjs.map +1 -1
- package/esm/workspace.d.mts +12 -9
- package/esm/workspace.d.mts.map +1 -1
- package/esm/workspace.mjs +109 -28
- package/esm/workspace.mjs.map +1 -1
- package/llms-full.txt +192 -35
- package/llms.txt +1 -1
- package/package.json +5 -4
- package/skills/README.md +2 -2
- package/skills/build-loop-agent/SKILL.md +7 -7
- package/skills/index.md +6 -1
- package/skills/use-a-workspace/SKILL.md +185 -28
|
@@ -1,27 +1,47 @@
|
|
|
1
|
-
import { RunShellInput, RunShellResult } from "../contracts/tool-io.type.mjs";
|
|
1
|
+
import { RunShellBackgroundResult, RunShellInput, RunShellResult } from "../contracts/tool-io.type.mjs";
|
|
2
2
|
import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
|
|
3
3
|
import { ToolContract } from "@warlock.js/ai";
|
|
4
4
|
|
|
5
|
-
//#region
|
|
5
|
+
//#region ../../packages/ai-workspace/src/tools/run-shell.d.ts
|
|
6
6
|
/** Options for {@link makeRunShellTool}. */
|
|
7
7
|
interface MakeRunShellToolOptions {
|
|
8
8
|
/** Override the tool name exposed to the LLM (default `"run_shell"`). */
|
|
9
9
|
name?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Upper bound for a model-supplied `timeoutMs` on a foreground command —
|
|
12
|
+
* the model can lower the timeout, never raise it past this. The
|
|
13
|
+
* workspace passes its `shell.timeoutMs`.
|
|
14
|
+
*/
|
|
15
|
+
maxTimeoutMs?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Accept `background: true` and start the command as a background job
|
|
18
|
+
* (`ops.startShell`), returning a {@link RunShellBackgroundResult}. The
|
|
19
|
+
* workspace sets it when the policy has `shell.background`. Default
|
|
20
|
+
* `false`: a background request is refused.
|
|
21
|
+
*/
|
|
22
|
+
background?: boolean;
|
|
10
23
|
}
|
|
11
24
|
/**
|
|
12
|
-
* Build the `run_shell` tool — a {@link ToolContract} that runs a
|
|
13
|
-
*
|
|
25
|
+
* Build the `run_shell` tool — a {@link ToolContract} that runs a command
|
|
26
|
+
* line through the policy-enforced {@link WorkspaceOps} layer.
|
|
14
27
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `
|
|
18
|
-
* in the result's `error` field
|
|
19
|
-
* reads the refusal as tool data
|
|
20
|
-
* but exits non-zero is *not* an
|
|
21
|
-
* in `data` for the agent to
|
|
28
|
+
* Every command in the line is checked against the shell policy by
|
|
29
|
+
* `ops.exec`; a refused line throws a `WorkspacePolicyError` (with a
|
|
30
|
+
* `reason` and a message that says how to fix the command) which the
|
|
31
|
+
* `tool()` runtime catches and surfaces in the result's `error` field
|
|
32
|
+
* (never a thrown run-killer), so the agent reads the refusal as tool data
|
|
33
|
+
* and self-corrects. A command that runs but exits non-zero is *not* an
|
|
34
|
+
* error — its `exitCode`/`stderr` come back in `data` for the agent to
|
|
35
|
+
* inspect.
|
|
36
|
+
*
|
|
37
|
+
* The agent run's cancellation `signal` (from the dispatch `ctx`) is passed
|
|
38
|
+
* to `ops.exec` per invocation: a cancelled run never starts the command,
|
|
39
|
+
* and one cancelled mid-command kills its process tree (`cancelled: true`).
|
|
40
|
+
* A background command (`background: true`, when enabled) belongs to the
|
|
41
|
+
* workspace instead and keeps running after the call returns.
|
|
22
42
|
*
|
|
23
43
|
* @param ops - The policy-enforced operation layer to delegate `exec` to.
|
|
24
|
-
* @param options -
|
|
44
|
+
* @param options - Tool-name override, timeout cap and background support.
|
|
25
45
|
*
|
|
26
46
|
* @example
|
|
27
47
|
* const runShell = makeRunShellTool(ops);
|
|
@@ -29,7 +49,13 @@ interface MakeRunShellToolOptions {
|
|
|
29
49
|
* if (error) handleDenied(error);
|
|
30
50
|
* else console.log(data.exitCode, data.stdout);
|
|
31
51
|
*/
|
|
32
|
-
declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions
|
|
52
|
+
declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions & {
|
|
53
|
+
background?: false;
|
|
54
|
+
}): ToolContract<RunShellInput, RunShellResult>;
|
|
55
|
+
declare function makeRunShellTool(ops: WorkspaceOps, options: MakeRunShellToolOptions & {
|
|
56
|
+
background: true;
|
|
57
|
+
}): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;
|
|
58
|
+
declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;
|
|
33
59
|
//#endregion
|
|
34
60
|
export { MakeRunShellToolOptions, makeRunShellTool };
|
|
35
61
|
//# sourceMappingURL=run-shell.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-shell.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"run-shell.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-shell.ts"],"mappings":";;;;;;UA2EiB,uBAAA;;EAEf,IAAA;EAFe;;;;;EAQf,YAAA;EAOA;;AAAU;AAwCZ;;;EAxCE,UAAA;AAAA;;;;;;;;;;;;;;;AA2C2C;AAC7C;;;;;;;;;;;;;iBAJgB,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA;EAA4B,UAAA;AAAA,IACrC,YAAA,CAAa,aAAA,EAAe,cAAA;AAAA,iBACf,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,EAAS,uBAAA;EAA4B,UAAA;AAAA,IACpC,YAAA,CAAa,aAAA,EAAe,cAAA,GAAiB,wBAAA;AAAA,iBAChC,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA,GACT,YAAA,CAAa,aAAA,EAAe,cAAA,GAAiB,wBAAA"}
|
package/esm/tools/run-shell.mjs
CHANGED
|
@@ -1,62 +1,75 @@
|
|
|
1
|
+
import { WorkspacePolicyError } from "../errors.mjs";
|
|
2
|
+
import { withJsonSchema } from "./schema.mjs";
|
|
3
|
+
import { runShellJsonSchema } from "./json-schemas.mjs";
|
|
1
4
|
import { tool } from "@warlock.js/ai";
|
|
2
5
|
|
|
3
|
-
//#region
|
|
6
|
+
//#region ../../packages/ai-workspace/src/tools/run-shell.ts
|
|
4
7
|
/** The default tool name `run_shell` is exposed to the LLM under. */
|
|
5
8
|
const DEFAULT_RUN_SHELL_TOOL_NAME = "run_shell";
|
|
6
9
|
/**
|
|
7
10
|
* Hand-rolled Standard Schema for {@link RunShellInput}. We validate the
|
|
8
11
|
* model's arguments without a runtime schema dependency: `command` must be
|
|
9
|
-
* a non-empty string,
|
|
10
|
-
* Invalid args surface as a
|
|
11
|
-
* `error` field rather than
|
|
12
|
-
|
|
13
|
-
const runShellInputSchema = { "~standard": {
|
|
14
|
-
version: 1,
|
|
15
|
-
vendor: "@warlock.js/ai-workspace",
|
|
16
|
-
validate: (value) => {
|
|
17
|
-
if (typeof value !== "object" || value === null) return { issues: [{ message: "expected an object" }] };
|
|
18
|
-
const candidate = value;
|
|
19
|
-
if (typeof candidate.command !== "string" || candidate.command.length === 0) return { issues: [{
|
|
20
|
-
message: "command must be a non-empty string",
|
|
21
|
-
path: ["command"]
|
|
22
|
-
}] };
|
|
23
|
-
if (candidate.timeoutMs !== void 0 && (typeof candidate.timeoutMs !== "number" || candidate.timeoutMs <= 0)) return { issues: [{
|
|
24
|
-
message: "timeoutMs must be a positive number",
|
|
25
|
-
path: ["timeoutMs"]
|
|
26
|
-
}] };
|
|
27
|
-
const result = { command: candidate.command };
|
|
28
|
-
if (candidate.timeoutMs !== void 0) result.timeoutMs = candidate.timeoutMs;
|
|
29
|
-
return { value: result };
|
|
30
|
-
}
|
|
31
|
-
} };
|
|
32
|
-
/**
|
|
33
|
-
* Build the `run_shell` tool — a {@link ToolContract} that runs a single
|
|
34
|
-
* shell command through the policy-enforced {@link WorkspaceOps} layer.
|
|
35
|
-
*
|
|
36
|
-
* The command's leading executable basename is gated against the shell
|
|
37
|
-
* allow/deny policy by `ops.exec`; a blocked command throws a
|
|
38
|
-
* `WorkspacePolicyError` which the `tool()` runtime catches and surfaces
|
|
39
|
-
* in the result's `error` field (never a thrown run-killer), so the agent
|
|
40
|
-
* reads the refusal as tool data and self-corrects. A command that runs
|
|
41
|
-
* but exits non-zero is *not* an error — its `exitCode`/`stderr` come back
|
|
42
|
-
* in `data` for the agent to inspect.
|
|
43
|
-
*
|
|
44
|
-
* @param ops - The policy-enforced operation layer to delegate `exec` to.
|
|
45
|
-
* @param options - Optional tool-name override.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* const runShell = makeRunShellTool(ops);
|
|
49
|
-
* const { data, error } = await runShell.invoke({ command: "npm run build" });
|
|
50
|
-
* if (error) handleDenied(error);
|
|
51
|
-
* else console.log(data.exitCode, data.stdout);
|
|
12
|
+
* a non-empty string, `timeoutMs` (when present) a positive number and
|
|
13
|
+
* `background` (when present) a boolean. Invalid args surface as a
|
|
14
|
+
* `SchemaValidationError` in the tool result's `error` field rather than
|
|
15
|
+
* reaching `ops.exec`.
|
|
52
16
|
*/
|
|
17
|
+
function runShellInputSchema(background) {
|
|
18
|
+
return withJsonSchema({ "~standard": {
|
|
19
|
+
version: 1,
|
|
20
|
+
vendor: "@warlock.js/ai-workspace",
|
|
21
|
+
validate: (value) => {
|
|
22
|
+
if (typeof value !== "object" || value === null) return { issues: [{ message: "expected an object" }] };
|
|
23
|
+
const candidate = value;
|
|
24
|
+
if (typeof candidate.command !== "string" || candidate.command.length === 0) return { issues: [{
|
|
25
|
+
message: "command must be a non-empty string",
|
|
26
|
+
path: ["command"]
|
|
27
|
+
}] };
|
|
28
|
+
if (candidate.timeoutMs !== void 0 && (typeof candidate.timeoutMs !== "number" || candidate.timeoutMs <= 0)) return { issues: [{
|
|
29
|
+
message: "timeoutMs must be a positive number",
|
|
30
|
+
path: ["timeoutMs"]
|
|
31
|
+
}] };
|
|
32
|
+
if (candidate.background !== void 0 && typeof candidate.background !== "boolean") return { issues: [{
|
|
33
|
+
message: "background must be a boolean",
|
|
34
|
+
path: ["background"]
|
|
35
|
+
}] };
|
|
36
|
+
const result = { command: candidate.command };
|
|
37
|
+
if (typeof candidate.timeoutMs === "number") result.timeoutMs = candidate.timeoutMs;
|
|
38
|
+
if (candidate.background === true) result.background = true;
|
|
39
|
+
return { value: result };
|
|
40
|
+
}
|
|
41
|
+
} }, runShellJsonSchema(background));
|
|
42
|
+
}
|
|
43
|
+
/** The lower of the model's timeout and the cap (either may be absent). */
|
|
44
|
+
function cappedTimeout(requested, cap) {
|
|
45
|
+
if (requested === void 0) return cap;
|
|
46
|
+
return cap === void 0 ? requested : Math.min(requested, cap);
|
|
47
|
+
}
|
|
53
48
|
function makeRunShellTool(ops, options) {
|
|
49
|
+
const background = options?.background === true;
|
|
54
50
|
return tool({
|
|
55
51
|
name: options?.name ?? DEFAULT_RUN_SHELL_TOOL_NAME,
|
|
56
|
-
description: "Run a
|
|
52
|
+
description: "Run a shell command inside the workspace. Every command in it must be permitted by the shell policy; a refusal explains how to fix the command. Output is byte-capped and the run is time-limited. A non-zero exit code is returned as data, not an error." + (background ? " Pass background: true for a long-running command (dev server, watcher): it returns an id at once; read its output with shell_output and stop it with shell_kill." : ""),
|
|
57
53
|
action: (input) => `Running \`${input.command}\``,
|
|
58
|
-
input: runShellInputSchema,
|
|
59
|
-
execute: (input) =>
|
|
54
|
+
input: runShellInputSchema(background),
|
|
55
|
+
execute: async (input, ctx) => {
|
|
56
|
+
if (input.background === true) {
|
|
57
|
+
if (!background) throw new WorkspacePolicyError("Background commands are not enabled for this workspace; run the command without background.", {
|
|
58
|
+
type: "denied-command",
|
|
59
|
+
reason: "not-allowed",
|
|
60
|
+
command: input.command
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
...await ops.startShell(input.command, input.timeoutMs !== void 0 ? { timeoutMs: input.timeoutMs } : void 0),
|
|
64
|
+
background: true
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const timeoutMs = cappedTimeout(input.timeoutMs, options?.maxTimeoutMs);
|
|
68
|
+
return ops.exec(input.command, {
|
|
69
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
70
|
+
...ctx?.signal ? { signal: ctx.signal } : {}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
60
73
|
});
|
|
61
74
|
}
|
|
62
75
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-shell.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"run-shell.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-shell.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { tool, type ToolContract } from \"@warlock.js/ai\";\nimport { WorkspacePolicyError } from \"../errors\";\nimport type {\n RunShellBackgroundResult,\n RunShellInput,\n RunShellResult,\n WorkspaceOps,\n} from \"../contracts\";\nimport { runShellJsonSchema } from \"./json-schemas\";\nimport { withJsonSchema } from \"./schema\";\n\n/** The default tool name `run_shell` is exposed to the LLM under. */\nconst DEFAULT_RUN_SHELL_TOOL_NAME = \"run_shell\";\n\n/**\n * Hand-rolled Standard Schema for {@link RunShellInput}. We validate the\n * model's arguments without a runtime schema dependency: `command` must be\n * a non-empty string, `timeoutMs` (when present) a positive number and\n * `background` (when present) a boolean. Invalid args surface as a\n * `SchemaValidationError` in the tool result's `error` field rather than\n * reaching `ops.exec`.\n */\nfunction runShellInputSchema(background: boolean): StandardSchemaV1<RunShellInput> {\n const schema: StandardSchemaV1<RunShellInput> = {\n \"~standard\": {\n version: 1,\n vendor: \"@warlock.js/ai-workspace\",\n validate: (value) => {\n if (typeof value !== \"object\" || value === null) {\n return { issues: [{ message: \"expected an object\" }] };\n }\n\n const candidate = value as Record<string, unknown>;\n\n if (typeof candidate.command !== \"string\" || candidate.command.length === 0) {\n return {\n issues: [{ message: \"command must be a non-empty string\", path: [\"command\"] }],\n };\n }\n\n if (\n candidate.timeoutMs !== undefined &&\n (typeof candidate.timeoutMs !== \"number\" || candidate.timeoutMs <= 0)\n ) {\n return {\n issues: [{ message: \"timeoutMs must be a positive number\", path: [\"timeoutMs\"] }],\n };\n }\n\n if (candidate.background !== undefined && typeof candidate.background !== \"boolean\") {\n return {\n issues: [{ message: \"background must be a boolean\", path: [\"background\"] }],\n };\n }\n\n const result: RunShellInput = { command: candidate.command };\n\n if (typeof candidate.timeoutMs === \"number\") {\n result.timeoutMs = candidate.timeoutMs;\n }\n\n if (candidate.background === true) {\n result.background = true;\n }\n\n return { value: result };\n },\n },\n };\n\n return withJsonSchema(schema, runShellJsonSchema(background));\n}\n\n/** Options for {@link makeRunShellTool}. */\nexport interface MakeRunShellToolOptions {\n /** Override the tool name exposed to the LLM (default `\"run_shell\"`). */\n name?: string;\n /**\n * Upper bound for a model-supplied `timeoutMs` on a foreground command —\n * the model can lower the timeout, never raise it past this. The\n * workspace passes its `shell.timeoutMs`.\n */\n maxTimeoutMs?: number;\n /**\n * Accept `background: true` and start the command as a background job\n * (`ops.startShell`), returning a {@link RunShellBackgroundResult}. The\n * workspace sets it when the policy has `shell.background`. Default\n * `false`: a background request is refused.\n */\n background?: boolean;\n}\n\n/** The lower of the model's timeout and the cap (either may be absent). */\nfunction cappedTimeout(requested: number | undefined, cap: number | undefined): number | undefined {\n if (requested === undefined) {\n return cap;\n }\n\n return cap === undefined ? requested : Math.min(requested, cap);\n}\n\n/**\n * Build the `run_shell` tool — a {@link ToolContract} that runs a command\n * line through the policy-enforced {@link WorkspaceOps} layer.\n *\n * Every command in the line is checked against the shell policy by\n * `ops.exec`; a refused line throws a `WorkspacePolicyError` (with a\n * `reason` and a message that says how to fix the command) which the\n * `tool()` runtime catches and surfaces in the result's `error` field\n * (never a thrown run-killer), so the agent reads the refusal as tool data\n * and self-corrects. A command that runs but exits non-zero is *not* an\n * error — its `exitCode`/`stderr` come back in `data` for the agent to\n * inspect.\n *\n * The agent run's cancellation `signal` (from the dispatch `ctx`) is passed\n * to `ops.exec` per invocation: a cancelled run never starts the command,\n * and one cancelled mid-command kills its process tree (`cancelled: true`).\n * A background command (`background: true`, when enabled) belongs to the\n * workspace instead and keeps running after the call returns.\n *\n * @param ops - The policy-enforced operation layer to delegate `exec` to.\n * @param options - Tool-name override, timeout cap and background support.\n *\n * @example\n * const runShell = makeRunShellTool(ops);\n * const { data, error } = await runShell.invoke({ command: \"npm run build\" });\n * if (error) handleDenied(error);\n * else console.log(data.exitCode, data.stdout);\n */\nexport function makeRunShellTool(\n ops: WorkspaceOps,\n options?: MakeRunShellToolOptions & { background?: false },\n): ToolContract<RunShellInput, RunShellResult>;\nexport function makeRunShellTool(\n ops: WorkspaceOps,\n options: MakeRunShellToolOptions & { background: true },\n): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;\nexport function makeRunShellTool(\n ops: WorkspaceOps,\n options?: MakeRunShellToolOptions,\n): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;\nexport function makeRunShellTool(\n ops: WorkspaceOps,\n options?: MakeRunShellToolOptions,\n): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult> {\n const background = options?.background === true;\n\n return tool<RunShellInput, RunShellResult | RunShellBackgroundResult>({\n name: options?.name ?? DEFAULT_RUN_SHELL_TOOL_NAME,\n description:\n \"Run a shell command inside the workspace. Every command in it must be \" +\n \"permitted by the shell policy; a refusal explains how to fix the \" +\n \"command. Output is byte-capped and the run is time-limited. A \" +\n \"non-zero exit code is returned as data, not an error.\" +\n (background\n ? \" Pass background: true for a long-running command (dev server, \" +\n \"watcher): it returns an id at once; read its output with \" +\n \"shell_output and stop it with shell_kill.\"\n : \"\"),\n action: (input) => `Running \\`${input.command}\\``,\n input: runShellInputSchema(background),\n // The run's signal belongs to this one invocation: it is read from the\n // dispatch ctx on every call and never stored on the tool or workspace.\n execute: async (input, ctx) => {\n if (input.background === true) {\n if (!background) {\n throw new WorkspacePolicyError(\n \"Background commands are not enabled for this workspace; run the command without background.\",\n { type: \"denied-command\", reason: \"not-allowed\", command: input.command },\n );\n }\n\n const job = await ops.startShell(\n input.command,\n input.timeoutMs !== undefined ? { timeoutMs: input.timeoutMs } : undefined,\n );\n\n return { ...job, background: true };\n }\n\n const timeoutMs = cappedTimeout(input.timeoutMs, options?.maxTimeoutMs);\n\n return ops.exec(input.command, {\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(ctx?.signal ? { signal: ctx.signal } : {}),\n });\n },\n });\n}\n"],"mappings":";;;;;;;AAaA,MAAM,8BAA8B;;;;;;;;;AAUpC,SAAS,oBAAoB,YAAsD;CAgDjF,OAAO,eAAe,EA9CpB,aAAa;EACX,SAAS;EACT,QAAQ;EACR,WAAW,UAAU;GACnB,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,qBAAqB,CAAC,EAAE;GAGvD,MAAM,YAAY;GAElB,IAAI,OAAO,UAAU,YAAY,YAAY,UAAU,QAAQ,WAAW,GACxE,OAAO,EACL,QAAQ,CAAC;IAAE,SAAS;IAAsC,MAAM,CAAC,SAAS;GAAE,CAAC,EAC/E;GAGF,IACE,UAAU,cAAc,WACvB,OAAO,UAAU,cAAc,YAAY,UAAU,aAAa,IAEnE,OAAO,EACL,QAAQ,CAAC;IAAE,SAAS;IAAuC,MAAM,CAAC,WAAW;GAAE,CAAC,EAClF;GAGF,IAAI,UAAU,eAAe,UAAa,OAAO,UAAU,eAAe,WACxE,OAAO,EACL,QAAQ,CAAC;IAAE,SAAS;IAAgC,MAAM,CAAC,YAAY;GAAE,CAAC,EAC5E;GAGF,MAAM,SAAwB,EAAE,SAAS,UAAU,QAAQ;GAE3D,IAAI,OAAO,UAAU,cAAc,UACjC,OAAO,YAAY,UAAU;GAG/B,IAAI,UAAU,eAAe,MAC3B,OAAO,aAAa;GAGtB,OAAO,EAAE,OAAO,OAAO;EACzB;CACF,EAGyB,GAAG,mBAAmB,UAAU,CAAC;AAC9D;;AAsBA,SAAS,cAAc,WAA+B,KAA6C;CACjG,IAAI,cAAc,QAChB,OAAO;CAGT,OAAO,QAAQ,SAAY,YAAY,KAAK,IAAI,WAAW,GAAG;AAChE;AA0CA,SAAgB,iBACd,KACA,SACwE;CACxE,MAAM,aAAa,SAAS,eAAe;CAE3C,OAAO,KAA+D;EACpE,MAAM,SAAS,QAAQ;EACvB,aACE,gQAIC,aACG,sKAGA;EACN,SAAS,UAAU,aAAa,MAAM,QAAQ;EAC9C,OAAO,oBAAoB,UAAU;EAGrC,SAAS,OAAO,OAAO,QAAQ;GAC7B,IAAI,MAAM,eAAe,MAAM;IAC7B,IAAI,CAAC,YACH,MAAM,IAAI,qBACR,+FACA;KAAE,MAAM;KAAkB,QAAQ;KAAe,SAAS,MAAM;IAAQ,CAC1E;IAQF,OAAO;KAAE,GAAG,MALM,IAAI,WACpB,MAAM,SACN,MAAM,cAAc,SAAY,EAAE,WAAW,MAAM,UAAU,IAAI,MACnE;KAEiB,YAAY;IAAK;GACpC;GAEA,MAAM,YAAY,cAAc,MAAM,WAAW,SAAS,YAAY;GAEtE,OAAO,IAAI,KAAK,MAAM,SAAS;IAC7B,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;IAC/C,GAAI,KAAK,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;GAC9C,CAAC;EACH;CACF,CAAC;AACH"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { RunShellResult, RunTestsInput } from "../contracts/tool-io.type.mjs";
|
|
2
|
+
import { WorkspaceShellInterpreter } from "../contracts/workspace-policy.type.mjs";
|
|
2
3
|
import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
|
|
3
4
|
import { ToolContract } from "@warlock.js/ai";
|
|
4
5
|
|
|
5
|
-
//#region
|
|
6
|
+
//#region ../../packages/ai-workspace/src/tools/run-tests.d.ts
|
|
6
7
|
/** Options for {@link makeRunTestsTool}. */
|
|
7
8
|
interface MakeRunTestsToolOptions {
|
|
8
9
|
/** Override the tool name exposed to the LLM (default `"run_tests"`). */
|
|
@@ -13,6 +14,13 @@ interface MakeRunTestsToolOptions {
|
|
|
13
14
|
* quoted argument.
|
|
14
15
|
*/
|
|
15
16
|
command?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The workspace's `shell.interpreter`, so the pattern is quoted for the
|
|
19
|
+
* way the line runs: double quotes in argv mode (the default), single
|
|
20
|
+
* quotes for `/bin/sh` (so `$` and backticks in a pattern stay literal),
|
|
21
|
+
* double quotes for cmd.exe.
|
|
22
|
+
*/
|
|
23
|
+
interpreter?: WorkspaceShellInterpreter;
|
|
16
24
|
}
|
|
17
25
|
/**
|
|
18
26
|
* Build the `run_tests` tool — a {@link ToolContract} convenience over
|
|
@@ -27,7 +35,8 @@ interface MakeRunTestsToolOptions {
|
|
|
27
35
|
* data, never a second command. Like `run_shell`, the resolved command's
|
|
28
36
|
* executable is gated by the shell policy — a denial surfaces in the
|
|
29
37
|
* result's `error` field — and a non-zero exit (failing tests) comes back
|
|
30
|
-
* as `data` for the agent to read and fix.
|
|
38
|
+
* as `data` for the agent to read and fix. The agent run's cancellation
|
|
39
|
+
* `signal` is threaded per invocation, exactly as for `run_shell`.
|
|
31
40
|
*
|
|
32
41
|
* @param ops - The policy-enforced operation layer to delegate `exec` to.
|
|
33
42
|
* @param options - Optional tool-name and base-command overrides.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-tests.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"run-tests.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-tests.ts"],"mappings":";;;;;;;UAyEiB,uBAAA;;EAEf,IAAA;;AAFF;;;;EAQE,OAAA;EAAA;;;;AAOuC;AAoCzC;EApCE,WAAA,GAAc,yBAAyB;AAAA;;;;;;;;;;;;;;;;AAuCI;;;;;;;;;iBAH7B,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA,GACT,YAAA,CAAa,aAAA,EAAe,cAAA"}
|
package/esm/tools/run-tests.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { withJsonSchema } from "./schema.mjs";
|
|
2
|
+
import { RUN_TESTS_JSON_SCHEMA } from "./json-schemas.mjs";
|
|
1
3
|
import { tool } from "@warlock.js/ai";
|
|
2
4
|
|
|
3
|
-
//#region
|
|
5
|
+
//#region ../../packages/ai-workspace/src/tools/run-tests.ts
|
|
4
6
|
/** The default tool name `run_tests` is exposed to the LLM under. */
|
|
5
7
|
const DEFAULT_RUN_TESTS_TOOL_NAME = "run_tests";
|
|
6
8
|
/** The default command run when no `command` override is configured. */
|
|
@@ -14,7 +16,7 @@ const DEFAULT_TEST_COMMAND = "npm test";
|
|
|
14
16
|
* happens without a runtime schema dependency, mirroring the wider tool
|
|
15
17
|
* layer.
|
|
16
18
|
*/
|
|
17
|
-
const runTestsInputSchema = { "~standard": {
|
|
19
|
+
const runTestsInputSchema = withJsonSchema({ "~standard": {
|
|
18
20
|
version: 1,
|
|
19
21
|
vendor: "@warlock.js/ai-workspace",
|
|
20
22
|
validate: (value) => {
|
|
@@ -33,7 +35,12 @@ const runTestsInputSchema = { "~standard": {
|
|
|
33
35
|
if (candidate.pattern !== void 0) result.pattern = candidate.pattern;
|
|
34
36
|
return { value: result };
|
|
35
37
|
}
|
|
36
|
-
} };
|
|
38
|
+
} }, RUN_TESTS_JSON_SCHEMA);
|
|
39
|
+
/** Quote the test pattern as one literal argument for the line's interpreter. */
|
|
40
|
+
function quotePattern(pattern, interpreter) {
|
|
41
|
+
if (interpreter === "sh" && process.platform !== "win32") return `'${pattern.replace(/'/g, "'\\''")}'`;
|
|
42
|
+
return `"${pattern}"`;
|
|
43
|
+
}
|
|
37
44
|
/**
|
|
38
45
|
* Build the `run_tests` tool — a {@link ToolContract} convenience over
|
|
39
46
|
* `run_shell` that runs the workspace's configured test command through
|
|
@@ -47,7 +54,8 @@ const runTestsInputSchema = { "~standard": {
|
|
|
47
54
|
* data, never a second command. Like `run_shell`, the resolved command's
|
|
48
55
|
* executable is gated by the shell policy — a denial surfaces in the
|
|
49
56
|
* result's `error` field — and a non-zero exit (failing tests) comes back
|
|
50
|
-
* as `data` for the agent to read and fix.
|
|
57
|
+
* as `data` for the agent to read and fix. The agent run's cancellation
|
|
58
|
+
* `signal` is threaded per invocation, exactly as for `run_shell`.
|
|
51
59
|
*
|
|
52
60
|
* @param ops - The policy-enforced operation layer to delegate `exec` to.
|
|
53
61
|
* @param options - Optional tool-name and base-command overrides.
|
|
@@ -64,9 +72,9 @@ function makeRunTestsTool(ops, options) {
|
|
|
64
72
|
description: "Run the workspace's test suite, optionally narrowed to a path or name pattern forwarded to the test runner. Failing tests return a non-zero exit code as data, not an error.",
|
|
65
73
|
action: (input) => input.pattern ? `Running tests matching "${input.pattern}"` : "Running tests",
|
|
66
74
|
input: runTestsInputSchema,
|
|
67
|
-
execute: (input) => {
|
|
68
|
-
const command = input.pattern ? `${baseCommand}
|
|
69
|
-
return ops.exec(command);
|
|
75
|
+
execute: (input, ctx) => {
|
|
76
|
+
const command = input.pattern ? `${baseCommand} ${quotePattern(input.pattern, options?.interpreter ?? "none")}` : baseCommand;
|
|
77
|
+
return ops.exec(command, ctx?.signal ? { signal: ctx.signal } : void 0);
|
|
70
78
|
}
|
|
71
79
|
});
|
|
72
80
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-tests.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"run-tests.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-tests.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { tool, type ToolContract } from \"@warlock.js/ai\";\nimport type {\n RunShellResult,\n RunTestsInput,\n WorkspaceOps,\n WorkspaceShellInterpreter,\n} from \"../contracts\";\nimport { RUN_TESTS_JSON_SCHEMA } from \"./json-schemas\";\nimport { withJsonSchema } from \"./schema\";\n\n/** The default tool name `run_tests` is exposed to the LLM under. */\nconst DEFAULT_RUN_TESTS_TOOL_NAME = \"run_tests\";\n\n/** The default command run when no `command` override is configured. */\nconst DEFAULT_TEST_COMMAND = \"npm test\";\n\n/**\n * Hand-rolled Standard Schema for {@link RunTestsInput}. `pattern` is the\n * only field and is optional; when present it must be a string without\n * double quotes or newlines — the pattern is forwarded to the runner as a\n * single double-quoted argument, and those characters would break out of\n * the quoting (i.e. inject extra arguments or commands). Validation\n * happens without a runtime schema dependency, mirroring the wider tool\n * layer.\n */\nconst runTestsInputSchema: StandardSchemaV1<RunTestsInput> = withJsonSchema<RunTestsInput>(\n {\n \"~standard\": {\n version: 1,\n vendor: \"@warlock.js/ai-workspace\",\n validate: (value) => {\n // A no-argument call (the common case) is valid and runs the bare\n // test command.\n if (value === undefined || value === null) {\n return { value: {} };\n }\n\n if (typeof value !== \"object\") {\n return { issues: [{ message: \"expected an object\" }] };\n }\n\n const candidate = value as Record<string, unknown>;\n\n if (candidate.pattern !== undefined && typeof candidate.pattern !== \"string\") {\n return { issues: [{ message: \"pattern must be a string\", path: [\"pattern\"] }] };\n }\n\n if (typeof candidate.pattern === \"string\" && /[\"\\r\\n]/.test(candidate.pattern)) {\n return {\n issues: [\n {\n message: \"pattern must not contain double quotes or newlines\",\n path: [\"pattern\"],\n },\n ],\n };\n }\n\n const result: RunTestsInput = {};\n\n if (candidate.pattern !== undefined) {\n result.pattern = candidate.pattern as string;\n }\n\n return { value: result };\n },\n },\n },\n RUN_TESTS_JSON_SCHEMA,\n);\n\n/** Options for {@link makeRunTestsTool}. */\nexport interface MakeRunTestsToolOptions {\n /** Override the tool name exposed to the LLM (default `\"run_tests\"`). */\n name?: string;\n /**\n * The base test command to run (default `\"npm test\"`). When the model\n * supplies a `pattern`, it is appended to this command as a single\n * quoted argument.\n */\n command?: string;\n /**\n * The workspace's `shell.interpreter`, so the pattern is quoted for the\n * way the line runs: double quotes in argv mode (the default), single\n * quotes for `/bin/sh` (so `$` and backticks in a pattern stay literal),\n * double quotes for cmd.exe.\n */\n interpreter?: WorkspaceShellInterpreter;\n}\n\n/** Quote the test pattern as one literal argument for the line's interpreter. */\nfunction quotePattern(pattern: string, interpreter: WorkspaceShellInterpreter): string {\n if (interpreter === \"sh\" && process.platform !== \"win32\") {\n return `'${pattern.replace(/'/g, \"'\\\\''\")}'`;\n }\n\n return `\"${pattern}\"`;\n}\n\n/**\n * Build the `run_tests` tool — a {@link ToolContract} convenience over\n * `run_shell` that runs the workspace's configured test command through\n * the policy-enforced {@link WorkspaceOps} layer.\n *\n * The base command defaults to `\"npm test\"` and can be overridden via\n * `options.command`. When the model passes a `pattern`, it is appended to\n * the command as a **single quoted argument** — a path/suite filter the\n * tokenizer hands to the runner as one argv element (e.g.\n * `npm test \"src/cart\"`), so shell metacharacters inside it are literal\n * data, never a second command. Like `run_shell`, the resolved command's\n * executable is gated by the shell policy — a denial surfaces in the\n * result's `error` field — and a non-zero exit (failing tests) comes back\n * as `data` for the agent to read and fix. The agent run's cancellation\n * `signal` is threaded per invocation, exactly as for `run_shell`.\n *\n * @param ops - The policy-enforced operation layer to delegate `exec` to.\n * @param options - Optional tool-name and base-command overrides.\n *\n * @example\n * const runTests = makeRunTestsTool(ops, { command: \"pnpm test\" });\n * const { data } = await runTests.invoke({ pattern: \"cart-total\" });\n * if (data.exitCode !== 0) inspect(data.stderr);\n */\nexport function makeRunTestsTool(\n ops: WorkspaceOps,\n options?: MakeRunTestsToolOptions,\n): ToolContract<RunTestsInput, RunShellResult> {\n const baseCommand = options?.command ?? DEFAULT_TEST_COMMAND;\n\n return tool<RunTestsInput, RunShellResult>({\n name: options?.name ?? DEFAULT_RUN_TESTS_TOOL_NAME,\n description:\n \"Run the workspace's test suite, optionally narrowed to a path or \" +\n \"name pattern forwarded to the test runner. Failing tests return a \" +\n \"non-zero exit code as data, not an error.\",\n action: (input) =>\n input.pattern ? `Running tests matching \"${input.pattern}\"` : \"Running tests\",\n input: runTestsInputSchema,\n execute: (input, ctx) => {\n // The pattern rides as ONE quoted token (double quotes and newlines are\n // rejected by the schema; under /bin/sh it is single-quoted, so `$` and\n // backticks stay literal), so it reaches the runner as a single argv\n // element and can never smuggle in additional commands or arguments.\n const command = input.pattern\n ? `${baseCommand} ${quotePattern(input.pattern, options?.interpreter ?? \"none\")}`\n : baseCommand;\n\n return ops.exec(command, ctx?.signal ? { signal: ctx.signal } : undefined);\n },\n });\n}\n"],"mappings":";;;;;;AAYA,MAAM,8BAA8B;;AAGpC,MAAM,uBAAuB;;;;;;;;;;AAW7B,MAAM,sBAAuD,eAC3D,EACE,aAAa;CACX,SAAS;CACT,QAAQ;CACR,WAAW,UAAU;EAGnB,IAAI,UAAU,UAAa,UAAU,MACnC,OAAO,EAAE,OAAO,CAAC,EAAE;EAGrB,IAAI,OAAO,UAAU,UACnB,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,qBAAqB,CAAC,EAAE;EAGvD,MAAM,YAAY;EAElB,IAAI,UAAU,YAAY,UAAa,OAAO,UAAU,YAAY,UAClE,OAAO,EAAE,QAAQ,CAAC;GAAE,SAAS;GAA4B,MAAM,CAAC,SAAS;EAAE,CAAC,EAAE;EAGhF,IAAI,OAAO,UAAU,YAAY,YAAY,UAAU,KAAK,UAAU,OAAO,GAC3E,OAAO,EACL,QAAQ,CACN;GACE,SAAS;GACT,MAAM,CAAC,SAAS;EAClB,CACF,EACF;EAGF,MAAM,SAAwB,CAAC;EAE/B,IAAI,UAAU,YAAY,QACxB,OAAO,UAAU,UAAU;EAG7B,OAAO,EAAE,OAAO,OAAO;CACzB;AACF,EACF,GACA,qBACF;;AAsBA,SAAS,aAAa,SAAiB,aAAgD;CACrF,IAAI,gBAAgB,QAAQ,QAAQ,aAAa,SAC/C,OAAO,IAAI,QAAQ,QAAQ,MAAM,OAAO,EAAE;CAG5C,OAAO,IAAI,QAAQ;AACrB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,iBACd,KACA,SAC6C;CAC7C,MAAM,cAAc,SAAS,WAAW;CAExC,OAAO,KAAoC;EACzC,MAAM,SAAS,QAAQ;EACvB,aACE;EAGF,SAAS,UACP,MAAM,UAAU,2BAA2B,MAAM,QAAQ,KAAK;EAChE,OAAO;EACP,UAAU,OAAO,QAAQ;GAKvB,MAAM,UAAU,MAAM,UAClB,GAAG,YAAY,GAAG,aAAa,MAAM,SAAS,SAAS,eAAe,MAAM,MAC5E;GAEJ,OAAO,IAAI,KAAK,SAAS,KAAK,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,MAAS;EAC3E;CACF,CAAC;AACH"}
|
package/esm/tools/schema.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region
|
|
1
|
+
//#region ../../packages/ai-workspace/src/tools/schema.ts
|
|
2
2
|
/**
|
|
3
3
|
* Tiny, dependency-free [Standard Schema](https://standardschema.dev)
|
|
4
4
|
* builders for the workspace tools' input validation. The package pins
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
*/
|
|
16
16
|
/** The vendor tag stamped on every issue these builders produce. */
|
|
17
17
|
const VENDOR = "ai-workspace";
|
|
18
|
+
/** Attach a JSON Schema description to a hand-rolled Standard Schema. */
|
|
19
|
+
function withJsonSchema(schema, jsonSchema) {
|
|
20
|
+
return Object.assign(schema, { jsonSchema });
|
|
21
|
+
}
|
|
18
22
|
/** Required string field — rejects anything that is not a string. */
|
|
19
23
|
function stringField() {
|
|
20
24
|
return (value, key) => {
|
|
@@ -65,24 +69,25 @@ function optionalBooleanField() {
|
|
|
65
69
|
};
|
|
66
70
|
}
|
|
67
71
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* object; each declared field is validated and the (possibly coerced)
|
|
71
|
-
* values are collected into the typed result. All field issues are merged
|
|
72
|
-
* so the caller sees every problem at once.
|
|
73
|
-
*
|
|
74
|
-
* `T` is constrained to `object` rather than `Record<string, unknown>` so
|
|
75
|
-
* the tool IO `interface`s (which carry no implicit string index
|
|
76
|
-
* signature) satisfy it directly — only the declared keys in `shape` are
|
|
77
|
-
* ever read, so a string index signature is never required.
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* const schema = objectSchema<{ path: string; limit?: number }>({
|
|
81
|
-
* path: stringField(),
|
|
82
|
-
* limit: optionalNumberField(),
|
|
83
|
-
* });
|
|
72
|
+
* Optional array-of-strings field — accepts `undefined` or an array whose
|
|
73
|
+
* every element is a string (at most `maxItems` of them).
|
|
84
74
|
*/
|
|
85
|
-
function
|
|
75
|
+
function optionalStringArrayField(maxItems = 50) {
|
|
76
|
+
return (value, key) => {
|
|
77
|
+
if (value === void 0) return { value: void 0 };
|
|
78
|
+
if (Array.isArray(value) && value.length <= maxItems && value.every((item) => typeof item === "string")) return { value };
|
|
79
|
+
return { issues: [{
|
|
80
|
+
message: `"${key}" must be an array of at most ${maxItems} strings when provided`,
|
|
81
|
+
path: [key]
|
|
82
|
+
}] };
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function objectSchema(shape, jsonSchema) {
|
|
86
|
+
const schema = buildObjectSchema(shape);
|
|
87
|
+
return jsonSchema === void 0 ? schema : withJsonSchema(schema, jsonSchema);
|
|
88
|
+
}
|
|
89
|
+
/** The validator behind {@link objectSchema}. */
|
|
90
|
+
function buildObjectSchema(shape) {
|
|
86
91
|
return { "~standard": {
|
|
87
92
|
version: 1,
|
|
88
93
|
vendor: VENDOR,
|
|
@@ -107,5 +112,5 @@ function objectSchema(shape) {
|
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
//#endregion
|
|
110
|
-
export { objectSchema, optionalBooleanField, optionalNumberField, optionalStringField, stringField };
|
|
115
|
+
export { objectSchema, optionalBooleanField, optionalNumberField, optionalStringArrayField, optionalStringField, stringField, withJsonSchema };
|
|
111
116
|
//# sourceMappingURL=schema.mjs.map
|
package/esm/tools/schema.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"schema.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/schema.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Tiny, dependency-free [Standard Schema](https://standardschema.dev)\n * builders for the workspace tools' input validation. The package pins\n * only `@warlock.js/ai` and `@warlock.js/fs` as runtime dependencies, so\n * rather than pull in a schema library we hand-roll the few shapes the\n * file tools need — exactly the pattern `@warlock.js/ai`'s own `tool()`\n * tests use. Each builder returns a `StandardSchemaV1`, which is what\n * `tool({ input })` validates against before calling `execute`.\n *\n * These intentionally cover only the primitive cases the FILE tools\n * require (`string`, `optional string`, `optional number`, `optional\n * boolean`, and an `object` of fields). They are not a general-purpose\n * validator.\n */\n\n/** The vendor tag stamped on every issue these builders produce. */\nconst VENDOR = \"ai-workspace\";\n\n/** A JSON Schema object, as providers send it with a tool definition. */\nexport type JsonSchemaObject = Record<string, unknown>;\n\n/**\n * A Standard Schema that also carries the JSON Schema of its input as a\n * top-level `jsonSchema` property — the property `@warlock.js/ai`'s\n * `extractJsonSchema` reads — so providers send the model the real\n * parameter shape instead of a bare `{ type: \"object\" }`.\n */\nexport type JsonStandardSchema<T> = StandardSchemaV1<T> & { jsonSchema: JsonSchemaObject };\n\n/** Attach a JSON Schema description to a hand-rolled Standard Schema. */\nexport function withJsonSchema<T>(\n schema: StandardSchemaV1<T>,\n jsonSchema: JsonSchemaObject,\n): JsonStandardSchema<T> {\n return Object.assign(schema, { jsonSchema });\n}\n\n/**\n * A single field validator inside {@link objectSchema}: given a value,\n * return either the coerced value or a list of issues. Field validators\n * receive the raw property and the property name (for issue messages).\n */\nexport type FieldValidator<T> = (\n value: unknown,\n key: string,\n) => { value: T } | { issues: StandardSchemaV1.Issue[] };\n\n/** Required string field — rejects anything that is not a string. */\nexport function stringField(): FieldValidator<string> {\n return (value, key) => {\n if (typeof value === \"string\") {\n return { value };\n }\n\n return { issues: [{ message: `\"${key}\" must be a string`, path: [key] }] };\n };\n}\n\n/**\n * Optional string field — accepts `undefined` (the property absent or\n * explicitly undefined) or a string, and rejects every other type.\n */\nexport function optionalStringField(): FieldValidator<string | undefined> {\n return (value, key) => {\n if (value === undefined) {\n return { value: undefined };\n }\n\n if (typeof value === \"string\") {\n return { value };\n }\n\n return {\n issues: [{ message: `\"${key}\" must be a string when provided`, path: [key] }],\n };\n };\n}\n\n/**\n * Optional finite-number field — accepts `undefined` or a finite number,\n * rejecting `NaN`/`Infinity` and non-number types.\n */\nexport function optionalNumberField(): FieldValidator<number | undefined> {\n return (value, key) => {\n if (value === undefined) {\n return { value: undefined };\n }\n\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return { value };\n }\n\n return {\n issues: [{ message: `\"${key}\" must be a finite number when provided`, path: [key] }],\n };\n };\n}\n\n/** Optional boolean field — accepts `undefined` or a boolean. */\nexport function optionalBooleanField(): FieldValidator<boolean | undefined> {\n return (value, key) => {\n if (value === undefined) {\n return { value: undefined };\n }\n\n if (typeof value === \"boolean\") {\n return { value };\n }\n\n return {\n issues: [{ message: `\"${key}\" must be a boolean when provided`, path: [key] }],\n };\n };\n}\n\n/**\n * Optional array-of-strings field — accepts `undefined` or an array whose\n * every element is a string (at most `maxItems` of them).\n */\nexport function optionalStringArrayField(maxItems = 50): FieldValidator<string[] | undefined> {\n return (value, key) => {\n if (value === undefined) {\n return { value: undefined };\n }\n\n if (\n Array.isArray(value) &&\n value.length <= maxItems &&\n value.every((item) => typeof item === \"string\")\n ) {\n return { value: value as string[] };\n }\n\n return {\n issues: [\n {\n message: `\"${key}\" must be an array of at most ${maxItems} strings when provided`,\n path: [key],\n },\n ],\n };\n };\n}\n\n/** The per-key field validator map describing an object schema's shape. */\ntype ObjectShape<T> = {\n [K in keyof T]-?: FieldValidator<T[K]>;\n};\n\n/**\n * Build a {@link StandardSchemaV1} for a flat object whose every property\n * is validated by a {@link FieldValidator}. The input must be a non-null\n * object; each declared field is validated and the (possibly coerced)\n * values are collected into the typed result. All field issues are merged\n * so the caller sees every problem at once.\n *\n * `T` is constrained to `object` rather than `Record<string, unknown>` so\n * the tool IO `interface`s (which carry no implicit string index\n * signature) satisfy it directly — only the declared keys in `shape` are\n * ever read, so a string index signature is never required.\n *\n * @example\n * const schema = objectSchema<{ path: string; limit?: number }>({\n * path: stringField(),\n * limit: optionalNumberField(),\n * });\n */\nexport function objectSchema<T extends object>(shape: ObjectShape<T>): StandardSchemaV1<T>;\nexport function objectSchema<T extends object>(\n shape: ObjectShape<T>,\n jsonSchema: JsonSchemaObject,\n): JsonStandardSchema<T>;\nexport function objectSchema<T extends object>(\n shape: ObjectShape<T>,\n jsonSchema?: JsonSchemaObject,\n): StandardSchemaV1<T> {\n const schema = buildObjectSchema(shape);\n\n return jsonSchema === undefined ? schema : withJsonSchema(schema, jsonSchema);\n}\n\n/** The validator behind {@link objectSchema}. */\nfunction buildObjectSchema<T extends object>(shape: ObjectShape<T>): StandardSchemaV1<T> {\n return {\n \"~standard\": {\n version: 1,\n vendor: VENDOR,\n validate(input) {\n if (typeof input !== \"object\" || input === null || Array.isArray(input)) {\n return { issues: [{ message: \"input must be an object\" }] };\n }\n\n const source = input as Record<string, unknown>;\n const issues: StandardSchemaV1.Issue[] = [];\n const result: Record<string, unknown> = {};\n\n for (const key of Object.keys(shape) as (keyof T)[]) {\n const field = shape[key];\n const outcome = field(source[key as string], key as string);\n\n if (\"issues\" in outcome) {\n issues.push(...outcome.issues);\n\n continue;\n }\n\n // Only carry through keys that resolved to a defined value, so\n // optional-absent fields stay absent rather than becoming\n // explicit `undefined` properties.\n if (outcome.value !== undefined) {\n result[key as string] = outcome.value;\n }\n }\n\n if (issues.length > 0) {\n return { issues };\n }\n\n return { value: result as T };\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAM,SAAS;;AAcf,SAAgB,eACd,QACA,YACuB;CACvB,OAAO,OAAO,OAAO,QAAQ,EAAE,WAAW,CAAC;AAC7C;;AAaA,SAAgB,cAAsC;CACpD,QAAQ,OAAO,QAAQ;EACrB,IAAI,OAAO,UAAU,UACnB,OAAO,EAAE,MAAM;EAGjB,OAAO,EAAE,QAAQ,CAAC;GAAE,SAAS,IAAI,IAAI;GAAqB,MAAM,CAAC,GAAG;EAAE,CAAC,EAAE;CAC3E;AACF;;;;;AAMA,SAAgB,sBAA0D;CACxE,QAAQ,OAAO,QAAQ;EACrB,IAAI,UAAU,QACZ,OAAO,EAAE,OAAO,OAAU;EAG5B,IAAI,OAAO,UAAU,UACnB,OAAO,EAAE,MAAM;EAGjB,OAAO,EACL,QAAQ,CAAC;GAAE,SAAS,IAAI,IAAI;GAAmC,MAAM,CAAC,GAAG;EAAE,CAAC,EAC9E;CACF;AACF;;;;;AAMA,SAAgB,sBAA0D;CACxE,QAAQ,OAAO,QAAQ;EACrB,IAAI,UAAU,QACZ,OAAO,EAAE,OAAO,OAAU;EAG5B,IAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GACpD,OAAO,EAAE,MAAM;EAGjB,OAAO,EACL,QAAQ,CAAC;GAAE,SAAS,IAAI,IAAI;GAA0C,MAAM,CAAC,GAAG;EAAE,CAAC,EACrF;CACF;AACF;;AAGA,SAAgB,uBAA4D;CAC1E,QAAQ,OAAO,QAAQ;EACrB,IAAI,UAAU,QACZ,OAAO,EAAE,OAAO,OAAU;EAG5B,IAAI,OAAO,UAAU,WACnB,OAAO,EAAE,MAAM;EAGjB,OAAO,EACL,QAAQ,CAAC;GAAE,SAAS,IAAI,IAAI;GAAoC,MAAM,CAAC,GAAG;EAAE,CAAC,EAC/E;CACF;AACF;;;;;AAMA,SAAgB,yBAAyB,WAAW,IAA0C;CAC5F,QAAQ,OAAO,QAAQ;EACrB,IAAI,UAAU,QACZ,OAAO,EAAE,OAAO,OAAU;EAG5B,IACE,MAAM,QAAQ,KAAK,KACnB,MAAM,UAAU,YAChB,MAAM,OAAO,SAAS,OAAO,SAAS,QAAQ,GAE9C,OAAO,EAAS,MAAkB;EAGpC,OAAO,EACL,QAAQ,CACN;GACE,SAAS,IAAI,IAAI,gCAAgC,SAAS;GAC1D,MAAM,CAAC,GAAG;EACZ,CACF,EACF;CACF;AACF;AA8BA,SAAgB,aACd,OACA,YACqB;CACrB,MAAM,SAAS,kBAAkB,KAAK;CAEtC,OAAO,eAAe,SAAY,SAAS,eAAe,QAAQ,UAAU;AAC9E;;AAGA,SAAS,kBAAoC,OAA4C;CACvF,OAAO,EACL,aAAa;EACX,SAAS;EACT,QAAQ;EACR,SAAS,OAAO;GACd,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACpE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,0BAA0B,CAAC,EAAE;GAG5D,MAAM,SAAS;GACf,MAAM,SAAmC,CAAC;GAC1C,MAAM,SAAkC,CAAC;GAEzC,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAAkB;IACnD,MAAM,QAAQ,MAAM;IACpB,MAAM,UAAU,MAAM,OAAO,MAAgB,GAAa;IAE1D,IAAI,YAAY,SAAS;KACvB,OAAO,KAAK,GAAG,QAAQ,MAAM;KAE7B;IACF;IAKA,IAAI,QAAQ,UAAU,QACpB,OAAO,OAAiB,QAAQ;GAEpC;GAEA,IAAI,OAAO,SAAS,GAClB,OAAO,EAAE,OAAO;GAGlB,OAAO,EAAE,OAAO,OAAY;EAC9B;CACF,EACF;AACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ShellJobInfo, ShellKillInput } from "../contracts/tool-io.type.mjs";
|
|
2
|
+
import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
|
|
3
|
+
import { ToolContract } from "@warlock.js/ai";
|
|
4
|
+
|
|
5
|
+
//#region ../../packages/ai-workspace/src/tools/shell-kill.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Build the agent-facing `shell_kill` tool: stop a background command
|
|
8
|
+
* started with `run_shell({ background: true })`, killing its whole process
|
|
9
|
+
* tree, and return its final state. Killing a command that already stopped
|
|
10
|
+
* just reports its state. An unknown id surfaces as a `WorkspaceJobError`
|
|
11
|
+
* in the result's `error` field.
|
|
12
|
+
*
|
|
13
|
+
* @param ops - The shared, policy-enforced operation layer.
|
|
14
|
+
* @param options - Optional overrides; `name` renames the LLM-visible tool.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const { data } = await makeShellKillTool(ops).invoke({ id: "job-1" });
|
|
18
|
+
* console.log(data?.status); // "killed"
|
|
19
|
+
*/
|
|
20
|
+
declare function makeShellKillTool(ops: WorkspaceOps, options?: {
|
|
21
|
+
name?: string;
|
|
22
|
+
}): ToolContract<ShellKillInput, ShellJobInfo>;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { makeShellKillTool };
|
|
25
|
+
//# sourceMappingURL=shell-kill.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-kill.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/shell-kill.ts"],"mappings":";;;;;;;;;AAyBA;;;;;;;;;;iBAAgB,iBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,cAAA,EAAgB,YAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { objectSchema, stringField } from "./schema.mjs";
|
|
2
|
+
import { SHELL_KILL_JSON_SCHEMA } from "./json-schemas.mjs";
|
|
3
|
+
import { tool } from "@warlock.js/ai";
|
|
4
|
+
|
|
5
|
+
//#region ../../packages/ai-workspace/src/tools/shell-kill.ts
|
|
6
|
+
/** Default tool name exposed to the LLM. */
|
|
7
|
+
const DEFAULT_NAME = "shell_kill";
|
|
8
|
+
/** Input schema for the `shell_kill` tool. */
|
|
9
|
+
const inputSchema = objectSchema({ id: stringField() }, SHELL_KILL_JSON_SCHEMA);
|
|
10
|
+
/**
|
|
11
|
+
* Build the agent-facing `shell_kill` tool: stop a background command
|
|
12
|
+
* started with `run_shell({ background: true })`, killing its whole process
|
|
13
|
+
* tree, and return its final state. Killing a command that already stopped
|
|
14
|
+
* just reports its state. An unknown id surfaces as a `WorkspaceJobError`
|
|
15
|
+
* in the result's `error` field.
|
|
16
|
+
*
|
|
17
|
+
* @param ops - The shared, policy-enforced operation layer.
|
|
18
|
+
* @param options - Optional overrides; `name` renames the LLM-visible tool.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const { data } = await makeShellKillTool(ops).invoke({ id: "job-1" });
|
|
22
|
+
* console.log(data?.status); // "killed"
|
|
23
|
+
*/
|
|
24
|
+
function makeShellKillTool(ops, options) {
|
|
25
|
+
return tool({
|
|
26
|
+
name: options?.name ?? DEFAULT_NAME,
|
|
27
|
+
description: "Stop a background command started with run_shell (background: true), killing it and everything it started. Returns its final state.",
|
|
28
|
+
action: (input) => `Stopping ${typeof input.id === "string" ? input.id : "a background command"}`,
|
|
29
|
+
input: inputSchema,
|
|
30
|
+
execute: (input) => ops.shellKill(input.id)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { makeShellKillTool };
|
|
36
|
+
//# sourceMappingURL=shell-kill.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-kill.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/shell-kill.ts"],"sourcesContent":["import { tool, type ToolContract } from \"@warlock.js/ai\";\nimport type { ShellJobInfo, ShellKillInput, WorkspaceOps } from \"../contracts\";\nimport { SHELL_KILL_JSON_SCHEMA } from \"./json-schemas\";\nimport { objectSchema, stringField } from \"./schema\";\n\n/** Default tool name exposed to the LLM. */\nconst DEFAULT_NAME = \"shell_kill\";\n\n/** Input schema for the `shell_kill` tool. */\nconst inputSchema = objectSchema<ShellKillInput>({ id: stringField() }, SHELL_KILL_JSON_SCHEMA);\n\n/**\n * Build the agent-facing `shell_kill` tool: stop a background command\n * started with `run_shell({ background: true })`, killing its whole process\n * tree, and return its final state. Killing a command that already stopped\n * just reports its state. An unknown id surfaces as a `WorkspaceJobError`\n * in the result's `error` field.\n *\n * @param ops - The shared, policy-enforced operation layer.\n * @param options - Optional overrides; `name` renames the LLM-visible tool.\n *\n * @example\n * const { data } = await makeShellKillTool(ops).invoke({ id: \"job-1\" });\n * console.log(data?.status); // \"killed\"\n */\nexport function makeShellKillTool(\n ops: WorkspaceOps,\n options?: { name?: string },\n): ToolContract<ShellKillInput, ShellJobInfo> {\n return tool<ShellKillInput, ShellJobInfo>({\n name: options?.name ?? DEFAULT_NAME,\n description:\n \"Stop a background command started with run_shell (background: true), \" +\n \"killing it and everything it started. Returns its final state.\",\n action: (input) =>\n `Stopping ${typeof input.id === \"string\" ? input.id : \"a background command\"}`,\n input: inputSchema,\n execute: (input) => ops.shellKill(input.id),\n });\n}\n"],"mappings":";;;;;;AAMA,MAAM,eAAe;;AAGrB,MAAM,cAAc,aAA6B,EAAE,IAAI,YAAY,EAAE,GAAG,sBAAsB;;;;;;;;;;;;;;;AAgB9F,SAAgB,kBACd,KACA,SAC4C;CAC5C,OAAO,KAAmC;EACxC,MAAM,SAAS,QAAQ;EACvB,aACE;EAEF,SAAS,UACP,YAAY,OAAO,MAAM,OAAO,WAAW,MAAM,KAAK;EACxD,OAAO;EACP,UAAU,UAAU,IAAI,UAAU,MAAM,EAAE;CAC5C,CAAC;AACH"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ShellOutputInput, ShellOutputResult } from "../contracts/tool-io.type.mjs";
|
|
2
|
+
import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
|
|
3
|
+
import { ToolContract } from "@warlock.js/ai";
|
|
4
|
+
|
|
5
|
+
//#region ../../packages/ai-workspace/src/tools/shell-output.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Build the agent-facing `shell_output` tool: the new output of a
|
|
8
|
+
* background command started with `run_shell({ background: true })`, plus
|
|
9
|
+
* its state (`running` / `exited` / `killed` / `timed-out`, `exitCode`).
|
|
10
|
+
*
|
|
11
|
+
* Without `since` it returns everything produced since the previous read;
|
|
12
|
+
* `cursor` in the result is the position to pass as `since` next time.
|
|
13
|
+
* `waitMs` (at most 30 s) waits for new output or for the command to stop
|
|
14
|
+
* when there is nothing new yet — the agent run's signal ends the wait
|
|
15
|
+
* early. Only the newest `shell.maxOutputBytes` of a command's output are
|
|
16
|
+
* kept; `droppedBytes` says how much the reader missed.
|
|
17
|
+
*
|
|
18
|
+
* @param ops - The shared, policy-enforced operation layer.
|
|
19
|
+
* @param options - Optional overrides; `name` renames the LLM-visible tool.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const { data } = await makeShellOutputTool(ops).invoke({ id: "job-1", waitMs: 2_000 });
|
|
23
|
+
* if (data?.stdout.includes("ready")) console.log("dev server is up");
|
|
24
|
+
*/
|
|
25
|
+
declare function makeShellOutputTool(ops: WorkspaceOps, options?: {
|
|
26
|
+
name?: string;
|
|
27
|
+
}): ToolContract<ShellOutputInput, ShellOutputResult>;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { makeShellOutputTool };
|
|
30
|
+
//# sourceMappingURL=shell-output.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-output.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/shell-output.ts"],"mappings":";;;;;;;;;AAqCA;;;;;;;;;;;;;;;iBAAgB,mBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,gBAAA,EAAkB,iBAAA"}
|