toolcraft 0.0.384 → 0.0.386

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 CHANGED
@@ -33,7 +33,7 @@ const result = await shell.exec("tools list-users --limit 10 --output json");
33
33
  await shell.dispose();
34
34
  ```
35
35
 
36
- Each root name and alias becomes a virtual command. Nested groups, command aliases,
36
+ Each root name, its kebab-case spelling and aliases become virtual commands. Nested groups, command aliases,
37
37
  default commands, positional arguments, schema defaults, scalar/enum/array/object/
38
38
  record/union inputs and CLI scope filtering reuse Toolcraft's CLI parser. Hidden
39
39
  commands are excluded from this surface. Standalone CLI behavior remains unchanged.
@@ -102,7 +102,11 @@ or overlay filesystem. Library services combine with invocation services, with
102
102
  invocation-owned services taking precedence on name collisions. Runtime capability
103
103
  names are reserved and cannot be replaced through services. Explicitly revoking
104
104
  `humanInLoop` also disables a library-configured approval provider.
105
- Schema pattern validation currently follows Toolcraft's existing validator.
105
+ Schema `pattern` and `patternProperties` validation is unsupported in this native
106
+ surface: registration rejects these keywords in parameter and stream-event schemas,
107
+ including nested JSON Schema definitions, instead of using the host regex engine.
108
+ Tools that need regex work can use the injected bounded provider in their handlers.
109
+ CLI-excluded roots are also inaccessible through the public command executor.
106
110
 
107
111
  ## What the owner decides
108
112
 
package/composition.json CHANGED
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.384",
116
+ "version": "0.0.386",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.384",
126
+ "version": "0.0.386",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.384",
116
+ "version": "0.0.386",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.384",
126
+ "version": "0.0.386",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
package/dist/safe-bash.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { cloneDefaultValue, validate } from "toolcraft-schema";
2
+ import { cloneDefaultValue, toJsonSchema, validate } from "toolcraft-schema";
3
3
  import { executeCLICommand, formatCLIName } from "./cli.js";
4
4
  import { validateServices } from "./runtime/io.js";
5
5
  /** Checks paths, parameter names and values against a library's inferred definitions. */
@@ -79,11 +79,42 @@ function handlerFileSystem(invocation) {
79
79
  }
80
80
  };
81
81
  }
82
+ function assertNativeSchema(schema, commandPath) {
83
+ if (schema === null || typeof schema !== "object" || Array.isArray(schema))
84
+ return;
85
+ const document = schema;
86
+ if (document.pattern !== undefined || document.patternProperties !== undefined) {
87
+ throw new TypeError(`Schema regex validation is unsupported in native Toolcraft commands: ${commandPath}; use the invocation's bounded regex capability in the handler`);
88
+ }
89
+ // Visit schema positions only: parameter names and literal defaults are not keywords.
90
+ for (const key of ["properties", "$defs", "definitions", "dependentSchemas", "dependencies"]) {
91
+ const map = document[key];
92
+ if (map !== null && typeof map === "object" && !Array.isArray(map)) {
93
+ for (const child of Object.values(map))
94
+ assertNativeSchema(child, commandPath);
95
+ }
96
+ }
97
+ for (const key of ["allOf", "anyOf", "oneOf", "prefixItems", "items", "additionalItems", "additionalProperties", "contains", "if", "then", "else", "not", "propertyNames", "unevaluatedItems", "unevaluatedProperties"]) {
98
+ const child = document[key];
99
+ if (Array.isArray(child)) {
100
+ for (const item of child)
101
+ assertNativeSchema(item, commandPath);
102
+ }
103
+ else
104
+ assertNativeSchema(child, commandPath);
105
+ }
106
+ }
82
107
  /** Executes already-tokenized argv in process, using the same parser and dispatch as runCLI. */
83
108
  export function createToolcraftCommandExecutor(library, options = {}) {
84
- const roots = Array.isArray(library) ? library : [library];
109
+ const roots = (Array.isArray(library) ? library : [library])
110
+ .filter(root => !root.scope || root.scope.includes("cli"));
85
111
  const multiple = Array.isArray(library);
86
112
  const commands = new Map(roots.flatMap(root => [...discoverCommands(root, multiple ? `${root.name}/` : "")]));
113
+ for (const [commandPath, command] of commands) {
114
+ assertNativeSchema(toJsonSchema(command.params), commandPath);
115
+ if (command.stream)
116
+ assertNativeSchema(toJsonSchema(command.stream.event), commandPath);
117
+ }
87
118
  const defaults = cloneDefaultValue(options.defaults ?? {});
88
119
  for (const [commandPath, values] of Object.entries(defaults)) {
89
120
  const command = commands.get(commandPath);
@@ -108,7 +139,7 @@ export function createToolcraftCommandExecutor(library, options = {}) {
108
139
  const configuredServices = typeof options.services === "function" ? options.services(invocation) : options.services;
109
140
  services = { ...configuredServices, ...invocation.services };
110
141
  const rootName = multiple ? argv[0] : roots[0]?.name;
111
- const selectedRoot = multiple ? roots.find(candidate => candidate.name === rootName || candidate.aliases.includes(rootName ?? "")) : roots[0];
142
+ const selectedRoot = multiple ? roots.find(candidate => candidate.name === rootName || formatCLIName(candidate.name, "kebab") === rootName || candidate.aliases.includes(rootName ?? "")) : roots[0];
112
143
  if (!selectedRoot)
113
144
  throw new TypeError(`Unknown toolcraft root: ${rootName}`);
114
145
  root = selectedRoot;
@@ -173,7 +204,7 @@ export function toolcraftCommands(library, options = {}) {
173
204
  for (const root of roots) {
174
205
  if (root.scope && !root.scope.includes("cli"))
175
206
  continue;
176
- for (const name of [root.name, ...root.aliases]) {
207
+ for (const name of new Set([root.name, formatCLIName(root.name, "kebab"), ...root.aliases])) {
177
208
  host.commands.register({
178
209
  name,
179
210
  description: root.description,
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.384",
11
+ "version": "0.0.386",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.384",
3
+ "version": "0.0.386",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft",
3
- "version": "0.0.384",
3
+ "version": "0.0.386",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -162,7 +162,7 @@
162
162
  "yaml"
163
163
  ],
164
164
  "optionalDependencies": {
165
- "toolcraft-schema": "0.0.384",
165
+ "toolcraft-schema": "0.0.386",
166
166
  "toolcraft-design": "*",
167
167
  "@poe-code/frontmatter": "*",
168
168
  "@poe-code/agent-mcp-config": "*",