@shardworks/tools-apparatus 0.1.101
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/LICENSE +15 -0
- package/README.md +218 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentarium.d.ts +65 -0
- package/dist/instrumentarium.d.ts.map +1 -0
- package/dist/instrumentarium.js +248 -0
- package/dist/instrumentarium.js.map +1 -0
- package/dist/tool.d.ts +137 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +84 -0
- package/dist/tool.js.map +1 -0
- package/dist/tools/tools-list.d.ts +29 -0
- package/dist/tools/tools-list.d.ts.map +1 -0
- package/dist/tools/tools-list.js +57 -0
- package/dist/tools/tools-list.js.map +1 -0
- package/dist/tools/tools-show.d.ts +30 -0
- package/dist/tools/tools-show.d.ts.map +1 -0
- package/dist/tools/tools-show.js +94 -0
- package/dist/tools/tools-show.js.map +1 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sean Boots
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# `@shardworks/tools-apparatus`
|
|
2
|
+
|
|
3
|
+
The Instrumentarium — the guild's tool registry. This apparatus scans installed tools from kit contributions and apparatus supportKits at startup, resolves permission-gated tool sets on demand, and serves as the single source of truth for "what tools exist and who can use them."
|
|
4
|
+
|
|
5
|
+
Both the CLI and the session layer (The Animator, via MCP) depend on The Instrumentarium to discover available tools. It sits low in the dependency graph — no dependencies on other apparatus.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
@shardworks/tools-apparatus — tool() factory, ToolDefinition type, tool registry, InstrumentariumApi
|
|
9
|
+
@shardworks/nexus (cli) — queries InstrumentariumApi for CLI-callable tools
|
|
10
|
+
kits / apparatus supportKits — contribute ToolDefinition[] via `tools` field
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@shardworks/tools-apparatus": "workspace:*"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Plugin id: `tools`
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## API
|
|
30
|
+
|
|
31
|
+
The Instrumentarium exposes `InstrumentariumApi` via `provides`, accessed by other plugins as:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { guild } from '@shardworks/nexus-core';
|
|
35
|
+
import type { InstrumentariumApi } from '@shardworks/tools-apparatus';
|
|
36
|
+
|
|
37
|
+
const instrumentarium = guild().apparatus<InstrumentariumApi>('tools');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `InstrumentariumApi`
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
interface InstrumentariumApi {
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the tool set for a given set of permissions.
|
|
46
|
+
*
|
|
47
|
+
* Evaluates each registered tool against the permission grants:
|
|
48
|
+
* - Tools with a `permission` field: included if any grant matches
|
|
49
|
+
* - Permissionless tools: always included (default) or gated by `strict`
|
|
50
|
+
* - Channel filtering applied last
|
|
51
|
+
*/
|
|
52
|
+
resolve(options: ResolveOptions): ResolvedTool[];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Find a single tool by name. Returns null if not installed.
|
|
56
|
+
*/
|
|
57
|
+
find(name: string): ResolvedTool | null;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* List all installed tools, regardless of permissions.
|
|
61
|
+
*/
|
|
62
|
+
list(): ResolvedTool[];
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `ResolvedTool`
|
|
67
|
+
|
|
68
|
+
A tool with provenance metadata:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface ResolvedTool {
|
|
72
|
+
/** The tool definition (name, description, params schema, handler). */
|
|
73
|
+
definition: ToolDefinition;
|
|
74
|
+
/** Plugin id of the kit or apparatus that contributed this tool. */
|
|
75
|
+
pluginId: string;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `ResolveOptions`
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
interface ResolveOptions {
|
|
83
|
+
/**
|
|
84
|
+
* Permission grants in `plugin:level` format.
|
|
85
|
+
* Supports wildcards: `plugin:*`, `*:level`, `*:*`.
|
|
86
|
+
*/
|
|
87
|
+
permissions: string[];
|
|
88
|
+
/**
|
|
89
|
+
* When true, permissionless tools are excluded unless the role grants
|
|
90
|
+
* `plugin:*` or `*:*` for the tool's plugin. When false (default),
|
|
91
|
+
* permissionless tools are included unconditionally.
|
|
92
|
+
*/
|
|
93
|
+
strict?: boolean;
|
|
94
|
+
/** Filter by caller type. Tools with no callableBy restriction pass all callers. */
|
|
95
|
+
caller?: ToolCaller;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Usage Examples
|
|
100
|
+
|
|
101
|
+
**Resolve tools for a session (The Loom's use case):**
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// The Loom resolves role → permissions, then asks the Instrumentarium
|
|
105
|
+
const tools = instrumentarium.resolve({
|
|
106
|
+
permissions: ['stdlib:read', 'stdlib:write', 'animator:read'],
|
|
107
|
+
caller: 'anima',
|
|
108
|
+
});
|
|
109
|
+
// → ResolvedTool[] — all anima-callable tools matching those permission grants
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Resolve with strict mode (lock down permissionless tools):**
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const tools = instrumentarium.resolve({
|
|
116
|
+
permissions: ['stdlib:*'],
|
|
117
|
+
strict: true,
|
|
118
|
+
});
|
|
119
|
+
// → Only tools from the stdlib plugin (both permissioned and permissionless)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Find a specific tool:**
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const tool = instrumentarium.find('commission-show');
|
|
126
|
+
if (tool) {
|
|
127
|
+
const result = await tool.definition.handler({ id: 'writ-123' });
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**List everything installed (the CLI's use case):**
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const cliTools = instrumentarium.list()
|
|
135
|
+
.filter(r => !r.definition.callableBy || r.definition.callableBy.includes('cli'))
|
|
136
|
+
.map(r => r.definition);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Permission Model
|
|
142
|
+
|
|
143
|
+
The Instrumentarium is **role-agnostic** — it receives an already-resolved permissions array and returns matching tools. Role definitions and permission grants are owned by the Loom.
|
|
144
|
+
|
|
145
|
+
### How permissions work
|
|
146
|
+
|
|
147
|
+
Each tool may declare a `permission` level (e.g. `'read'`, `'write'`, `'admin'`). Callers provide permission grants in `plugin:level` format:
|
|
148
|
+
|
|
149
|
+
| Grant format | Meaning |
|
|
150
|
+
|---|---|
|
|
151
|
+
| `stdlib:read` | Exact match — grants `read` tools from the `stdlib` plugin |
|
|
152
|
+
| `stdlib:*` | Plugin wildcard — grants all tools from `stdlib` |
|
|
153
|
+
| `*:read` | Level wildcard — grants `read` tools from any plugin |
|
|
154
|
+
| `*:*` | Superuser — grants all tools from all plugins |
|
|
155
|
+
|
|
156
|
+
There is **no permission hierarchy** — `write` does not imply `read`. Each level must be granted explicitly, or use wildcards.
|
|
157
|
+
|
|
158
|
+
### Permissionless tools
|
|
159
|
+
|
|
160
|
+
Tools without a `permission` field are **permissionless**. In default mode, they are always included in resolution results. In `strict` mode, they are excluded unless the caller has `plugin:*` or `*:*` for the tool's plugin.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Kit Interface
|
|
165
|
+
|
|
166
|
+
Kits contribute tools via a `tools` field in their kit export:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { tool } from '@shardworks/tools-apparatus';
|
|
170
|
+
import { z } from 'zod';
|
|
171
|
+
|
|
172
|
+
const showTool = tool({
|
|
173
|
+
name: 'commission-show',
|
|
174
|
+
description: 'Show details of a commission',
|
|
175
|
+
permission: 'read',
|
|
176
|
+
params: {
|
|
177
|
+
id: z.string().describe('Commission id'),
|
|
178
|
+
},
|
|
179
|
+
handler: async ({ id }) => {
|
|
180
|
+
const stacks = guild().apparatus<StacksApi>('stacks');
|
|
181
|
+
const writs = stacks.readBook<Writ>('clerk', 'writs');
|
|
182
|
+
return await writs.get(id);
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
export default {
|
|
187
|
+
kit: {
|
|
188
|
+
requires: ['tools'],
|
|
189
|
+
tools: [showTool],
|
|
190
|
+
},
|
|
191
|
+
} satisfies Plugin;
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Each entry in the `tools` array is a `ToolDefinition` produced by the `tool()` factory. The Instrumentarium scans these contributions at startup via the `plugin:initialized` lifecycle event.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Exports
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// Tool authoring API (canonical home)
|
|
202
|
+
import { tool, type ToolDefinition, type ToolCaller } from '@shardworks/tools-apparatus';
|
|
203
|
+
|
|
204
|
+
// Instrumentarium API
|
|
205
|
+
import {
|
|
206
|
+
type InstrumentariumApi,
|
|
207
|
+
type ResolvedTool,
|
|
208
|
+
type ResolveOptions,
|
|
209
|
+
createInstrumentarium,
|
|
210
|
+
} from '@shardworks/tools-apparatus';
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The default export is the apparatus plugin instance, ready for use in `guild.json`:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import instrumentarium from '@shardworks/tools-apparatus';
|
|
217
|
+
// → Plugin with apparatus.provides = InstrumentariumApi
|
|
218
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @shardworks/tools-apparatus — The Instrumentarium.
|
|
3
|
+
*
|
|
4
|
+
* Guild tool registry: scans kit contributions, resolves permission-gated
|
|
5
|
+
* tool sets, and provides the InstrumentariumApi for tool lookup and resolution.
|
|
6
|
+
*
|
|
7
|
+
* The tool() factory and ToolDefinition type live here canonically.
|
|
8
|
+
*
|
|
9
|
+
* See: docs/specification.md (instrumentarium)
|
|
10
|
+
*/
|
|
11
|
+
export { type ToolCaller, type ToolDefinition, tool, isToolDefinition, } from './tool.ts';
|
|
12
|
+
export { type InstrumentariumApi, type ResolvedTool, type ResolveOptions, } from './instrumentarium.ts';
|
|
13
|
+
declare const _default: import("@shardworks/nexus-core").Plugin;
|
|
14
|
+
export default _default;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EACL,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,IAAI,EACJ,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAInB,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,sBAAsB,CAAC;;AAI9B,wBAAuC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @shardworks/tools-apparatus — The Instrumentarium.
|
|
3
|
+
*
|
|
4
|
+
* Guild tool registry: scans kit contributions, resolves permission-gated
|
|
5
|
+
* tool sets, and provides the InstrumentariumApi for tool lookup and resolution.
|
|
6
|
+
*
|
|
7
|
+
* The tool() factory and ToolDefinition type live here canonically.
|
|
8
|
+
*
|
|
9
|
+
* See: docs/specification.md (instrumentarium)
|
|
10
|
+
*/
|
|
11
|
+
import { createInstrumentarium } from "./instrumentarium.js";
|
|
12
|
+
// ── Tool authoring API ───────────────────────────────────────────────
|
|
13
|
+
export { tool, isToolDefinition, } from "./tool.js";
|
|
14
|
+
// ── Instrumentarium API ───────────────────────────────────────────────
|
|
15
|
+
export {} from "./instrumentarium.js";
|
|
16
|
+
// ── Default export: the apparatus plugin ──────────────────────────────
|
|
17
|
+
export default createInstrumentarium();
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,wEAAwE;AAExE,OAAO,EAGL,IAAI,EACJ,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,yEAAyE;AAEzE,OAAO,EAIN,MAAM,sBAAsB,CAAC;AAE9B,yEAAyE;AAEzE,eAAe,qBAAqB,EAAE,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Instrumentarium — guild tool registry apparatus.
|
|
3
|
+
*
|
|
4
|
+
* Scans installed tools from kit contributions and apparatus supportKits,
|
|
5
|
+
* resolves permission-gated tool sets on demand, and serves as the single
|
|
6
|
+
* source of truth for "what tools exist and who can use them."
|
|
7
|
+
*
|
|
8
|
+
* The Instrumentarium is role-agnostic — it receives an already-resolved
|
|
9
|
+
* permissions array from the Loom and returns the matching tool set.
|
|
10
|
+
* Role definitions and permission grants are owned by the Loom.
|
|
11
|
+
*/
|
|
12
|
+
import type { Plugin } from '@shardworks/nexus-core';
|
|
13
|
+
import type { ToolDefinition, ToolCaller } from './tool.ts';
|
|
14
|
+
/** A resolved tool with provenance metadata. */
|
|
15
|
+
export interface ResolvedTool {
|
|
16
|
+
/** The tool definition (name, description, params schema, handler). */
|
|
17
|
+
definition: ToolDefinition;
|
|
18
|
+
/** Plugin id of the kit or apparatus that contributed this tool. */
|
|
19
|
+
pluginId: string;
|
|
20
|
+
}
|
|
21
|
+
/** Options for resolving a permission-gated tool set. */
|
|
22
|
+
export interface ResolveOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Permission grants in `plugin:level` format.
|
|
25
|
+
* Supports wildcards: `plugin:*`, `*:level`, `*:*`.
|
|
26
|
+
*/
|
|
27
|
+
permissions: string[];
|
|
28
|
+
/**
|
|
29
|
+
* When true, permissionless tools are excluded unless the role grants
|
|
30
|
+
* `plugin:*` or `*:*` for the tool's plugin. When false (default),
|
|
31
|
+
* permissionless tools are included unconditionally.
|
|
32
|
+
*/
|
|
33
|
+
strict?: boolean;
|
|
34
|
+
/** Filter by invocation caller. Tools with no callableBy pass all callers. */
|
|
35
|
+
caller?: ToolCaller;
|
|
36
|
+
}
|
|
37
|
+
/** The Instrumentarium's public API, exposed via `provides`. */
|
|
38
|
+
export interface InstrumentariumApi {
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the tool set for a given set of permissions.
|
|
41
|
+
*
|
|
42
|
+
* Evaluates each registered tool against the permission grants:
|
|
43
|
+
* - Tools with a `permission` field: included if any grant matches
|
|
44
|
+
* - Permissionless tools: always included (default) or gated by `strict`
|
|
45
|
+
* - Caller filtering applied last
|
|
46
|
+
*/
|
|
47
|
+
resolve(options: ResolveOptions): ResolvedTool[];
|
|
48
|
+
/**
|
|
49
|
+
* Find a single tool by name. Returns null if not installed.
|
|
50
|
+
*/
|
|
51
|
+
find(name: string): ResolvedTool | null;
|
|
52
|
+
/**
|
|
53
|
+
* List all installed tools, regardless of permissions.
|
|
54
|
+
*/
|
|
55
|
+
list(): ResolvedTool[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create the Instrumentarium apparatus plugin.
|
|
59
|
+
*
|
|
60
|
+
* Returns a Plugin with:
|
|
61
|
+
* - `consumes: ['tools']` — scans kit/supportKit contributions
|
|
62
|
+
* - `provides: InstrumentariumApi` — the tool registry API
|
|
63
|
+
*/
|
|
64
|
+
export declare function createInstrumentarium(): Plugin;
|
|
65
|
+
//# sourceMappingURL=instrumentarium.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentarium.d.ts","sourceRoot":"","sources":["../src/instrumentarium.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAKV,MAAM,EACP,MAAM,wBAAwB,CAAC;AAOhC,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAO5D,gDAAgD;AAChD,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,UAAU,EAAE,cAAc,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,yDAAyD;AACzD,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,EAAE,CAAC;IAEjD;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;IAExC;;OAEG;IACH,IAAI,IAAI,YAAY,EAAE,CAAC;CACxB;AAkND;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CA8D9C"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Instrumentarium — guild tool registry apparatus.
|
|
3
|
+
*
|
|
4
|
+
* Scans installed tools from kit contributions and apparatus supportKits,
|
|
5
|
+
* resolves permission-gated tool sets on demand, and serves as the single
|
|
6
|
+
* source of truth for "what tools exist and who can use them."
|
|
7
|
+
*
|
|
8
|
+
* The Instrumentarium is role-agnostic — it receives an already-resolved
|
|
9
|
+
* permissions array from the Loom and returns the matching tool set.
|
|
10
|
+
* Role definitions and permission grants are owned by the Loom.
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { guild, isLoadedKit, isLoadedApparatus, } from '@shardworks/nexus-core';
|
|
15
|
+
import { isToolDefinition } from "./tool.js";
|
|
16
|
+
import { createToolsList } from "./tools/tools-list.js";
|
|
17
|
+
import { createToolsShow } from "./tools/tools-show.js";
|
|
18
|
+
/** Parse a grant string like "plugin:level" into its components. */
|
|
19
|
+
function parseGrant(grant) {
|
|
20
|
+
const colonIdx = grant.indexOf(':');
|
|
21
|
+
if (colonIdx === -1)
|
|
22
|
+
return null;
|
|
23
|
+
return {
|
|
24
|
+
plugin: grant.slice(0, colonIdx),
|
|
25
|
+
level: grant.slice(colonIdx + 1),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if a tool with the given permission level from the given plugin
|
|
30
|
+
* is matched by any of the parsed grants.
|
|
31
|
+
*/
|
|
32
|
+
function matchesPermission(pluginId, permission, grants) {
|
|
33
|
+
for (const grant of grants) {
|
|
34
|
+
// Exact match: plugin:level
|
|
35
|
+
if (grant.plugin === pluginId && grant.level === permission)
|
|
36
|
+
return true;
|
|
37
|
+
// Plugin wildcard: plugin:*
|
|
38
|
+
if (grant.plugin === pluginId && grant.level === '*')
|
|
39
|
+
return true;
|
|
40
|
+
// Level wildcard: *:level
|
|
41
|
+
if (grant.plugin === '*' && grant.level === permission)
|
|
42
|
+
return true;
|
|
43
|
+
// Superuser: *:*
|
|
44
|
+
if (grant.plugin === '*' && grant.level === '*')
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if a permissionless tool from the given plugin should be included
|
|
51
|
+
* in strict mode. Only `plugin:*` or `*:*` opts in permissionless tools.
|
|
52
|
+
*/
|
|
53
|
+
function strictAllowsPermissionless(pluginId, grants) {
|
|
54
|
+
for (const grant of grants) {
|
|
55
|
+
if (grant.plugin === pluginId && grant.level === '*')
|
|
56
|
+
return true;
|
|
57
|
+
if (grant.plugin === '*' && grant.level === '*')
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
// ── Implementation ────────────────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* The tool registry — accumulates tools from plugin contributions
|
|
65
|
+
* and resolves permission-gated tool sets.
|
|
66
|
+
*/
|
|
67
|
+
class ToolRegistry {
|
|
68
|
+
/** Map from tool name → ResolvedTool. Last-write-wins for duplicates. */
|
|
69
|
+
tools = new Map();
|
|
70
|
+
/** Guild root path — set at startup, used for instructionsFile resolution. */
|
|
71
|
+
guildHome = '';
|
|
72
|
+
/** Set the guild root path for instructionsFile resolution. */
|
|
73
|
+
setHome(home) {
|
|
74
|
+
this.guildHome = home;
|
|
75
|
+
}
|
|
76
|
+
/** Register all tools from a loaded plugin. */
|
|
77
|
+
register(plugin) {
|
|
78
|
+
const pluginId = plugin.id;
|
|
79
|
+
const packageName = plugin.packageName;
|
|
80
|
+
if (isLoadedKit(plugin)) {
|
|
81
|
+
this.registerToolsFromKit(pluginId, packageName, plugin.kit);
|
|
82
|
+
}
|
|
83
|
+
else if (isLoadedApparatus(plugin)) {
|
|
84
|
+
if (plugin.apparatus.supportKit) {
|
|
85
|
+
this.registerToolsFromKit(pluginId, packageName, plugin.apparatus.supportKit);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Extract and register tools from a kit (or supportKit) contribution. */
|
|
90
|
+
registerToolsFromKit(pluginId, packageName, kit) {
|
|
91
|
+
const rawTools = kit.tools;
|
|
92
|
+
if (!Array.isArray(rawTools))
|
|
93
|
+
return;
|
|
94
|
+
for (const t of rawTools) {
|
|
95
|
+
if (isToolDefinition(t)) {
|
|
96
|
+
const definition = this.preloadInstructions(t, packageName);
|
|
97
|
+
this.tools.set(definition.name, { definition, pluginId });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Pre-load instructionsFile into instructions text.
|
|
103
|
+
*
|
|
104
|
+
* If the tool has an `instructionsFile`, resolve it relative to the
|
|
105
|
+
* package root in node_modules, read the file, and return a copy with
|
|
106
|
+
* `instructions` set to the file content and `instructionsFile` cleared.
|
|
107
|
+
*
|
|
108
|
+
* Tools with inline `instructions` or neither field are returned as-is.
|
|
109
|
+
*/
|
|
110
|
+
preloadInstructions(tool, packageName) {
|
|
111
|
+
if (!tool.instructionsFile)
|
|
112
|
+
return tool;
|
|
113
|
+
const packageDir = path.join(this.guildHome, 'node_modules', packageName);
|
|
114
|
+
const filePath = path.join(packageDir, tool.instructionsFile);
|
|
115
|
+
try {
|
|
116
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
117
|
+
// Return a mutated copy — instructionsFile consumed, instructions set
|
|
118
|
+
const { instructionsFile: _, ...rest } = tool;
|
|
119
|
+
return { ...rest, instructions: content };
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
console.warn(`[instrumentarium] Could not read instructions file for tool "${tool.name}": ${filePath}`);
|
|
123
|
+
// Return tool without instructions — don't block registration
|
|
124
|
+
const { instructionsFile: _, ...rest } = tool;
|
|
125
|
+
return rest;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Register a single tool definition directly (for self-contributed tools). */
|
|
129
|
+
registerTool(definition, pluginId) {
|
|
130
|
+
this.tools.set(definition.name, { definition, pluginId });
|
|
131
|
+
}
|
|
132
|
+
/** Find a tool by name. */
|
|
133
|
+
find(name) {
|
|
134
|
+
return this.tools.get(name) ?? null;
|
|
135
|
+
}
|
|
136
|
+
/** List all installed tools. */
|
|
137
|
+
list() {
|
|
138
|
+
return [...this.tools.values()];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Resolve a permission-gated tool set.
|
|
142
|
+
*
|
|
143
|
+
* 1. Parse each grant into (plugin, level) pairs
|
|
144
|
+
* 2. For each registered tool:
|
|
145
|
+
* a. If tool has no permission:
|
|
146
|
+
* - If NOT strict → include
|
|
147
|
+
* - If strict → include only if grants contain <tool's plugin>:* or *:*
|
|
148
|
+
* b. If tool has a permission:
|
|
149
|
+
* - Match against grants: exact, plugin wildcard, level wildcard, or superuser
|
|
150
|
+
* - Include if any grant matches
|
|
151
|
+
* 3. Filter by caller (callableBy)
|
|
152
|
+
*/
|
|
153
|
+
resolve(options) {
|
|
154
|
+
const grants = options.permissions
|
|
155
|
+
.map(parseGrant)
|
|
156
|
+
.filter((g) => g !== null);
|
|
157
|
+
const strict = options.strict ?? false;
|
|
158
|
+
const result = [];
|
|
159
|
+
for (const resolved of this.tools.values()) {
|
|
160
|
+
const { definition, pluginId } = resolved;
|
|
161
|
+
const permission = definition.permission;
|
|
162
|
+
// Permission check
|
|
163
|
+
if (permission === undefined) {
|
|
164
|
+
// Permissionless tool
|
|
165
|
+
if (strict && !strictAllowsPermissionless(pluginId, grants)) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
// In default mode, permissionless tools are always included
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
// Tool has a permission — must match against grants
|
|
172
|
+
if (!matchesPermission(pluginId, permission, grants)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Caller filter
|
|
177
|
+
if (options.caller &&
|
|
178
|
+
definition.callableBy &&
|
|
179
|
+
!definition.callableBy.includes(options.caller)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
result.push(resolved);
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// ── Apparatus factory ─────────────────────────────────────────────────
|
|
188
|
+
/**
|
|
189
|
+
* Create the Instrumentarium apparatus plugin.
|
|
190
|
+
*
|
|
191
|
+
* Returns a Plugin with:
|
|
192
|
+
* - `consumes: ['tools']` — scans kit/supportKit contributions
|
|
193
|
+
* - `provides: InstrumentariumApi` — the tool registry API
|
|
194
|
+
*/
|
|
195
|
+
export function createInstrumentarium() {
|
|
196
|
+
const registry = new ToolRegistry();
|
|
197
|
+
const api = {
|
|
198
|
+
resolve(options) {
|
|
199
|
+
return registry.resolve(options);
|
|
200
|
+
},
|
|
201
|
+
find(name) {
|
|
202
|
+
return registry.find(name);
|
|
203
|
+
},
|
|
204
|
+
list() {
|
|
205
|
+
return registry.list();
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
// Introspection tools use a lazy getter so they can query the registry
|
|
209
|
+
// after all plugins have registered their tools at startup.
|
|
210
|
+
const getApi = () => api;
|
|
211
|
+
const toolsList = createToolsList(getApi);
|
|
212
|
+
const toolsShow = createToolsShow(getApi);
|
|
213
|
+
return {
|
|
214
|
+
apparatus: {
|
|
215
|
+
requires: [],
|
|
216
|
+
consumes: ['tools'],
|
|
217
|
+
provides: api,
|
|
218
|
+
supportKit: {
|
|
219
|
+
tools: [toolsList, toolsShow],
|
|
220
|
+
},
|
|
221
|
+
start(ctx) {
|
|
222
|
+
const g = guild();
|
|
223
|
+
registry.setHome(g.home);
|
|
224
|
+
// Register our own supportKit tools (tools-list, tools-show).
|
|
225
|
+
// These live on this apparatus and aren't discovered through the
|
|
226
|
+
// normal kit scanning path.
|
|
227
|
+
for (const t of [toolsList, toolsShow]) {
|
|
228
|
+
registry.registerTool(t, 'tools');
|
|
229
|
+
}
|
|
230
|
+
// Scan all already-loaded kits. These fired plugin:initialized before
|
|
231
|
+
// any apparatus started, so we can't catch them via events.
|
|
232
|
+
for (const kit of g.kits()) {
|
|
233
|
+
registry.register(kit);
|
|
234
|
+
}
|
|
235
|
+
// Subscribe to plugin:initialized for apparatus supportKits that
|
|
236
|
+
// fire after us in the startup sequence.
|
|
237
|
+
ctx.on('plugin:initialized', (plugin) => {
|
|
238
|
+
const loaded = plugin;
|
|
239
|
+
// Skip kits — we already scanned them above.
|
|
240
|
+
if (isLoadedApparatus(loaded)) {
|
|
241
|
+
registry.register(loaded);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=instrumentarium.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentarium.js","sourceRoot":"","sources":["../src/instrumentarium.ts"],"names":[],"mappings":"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"}
|
package/dist/tool.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool SDK — the primary authoring interface for module-based tools.
|
|
3
|
+
*
|
|
4
|
+
* Use `tool()` to define a typed tool with Zod parameter schemas.
|
|
5
|
+
* The returned definition is what the MCP engine imports and registers as a tool,
|
|
6
|
+
* what the CLI uses to auto-generate subcommands, and what engines import directly.
|
|
7
|
+
*
|
|
8
|
+
* A package can export a single tool or an array of tools:
|
|
9
|
+
*
|
|
10
|
+
* @example Single tool
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { tool } from '@shardworks/tools-apparatus';
|
|
13
|
+
* import { z } from 'zod';
|
|
14
|
+
*
|
|
15
|
+
* export default tool({
|
|
16
|
+
* name: 'lookup',
|
|
17
|
+
* description: 'Look up an anima by name',
|
|
18
|
+
* instructionsFile: './instructions.md',
|
|
19
|
+
* params: {
|
|
20
|
+
* name: z.string().describe('Anima name'),
|
|
21
|
+
* },
|
|
22
|
+
* handler: async ({ name }) => {
|
|
23
|
+
* const { home } = guild();
|
|
24
|
+
* return { found: true, status: 'active' };
|
|
25
|
+
* },
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example Tool collection
|
|
30
|
+
* ```typescript
|
|
31
|
+
* export default [
|
|
32
|
+
* tool({ name: 'commission', description: '...', params: {...}, handler: ... }),
|
|
33
|
+
* tool({ name: 'signal', description: '...', params: {...}, handler: ... }),
|
|
34
|
+
* ];
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
import { z } from 'zod';
|
|
38
|
+
type ZodShape = Record<string, z.ZodType>;
|
|
39
|
+
/**
|
|
40
|
+
* The caller types a tool can be invoked by.
|
|
41
|
+
* - `'cli'` — accessible via `nsg` commands (human-facing)
|
|
42
|
+
* - `'anima'` — accessible via MCP server (anima-facing, in sessions)
|
|
43
|
+
* - `'library'` — accessible programmatically via direct import
|
|
44
|
+
*
|
|
45
|
+
* Defaults to all caller types if `callableBy` is unspecified.
|
|
46
|
+
*/
|
|
47
|
+
export type ToolCaller = 'cli' | 'anima' | 'library';
|
|
48
|
+
/**
|
|
49
|
+
* A fully-defined tool — the return type of `tool()`.
|
|
50
|
+
*
|
|
51
|
+
* The MCP engine uses `.params.shape` to register the tool's input schema,
|
|
52
|
+
* `.description` for the tool description, and `.handler` to execute calls.
|
|
53
|
+
* The CLI uses `.params` to auto-generate Commander options.
|
|
54
|
+
* Engines call `.handler` directly.
|
|
55
|
+
*/
|
|
56
|
+
export interface ToolDefinition<TShape extends ZodShape = ZodShape> {
|
|
57
|
+
/** Tool name — used for resolution when a package exports multiple tools. */
|
|
58
|
+
readonly name: string;
|
|
59
|
+
readonly description: string;
|
|
60
|
+
/** Per-tool instructions injected into the anima's session context (inline text). */
|
|
61
|
+
readonly instructions?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Path to an instructions file, relative to the package root.
|
|
64
|
+
* Resolved by the manifest engine at session time.
|
|
65
|
+
* Mutually exclusive with `instructions`.
|
|
66
|
+
*/
|
|
67
|
+
readonly instructionsFile?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Caller types this tool is available to.
|
|
70
|
+
* Always a normalized array. Absent means available to all callers.
|
|
71
|
+
*/
|
|
72
|
+
readonly callableBy?: ToolCaller[];
|
|
73
|
+
/**
|
|
74
|
+
* Permission level required to invoke this tool. Matched against role grants.
|
|
75
|
+
*
|
|
76
|
+
* Format: a freeform string chosen by the tool author. Conventional names:
|
|
77
|
+
* - `'read'` — query/inspect operations
|
|
78
|
+
* - `'write'` — create/update operations
|
|
79
|
+
* - `'delete'` — destructive operations
|
|
80
|
+
* - `'admin'` — configuration and lifecycle operations
|
|
81
|
+
*
|
|
82
|
+
* Plugins are free to define their own levels.
|
|
83
|
+
* If omitted, the tool is permissionless — included by default in non-strict
|
|
84
|
+
* mode, excluded in strict mode unless the role grants `plugin:*` or `*:*`.
|
|
85
|
+
*/
|
|
86
|
+
readonly permission?: string;
|
|
87
|
+
readonly params: z.ZodObject<TShape>;
|
|
88
|
+
readonly handler: (params: z.infer<z.ZodObject<TShape>>) => unknown | Promise<unknown>;
|
|
89
|
+
}
|
|
90
|
+
/** Input to `tool()` — instructions are either inline text or a file path, not both. */
|
|
91
|
+
type ToolInput<TShape extends ZodShape> = {
|
|
92
|
+
name: string;
|
|
93
|
+
description: string;
|
|
94
|
+
params: TShape;
|
|
95
|
+
handler: (params: z.infer<z.ZodObject<TShape>>) => unknown | Promise<unknown>;
|
|
96
|
+
/**
|
|
97
|
+
* Caller types this tool is available to.
|
|
98
|
+
* Accepts a single caller or an array. Normalized to an array in the returned definition.
|
|
99
|
+
*/
|
|
100
|
+
callableBy?: ToolCaller | ToolCaller[];
|
|
101
|
+
/**
|
|
102
|
+
* Permission level required to invoke this tool.
|
|
103
|
+
* See ToolDefinition.permission for details.
|
|
104
|
+
*/
|
|
105
|
+
permission?: string;
|
|
106
|
+
} & ({
|
|
107
|
+
instructions?: string;
|
|
108
|
+
instructionsFile?: never;
|
|
109
|
+
} | {
|
|
110
|
+
instructions?: never;
|
|
111
|
+
instructionsFile?: string;
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* Define a Nexus tool.
|
|
115
|
+
*
|
|
116
|
+
* This is the primary SDK entry point for module-based tools. Pass a
|
|
117
|
+
* name, description, a params object of Zod schemas, and a handler function.
|
|
118
|
+
* The framework handles the rest — MCP registration, CLI generation, validation.
|
|
119
|
+
*
|
|
120
|
+
* The handler receives one argument:
|
|
121
|
+
* - `params` — the validated input, typed from your Zod schemas
|
|
122
|
+
*
|
|
123
|
+
* To access guild infrastructure (apparatus, config, home path), import
|
|
124
|
+
* `guild` from `@shardworks/nexus-core` and call `guild()` inside the handler.
|
|
125
|
+
*
|
|
126
|
+
* Return any JSON-serializable value. The MCP engine wraps it as tool output;
|
|
127
|
+
* the CLI prints it; engines use it directly.
|
|
128
|
+
*
|
|
129
|
+
* Instructions can be provided inline or as a file path:
|
|
130
|
+
* - `instructions: 'Use this tool when...'` — inline text
|
|
131
|
+
* - `instructionsFile: './instructions.md'` — resolved at manifest time
|
|
132
|
+
*/
|
|
133
|
+
export declare function tool<TShape extends ZodShape>(def: ToolInput<TShape>): ToolDefinition<TShape>;
|
|
134
|
+
/** Type guard: is this value a ToolDefinition? */
|
|
135
|
+
export declare function isToolDefinition(obj: unknown): obj is ToolDefinition;
|
|
136
|
+
export {};
|
|
137
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;AAE1C;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc,CAAC,MAAM,SAAS,QAAQ,GAAG,QAAQ;IAChE,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IACnC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,CAChB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KACjC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACjC;AAED,wFAAwF;AACxF,KAAK,SAAS,CAAC,MAAM,SAAS,QAAQ,IAAI;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,CACP,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KACjC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,UAAU,EAAE,CAAC;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,CACA;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,KAAK,CAAA;CAAE,GACnD;IAAE,YAAY,CAAC,EAAE,KAAK,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,CACtD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,IAAI,CAAC,MAAM,SAAS,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAa5F;AAED,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,cAAc,CAYpE"}
|
package/dist/tool.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool SDK — the primary authoring interface for module-based tools.
|
|
3
|
+
*
|
|
4
|
+
* Use `tool()` to define a typed tool with Zod parameter schemas.
|
|
5
|
+
* The returned definition is what the MCP engine imports and registers as a tool,
|
|
6
|
+
* what the CLI uses to auto-generate subcommands, and what engines import directly.
|
|
7
|
+
*
|
|
8
|
+
* A package can export a single tool or an array of tools:
|
|
9
|
+
*
|
|
10
|
+
* @example Single tool
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { tool } from '@shardworks/tools-apparatus';
|
|
13
|
+
* import { z } from 'zod';
|
|
14
|
+
*
|
|
15
|
+
* export default tool({
|
|
16
|
+
* name: 'lookup',
|
|
17
|
+
* description: 'Look up an anima by name',
|
|
18
|
+
* instructionsFile: './instructions.md',
|
|
19
|
+
* params: {
|
|
20
|
+
* name: z.string().describe('Anima name'),
|
|
21
|
+
* },
|
|
22
|
+
* handler: async ({ name }) => {
|
|
23
|
+
* const { home } = guild();
|
|
24
|
+
* return { found: true, status: 'active' };
|
|
25
|
+
* },
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example Tool collection
|
|
30
|
+
* ```typescript
|
|
31
|
+
* export default [
|
|
32
|
+
* tool({ name: 'commission', description: '...', params: {...}, handler: ... }),
|
|
33
|
+
* tool({ name: 'signal', description: '...', params: {...}, handler: ... }),
|
|
34
|
+
* ];
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
import { z } from 'zod';
|
|
38
|
+
/**
|
|
39
|
+
* Define a Nexus tool.
|
|
40
|
+
*
|
|
41
|
+
* This is the primary SDK entry point for module-based tools. Pass a
|
|
42
|
+
* name, description, a params object of Zod schemas, and a handler function.
|
|
43
|
+
* The framework handles the rest — MCP registration, CLI generation, validation.
|
|
44
|
+
*
|
|
45
|
+
* The handler receives one argument:
|
|
46
|
+
* - `params` — the validated input, typed from your Zod schemas
|
|
47
|
+
*
|
|
48
|
+
* To access guild infrastructure (apparatus, config, home path), import
|
|
49
|
+
* `guild` from `@shardworks/nexus-core` and call `guild()` inside the handler.
|
|
50
|
+
*
|
|
51
|
+
* Return any JSON-serializable value. The MCP engine wraps it as tool output;
|
|
52
|
+
* the CLI prints it; engines use it directly.
|
|
53
|
+
*
|
|
54
|
+
* Instructions can be provided inline or as a file path:
|
|
55
|
+
* - `instructions: 'Use this tool when...'` — inline text
|
|
56
|
+
* - `instructionsFile: './instructions.md'` — resolved at manifest time
|
|
57
|
+
*/
|
|
58
|
+
export function tool(def) {
|
|
59
|
+
return {
|
|
60
|
+
name: def.name,
|
|
61
|
+
description: def.description,
|
|
62
|
+
...(def.instructions ? { instructions: def.instructions } : {}),
|
|
63
|
+
...(def.instructionsFile ? { instructionsFile: def.instructionsFile } : {}),
|
|
64
|
+
...(def.callableBy !== undefined
|
|
65
|
+
? { callableBy: Array.isArray(def.callableBy) ? def.callableBy : [def.callableBy] }
|
|
66
|
+
: {}),
|
|
67
|
+
...(def.permission !== undefined ? { permission: def.permission } : {}),
|
|
68
|
+
params: z.object(def.params),
|
|
69
|
+
handler: def.handler,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Type guard: is this value a ToolDefinition? */
|
|
73
|
+
export function isToolDefinition(obj) {
|
|
74
|
+
return (typeof obj === 'object' &&
|
|
75
|
+
obj !== null &&
|
|
76
|
+
'name' in obj &&
|
|
77
|
+
'description' in obj &&
|
|
78
|
+
'params' in obj &&
|
|
79
|
+
'handler' in obj &&
|
|
80
|
+
typeof obj.name === 'string' &&
|
|
81
|
+
typeof obj.description === 'string' &&
|
|
82
|
+
typeof obj.handler === 'function');
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=tool.js.map
|
package/dist/tool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoFxB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,IAAI,CAA0B,GAAsB;IAClE,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,SAAS;YAC9B,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;YACnF,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;KACrB,CAAC;AACJ,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,MAAM,IAAI,GAAG;QACb,aAAa,IAAI,GAAG;QACpB,QAAQ,IAAI,GAAG;QACf,SAAS,IAAI,GAAG;QAChB,OAAQ,GAAsB,CAAC,IAAI,KAAK,QAAQ;QAChD,OAAQ,GAAsB,CAAC,WAAW,KAAK,QAAQ;QACvD,OAAQ,GAAsB,CAAC,OAAO,KAAK,UAAU,CACtD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools-list — administrative view of all tools installed in the guild.
|
|
3
|
+
*
|
|
4
|
+
* Lists the full registry with optional filters for caller type, permission
|
|
5
|
+
* level, and contributing plugin. This is an inventory tool, not a
|
|
6
|
+
* permission-resolved view — use MCP native tool listing for that.
|
|
7
|
+
*
|
|
8
|
+
* Requires `tools:read` permission.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import type { InstrumentariumApi } from '../instrumentarium.ts';
|
|
12
|
+
/** Summary returned for each tool in the list. */
|
|
13
|
+
export interface ToolSummary {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
pluginId: string;
|
|
17
|
+
permission: string | null;
|
|
18
|
+
callableBy: string[] | null;
|
|
19
|
+
}
|
|
20
|
+
export declare function createToolsList(getApi: () => InstrumentariumApi): import("../tool.ts").ToolDefinition<{
|
|
21
|
+
caller: z.ZodOptional<z.ZodEnum<{
|
|
22
|
+
cli: "cli";
|
|
23
|
+
anima: "anima";
|
|
24
|
+
library: "library";
|
|
25
|
+
}>>;
|
|
26
|
+
permission: z.ZodOptional<z.ZodString>;
|
|
27
|
+
plugin: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}>;
|
|
29
|
+
//# sourceMappingURL=tools-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-list.d.ts","sourceRoot":"","sources":["../../src/tools/tools-list.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,kBAAkB;;;;;;;;GA0D/D"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools-list — administrative view of all tools installed in the guild.
|
|
3
|
+
*
|
|
4
|
+
* Lists the full registry with optional filters for caller type, permission
|
|
5
|
+
* level, and contributing plugin. This is an inventory tool, not a
|
|
6
|
+
* permission-resolved view — use MCP native tool listing for that.
|
|
7
|
+
*
|
|
8
|
+
* Requires `tools:read` permission.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { tool } from "../tool.js";
|
|
12
|
+
export function createToolsList(getApi) {
|
|
13
|
+
return tool({
|
|
14
|
+
name: 'tools-list',
|
|
15
|
+
description: 'List all tools installed in the guild. Administrative view — shows the full registry, not a permission-resolved set.',
|
|
16
|
+
permission: 'read',
|
|
17
|
+
params: {
|
|
18
|
+
caller: z
|
|
19
|
+
.enum(['cli', 'anima', 'library'])
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Filter to tools callable by this caller type.'),
|
|
22
|
+
permission: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Filter to tools requiring this permission level (e.g. "read", "write").'),
|
|
26
|
+
plugin: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Filter to tools contributed by this plugin id.'),
|
|
30
|
+
},
|
|
31
|
+
handler: async ({ caller, permission, plugin }) => {
|
|
32
|
+
const api = getApi();
|
|
33
|
+
let tools = api.list();
|
|
34
|
+
// Filter by contributing plugin
|
|
35
|
+
if (plugin) {
|
|
36
|
+
tools = tools.filter((t) => t.pluginId === plugin);
|
|
37
|
+
}
|
|
38
|
+
// Filter by permission level
|
|
39
|
+
if (permission) {
|
|
40
|
+
tools = tools.filter((t) => t.definition.permission === permission);
|
|
41
|
+
}
|
|
42
|
+
// Filter by caller type (callableBy gate)
|
|
43
|
+
if (caller) {
|
|
44
|
+
tools = tools.filter((t) => !t.definition.callableBy ||
|
|
45
|
+
t.definition.callableBy.includes(caller));
|
|
46
|
+
}
|
|
47
|
+
return tools.map((t) => ({
|
|
48
|
+
name: t.definition.name,
|
|
49
|
+
description: t.definition.description,
|
|
50
|
+
pluginId: t.pluginId,
|
|
51
|
+
permission: t.definition.permission ?? null,
|
|
52
|
+
callableBy: t.definition.callableBy ?? null,
|
|
53
|
+
}));
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=tools-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-list.js","sourceRoot":"","sources":["../../src/tools/tools-list.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAYlC,MAAM,UAAU,eAAe,CAAC,MAAgC;IAC9D,OAAO,IAAI,CAAC;QACV,IAAI,EAAE,YAAY;QAClB,WAAW,EACT,sHAAsH;QACxH,UAAU,EAAE,MAAM;QAClB,MAAM,EAAE;YACN,MAAM,EAAE,CAAC;iBACN,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;iBACjC,QAAQ,EAAE;iBACV,QAAQ,CAAC,+CAA+C,CAAC;YAC5D,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,yEAAyE,CAC1E;YACH,MAAM,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,gDAAgD,CAAC;SAC9D;QACD,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE;YAChD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;YACrB,IAAI,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YAEvB,gCAAgC;YAChC,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;YACrD,CAAC;YAED,6BAA6B;YAC7B,IAAI,UAAU,EAAE,CAAC;gBACf,KAAK,GAAG,KAAK,CAAC,MAAM,CAClB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,KAAK,UAAU,CAC9C,CAAC;YACJ,CAAC;YAED,0CAA0C;YAC1C,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,GAAG,KAAK,CAAC,MAAM,CAClB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU;oBACxB,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC3C,CAAC;YACJ,CAAC;YAED,OAAO,KAAK,CAAC,GAAG,CACd,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC;gBACnB,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI;gBACvB,WAAW,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW;gBACrC,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,IAAI,IAAI;gBAC3C,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,IAAI,IAAI;aAC5C,CAAC,CACH,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools-show — show full details for a single tool.
|
|
3
|
+
*
|
|
4
|
+
* Returns name, description, plugin, permission, callableBy, parameter
|
|
5
|
+
* schema, and instructions for the named tool. Returns null if not found.
|
|
6
|
+
*
|
|
7
|
+
* Requires `tools:read` permission.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import type { InstrumentariumApi } from '../instrumentarium.ts';
|
|
11
|
+
/** Parameter info derived from the Zod schema. */
|
|
12
|
+
export interface ParamInfo {
|
|
13
|
+
type: string;
|
|
14
|
+
description: string | null;
|
|
15
|
+
optional: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Full detail returned for a single tool. */
|
|
18
|
+
export interface ToolDetail {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
pluginId: string;
|
|
22
|
+
permission: string | null;
|
|
23
|
+
callableBy: string[] | null;
|
|
24
|
+
params: Record<string, ParamInfo>;
|
|
25
|
+
instructions: string | null;
|
|
26
|
+
}
|
|
27
|
+
export declare function createToolsShow(getApi: () => InstrumentariumApi): import("../tool.ts").ToolDefinition<{
|
|
28
|
+
name: z.ZodString;
|
|
29
|
+
}>;
|
|
30
|
+
//# sourceMappingURL=tools-show.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-show.d.ts","sourceRoot":"","sources":["../../src/tools/tools-show.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,kDAAkD;AAClD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,8CAA8C;AAC9C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAyDD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,kBAAkB;;GA8B/D"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools-show — show full details for a single tool.
|
|
3
|
+
*
|
|
4
|
+
* Returns name, description, plugin, permission, callableBy, parameter
|
|
5
|
+
* schema, and instructions for the named tool. Returns null if not found.
|
|
6
|
+
*
|
|
7
|
+
* Requires `tools:read` permission.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { tool } from "../tool.js";
|
|
11
|
+
/**
|
|
12
|
+
* Extract parameter info from a Zod object schema.
|
|
13
|
+
*
|
|
14
|
+
* Walks the shape, unwraps ZodOptional/ZodDefault wrappers, and
|
|
15
|
+
* derives the JSON Schema type name from the inner Zod type.
|
|
16
|
+
*/
|
|
17
|
+
function extractParams(schema) {
|
|
18
|
+
const shape = schema.shape;
|
|
19
|
+
const result = {};
|
|
20
|
+
for (const [key, zodType] of Object.entries(shape)) {
|
|
21
|
+
result[key] = extractSingleParam(zodType);
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
/** Extract info for a single Zod parameter. */
|
|
26
|
+
function extractSingleParam(zodType) {
|
|
27
|
+
let isOptional = false;
|
|
28
|
+
let inner = zodType;
|
|
29
|
+
// Unwrap ZodOptional
|
|
30
|
+
if (inner instanceof z.ZodOptional) {
|
|
31
|
+
isOptional = true;
|
|
32
|
+
inner = inner.unwrap();
|
|
33
|
+
}
|
|
34
|
+
// Unwrap ZodDefault
|
|
35
|
+
if (inner instanceof z.ZodDefault) {
|
|
36
|
+
isOptional = true;
|
|
37
|
+
inner = inner.unwrap();
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
type: zodTypeToJsonType(inner),
|
|
41
|
+
description: inner.description ?? null,
|
|
42
|
+
optional: isOptional,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Map a Zod type to a JSON Schema type string. */
|
|
46
|
+
function zodTypeToJsonType(zodType) {
|
|
47
|
+
if (zodType instanceof z.ZodString)
|
|
48
|
+
return 'string';
|
|
49
|
+
if (zodType instanceof z.ZodNumber)
|
|
50
|
+
return 'number';
|
|
51
|
+
if (zodType instanceof z.ZodBoolean)
|
|
52
|
+
return 'boolean';
|
|
53
|
+
if (zodType instanceof z.ZodArray)
|
|
54
|
+
return 'array';
|
|
55
|
+
if (zodType instanceof z.ZodObject)
|
|
56
|
+
return 'object';
|
|
57
|
+
if (zodType instanceof z.ZodEnum)
|
|
58
|
+
return 'string';
|
|
59
|
+
if (zodType instanceof z.ZodLiteral)
|
|
60
|
+
return typeof zodType._def.values[0];
|
|
61
|
+
if (zodType instanceof z.ZodUnion)
|
|
62
|
+
return 'union';
|
|
63
|
+
if (zodType instanceof z.ZodNullable)
|
|
64
|
+
return zodTypeToJsonType(zodType.unwrap());
|
|
65
|
+
return 'unknown';
|
|
66
|
+
}
|
|
67
|
+
export function createToolsShow(getApi) {
|
|
68
|
+
return tool({
|
|
69
|
+
name: 'tools-show',
|
|
70
|
+
description: 'Show details for a tool by name, including parameter schema and instructions.',
|
|
71
|
+
permission: 'read',
|
|
72
|
+
params: {
|
|
73
|
+
name: z.string().describe('Tool name to look up.'),
|
|
74
|
+
},
|
|
75
|
+
handler: async ({ name }) => {
|
|
76
|
+
const api = getApi();
|
|
77
|
+
const resolved = api.find(name);
|
|
78
|
+
if (!resolved)
|
|
79
|
+
return null;
|
|
80
|
+
const { definition, pluginId } = resolved;
|
|
81
|
+
const detail = {
|
|
82
|
+
name: definition.name,
|
|
83
|
+
description: definition.description,
|
|
84
|
+
pluginId,
|
|
85
|
+
permission: definition.permission ?? null,
|
|
86
|
+
callableBy: definition.callableBy ?? null,
|
|
87
|
+
params: extractParams(definition.params),
|
|
88
|
+
instructions: definition.instructions ?? null,
|
|
89
|
+
};
|
|
90
|
+
return detail;
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=tools-show.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-show.js","sourceRoot":"","sources":["../../src/tools/tools-show.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shardworks/tools-apparatus",
|
|
3
|
+
"version": "0.1.101",
|
|
4
|
+
"license": "ISC",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/shardworks/nexus",
|
|
8
|
+
"directory": "packages/plugins/tools"
|
|
9
|
+
},
|
|
10
|
+
"description": "The Instrumentarium — guild tool registry apparatus",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"zod": "4.3.6",
|
|
20
|
+
"@shardworks/nexus-core": "0.1.101"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "25.5.0"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"test": "node --disable-warning=ExperimentalWarning --experimental-transform-types --test 'src/**/*.test.ts'",
|
|
31
|
+
"typecheck": "tsc --noEmit"
|
|
32
|
+
}
|
|
33
|
+
}
|