@amalgm/tools 0.1.7-preview.34176071261 → 0.1.7-preview.34545371724
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 +6 -0
- package/dist/cli-driver.d.ts +4 -3
- package/dist/cli-driver.js +42 -40
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +8 -0
- package/dist/definition.js +1 -0
- package/dist/host-mcp-tool.d.ts +18 -1
- package/dist/mcp.js +14 -1
- package/dist/toolbox.d.ts +5 -2
- package/dist/toolbox.js +8 -3
- package/dist/types.d.ts +6 -17
- package/dist/updates.d.ts +7 -2
- package/dist/updates.js +15 -1
- package/package.json +5 -5
- package/skills/tools/SKILL.md +6 -0
package/README.md
CHANGED
|
@@ -66,9 +66,15 @@ amalgm-tools apply ./tool.mjs
|
|
|
66
66
|
amalgm-tools list
|
|
67
67
|
amalgm-tools run hello.say --input '{"name":"Ada"}'
|
|
68
68
|
amalgm-tools disable hello.say
|
|
69
|
+
amalgm-tools link canvas app-3f1c
|
|
69
70
|
amalgm-tools connections
|
|
70
71
|
```
|
|
71
72
|
|
|
73
|
+
A tool may belong to an app: `appId` on the tool is the reverse edge of the
|
|
74
|
+
app manifest's `toolIds`, and sharing either side carries the other. The host
|
|
75
|
+
that composes Tools and Apps may pass `environment(tool)` so a linked tool
|
|
76
|
+
runs knowing where its app listens.
|
|
77
|
+
|
|
72
78
|
`amalgm-tools-mcp` serves Toolbox management and enabled action tools over
|
|
73
79
|
newline-delimited MCP stdio.
|
|
74
80
|
|
package/dist/cli-driver.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type { ToolDriver } from './types.js';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { ToolDriver, ToolRecord } from './types.js';
|
|
2
|
+
type Environment = (tool: ToolRecord) => Record<string, string> | Promise<Record<string, string>>;
|
|
3
|
+
declare function createCliDriver(environment?: Environment): ToolDriver;
|
|
4
|
+
export { createCliDriver };
|
package/dist/cli-driver.js
CHANGED
|
@@ -8,45 +8,47 @@ function inputArguments(input) {
|
|
|
8
8
|
}
|
|
9
9
|
return args;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
let result;
|
|
39
|
-
if (source.outputMode === 'json' && stdout) {
|
|
40
|
-
try {
|
|
41
|
-
result = structuredResult(JSON.parse(stdout));
|
|
11
|
+
function createCliDriver(environment = () => ({})) {
|
|
12
|
+
return {
|
|
13
|
+
type: 'cli',
|
|
14
|
+
async call({ tool, action, input, options }) {
|
|
15
|
+
const source = tool.source;
|
|
16
|
+
const target = action.target;
|
|
17
|
+
const secrets = await resolveReferences(source.secretEnv, options.resolveSecret);
|
|
18
|
+
const args = [...(source.args || []), ...(target.args || [])];
|
|
19
|
+
if (source.inputMode === 'argv')
|
|
20
|
+
args.push(...inputArguments(input));
|
|
21
|
+
const output = await runCommand({
|
|
22
|
+
command: source.command, args, cwd: source.cwd,
|
|
23
|
+
env: { ...process.env, ...(await environment(tool)), ...secrets },
|
|
24
|
+
stdin: source.inputMode === 'json-stdin' ? `${JSON.stringify(input)}\n` : undefined,
|
|
25
|
+
timeoutMs: source.timeoutMs, maximumBytes: source.maxOutputBytes, signal: options.signal,
|
|
26
|
+
});
|
|
27
|
+
const stdout = output.stdout.trim();
|
|
28
|
+
const stderr = output.stderr.trim();
|
|
29
|
+
if (output.timedOut)
|
|
30
|
+
return errorResult(`Tool ${action.id} timed out after ${source.timeoutMs}ms`);
|
|
31
|
+
if (output.aborted)
|
|
32
|
+
return errorResult(`Tool ${action.id} was cancelled`);
|
|
33
|
+
if (output.code !== 0) {
|
|
34
|
+
return errorResult([
|
|
35
|
+
`Tool ${action.id} exited with ${output.code ?? output.signal ?? 'unknown'}.`,
|
|
36
|
+
stdout && `stdout:\n${stdout}`, stderr && `stderr:\n${stderr}`,
|
|
37
|
+
].filter(Boolean).join('\n\n'));
|
|
42
38
|
}
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
let result;
|
|
40
|
+
if (source.outputMode === 'json' && stdout) {
|
|
41
|
+
try {
|
|
42
|
+
result = structuredResult(JSON.parse(stdout));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return errorResult(`Tool ${action.id} returned invalid JSON`);
|
|
46
|
+
}
|
|
45
47
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
result
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
export {
|
|
48
|
+
else
|
|
49
|
+
result = textResult(stdout || `Tool ${action.id} completed.`);
|
|
50
|
+
return { ...result, ...(output.truncated ? { truncated: true } : {}) };
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export { createCliDriver };
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CliIo, LoadoutInput } from './types.js';
|
|
2
|
-
declare const HELP = "Usage: amalgm-tools [--state-dir DIR] [--loadout IDS] <command>\n\nCommands:\n apply <definition.js|json> Apply one tool or an array of tools\n list List tools and enabled actions\n catalog Print the complete canonical catalog\n show <tool-or-action-id> Show one record\n enable <tool-or-action-id> Enable one record\n disable <tool-or-action-id> Disable one record\n remove <tool-or-action-id> Remove one record\n run <action-id> [--input JSON]\n Run an action\n connections List MCP connections for a composing host";
|
|
2
|
+
declare const HELP = "Usage: amalgm-tools [--state-dir DIR] [--loadout IDS] <command>\n\nCommands:\n apply <definition.js|json> Apply one tool or an array of tools\n list List tools and enabled actions\n catalog Print the complete canonical catalog\n show <tool-or-action-id> Show one record\n enable <tool-or-action-id> Enable one record\n disable <tool-or-action-id> Disable one record\n remove <tool-or-action-id> Remove one record\n link <tool-id> <app-id> Link one tool to the app it belongs to\n unlink <tool-id> Detach one tool from its app\n run <action-id> [--input JSON]\n Run an action\n connections List MCP connections for a composing host";
|
|
3
3
|
interface Parsed {
|
|
4
4
|
command?: string;
|
|
5
5
|
args: string[];
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,8 @@ Commands:
|
|
|
10
10
|
enable <tool-or-action-id> Enable one record
|
|
11
11
|
disable <tool-or-action-id> Disable one record
|
|
12
12
|
remove <tool-or-action-id> Remove one record
|
|
13
|
+
link <tool-id> <app-id> Link one tool to the app it belongs to
|
|
14
|
+
unlink <tool-id> Detach one tool from its app
|
|
13
15
|
run <action-id> [--input JSON]
|
|
14
16
|
Run an action
|
|
15
17
|
connections List MCP connections for a composing host`;
|
|
@@ -101,6 +103,12 @@ async function runCli(argv, io = {}) {
|
|
|
101
103
|
case 'remove':
|
|
102
104
|
write(stdout, await toolbox.remove(required(recordId, 'record id')));
|
|
103
105
|
break;
|
|
106
|
+
case 'link':
|
|
107
|
+
write(stdout, await toolbox.link(required(recordId, 'tool id'), required(parsed.args[1], 'app id')));
|
|
108
|
+
break;
|
|
109
|
+
case 'unlink':
|
|
110
|
+
write(stdout, await toolbox.link(required(recordId, 'tool id'), null));
|
|
111
|
+
break;
|
|
104
112
|
case 'run':
|
|
105
113
|
write(stdout, await toolbox.call(required(recordId, 'action id'), parsed.input, { loadout: parsed.loadout }));
|
|
106
114
|
break;
|
package/dist/definition.js
CHANGED
|
@@ -140,6 +140,7 @@ function normalizeDefinition(definition, existing, now = new Date().toISOString(
|
|
|
140
140
|
owner: definition.owner?.trim() || 'user', origin,
|
|
141
141
|
status: definition.status || 'enabled',
|
|
142
142
|
...(definition.description?.trim() ? { description: definition.description.trim() } : {}),
|
|
143
|
+
...(definition.appId?.trim() ? { appId: definition.appId.trim() } : {}),
|
|
143
144
|
...(definition.display ? { display: structuredClone(definition.display) } : {}),
|
|
144
145
|
...(definition.policy ? { policy: structuredClone(definition.policy) } : {}),
|
|
145
146
|
...(definition.metadata ? { metadata: structuredClone(definition.metadata) } : {}),
|
package/dist/host-mcp-tool.d.ts
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JsonSchema, ToolDefinition } from './types.js';
|
|
2
|
+
interface HostMcpToolDescriptor {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
inputSchema?: JsonSchema;
|
|
6
|
+
}
|
|
7
|
+
interface HostMcpToolDefinitionInput {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
serverName: string;
|
|
12
|
+
route: string;
|
|
13
|
+
tools: readonly HostMcpToolDescriptor[];
|
|
14
|
+
owner?: string;
|
|
15
|
+
display?: Record<string, unknown>;
|
|
16
|
+
metadata?: Record<string, unknown>;
|
|
17
|
+
}
|
|
2
18
|
/**
|
|
3
19
|
* Project an owning SDK's MCP descriptors into one immutable first-party
|
|
4
20
|
* Toolbox tool. The descriptors remain authoritative; this adapter does not
|
|
@@ -6,3 +22,4 @@ import type { HostMcpToolDefinitionInput, ToolDefinition } from './types.js';
|
|
|
6
22
|
*/
|
|
7
23
|
declare function defineHostMcpTool(input: HostMcpToolDefinitionInput): ToolDefinition;
|
|
8
24
|
export { defineHostMcpTool };
|
|
25
|
+
export type { HostMcpToolDefinitionInput, HostMcpToolDescriptor };
|
package/dist/mcp.js
CHANGED
|
@@ -51,6 +51,17 @@ function managementToolDescriptors() {
|
|
|
51
51
|
name: 'toolbox_record_remove', description: 'Remove one user-owned tool or action.',
|
|
52
52
|
inputSchema: { type: 'object', properties: idProperty, required: ['id'], additionalProperties: false },
|
|
53
53
|
},
|
|
54
|
+
{
|
|
55
|
+
name: 'toolbox_tool_link', description: 'Link one user-owned tool to the app it belongs to.',
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: 'object', required: ['id', 'app_id'], additionalProperties: false,
|
|
58
|
+
properties: { ...idProperty, app_id: { type: 'string', description: 'App id' } },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'toolbox_tool_unlink', description: 'Detach one user-owned tool from its app.',
|
|
63
|
+
inputSchema: { type: 'object', properties: idProperty, required: ['id'], additionalProperties: false },
|
|
64
|
+
},
|
|
54
65
|
{
|
|
55
66
|
name: 'toolbox_mcp_connections', description: 'List external MCP connections for the composing host.',
|
|
56
67
|
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
@@ -58,7 +69,7 @@ function managementToolDescriptors() {
|
|
|
58
69
|
];
|
|
59
70
|
}
|
|
60
71
|
function managementTools(toolbox) {
|
|
61
|
-
const [list, get, apply, enable, disable, remove, connections] = managementToolDescriptors();
|
|
72
|
+
const [list, get, apply, enable, disable, remove, link, unlink, connections] = managementToolDescriptors();
|
|
62
73
|
return [
|
|
63
74
|
managed(list, () => toolbox.catalog()),
|
|
64
75
|
managed(get, ({ id }) => {
|
|
@@ -71,6 +82,8 @@ function managementTools(toolbox) {
|
|
|
71
82
|
managed(enable, ({ id }) => toolbox.setStatus(String(id), 'enabled')),
|
|
72
83
|
managed(disable, ({ id }) => toolbox.setStatus(String(id), 'disabled')),
|
|
73
84
|
managed(remove, ({ id }) => toolbox.remove(String(id))),
|
|
85
|
+
managed(link, ({ id, app_id }) => toolbox.link(String(id), String(app_id))),
|
|
86
|
+
managed(unlink, ({ id }) => toolbox.link(String(id), null)),
|
|
74
87
|
managed(connections, () => toolbox.connections()),
|
|
75
88
|
];
|
|
76
89
|
}
|
package/dist/toolbox.d.ts
CHANGED
|
@@ -34,8 +34,11 @@ declare class Toolbox {
|
|
|
34
34
|
update(toolId: string, patch: ToolPatch): Promise<ApplyResult>;
|
|
35
35
|
upsertAction(toolId: string, definition: ActionDefinition): Promise<ActionRecord>;
|
|
36
36
|
updateAction(actionId: string, patch: ActionPatch): Promise<ActionRecord>;
|
|
37
|
-
setStatus(recordId: string, status: 'enabled' | 'disabled'): Promise<
|
|
38
|
-
|
|
37
|
+
setStatus(recordId: string, status: 'enabled' | 'disabled'): Promise<ActionRecord | ToolRecord>;
|
|
38
|
+
/** Link one user tool to the app it belongs to; `null` unlinks it. */
|
|
39
|
+
link(toolId: string, appId: string | null): Promise<ToolRecord>;
|
|
40
|
+
isSystemTool(toolId: string): boolean;
|
|
41
|
+
remove(recordId: string): Promise<ActionRecord | ToolRecord>;
|
|
39
42
|
currentDeployment(toolId: string): ToolDeployment | null;
|
|
40
43
|
deployment(deploymentId: string): ToolDeployment | null;
|
|
41
44
|
deploymentHistory(toolId: string): ToolDeployment[];
|
package/dist/toolbox.js
CHANGED
|
@@ -5,7 +5,7 @@ import { apiDriver } from './api-driver.js';
|
|
|
5
5
|
import { applyDefinition } from './apply-definition.js';
|
|
6
6
|
import { ArtifactFiles } from './artifact-files.js';
|
|
7
7
|
import { preserveProjectionTime } from './artifacts.js';
|
|
8
|
-
import {
|
|
8
|
+
import { createCliDriver } from './cli-driver.js';
|
|
9
9
|
import { DeploymentFiles } from './deployment-files.js';
|
|
10
10
|
import { deploymentRevisionId } from './deployments.js';
|
|
11
11
|
import { normalizeDefinition } from './definition.js';
|
|
@@ -14,7 +14,7 @@ import { Store } from './store.js';
|
|
|
14
14
|
import { ToolboxDeployments } from './toolbox-deployments.js';
|
|
15
15
|
import { ToolboxProjection } from './toolbox-projection.js';
|
|
16
16
|
import { ToolboxView } from './toolbox-view.js';
|
|
17
|
-
import { removeAction, updateAction, updateTool, upsertAction } from './updates.js';
|
|
17
|
+
import { linkTool, removeAction, updateAction, updateTool, upsertAction } from './updates.js';
|
|
18
18
|
function defaultDatabase(options) {
|
|
19
19
|
if (options.databaseFile)
|
|
20
20
|
return path.resolve(options.databaseFile);
|
|
@@ -43,7 +43,7 @@ class Toolbox {
|
|
|
43
43
|
const artifacts = new ArtifactFiles(path.dirname(databaseFile));
|
|
44
44
|
const deploymentFiles = new DeploymentFiles(path.resolve(options.deploymentDir || options.stateDir || path.dirname(databaseFile)));
|
|
45
45
|
const priorIndex = artifacts.readIndex();
|
|
46
|
-
for (const driver of [
|
|
46
|
+
for (const driver of [createCliDriver(options.environment), apiDriver, ...(options.drivers || [])])
|
|
47
47
|
this.drivers.set(driver.type, driver);
|
|
48
48
|
const tools = [];
|
|
49
49
|
const actions = [];
|
|
@@ -138,6 +138,11 @@ class Toolbox {
|
|
|
138
138
|
throw new Error(`Unknown tool or action: ${value}`);
|
|
139
139
|
return action.status === status ? action : this.updateAction(value, { status });
|
|
140
140
|
}
|
|
141
|
+
/** Link one user tool to the app it belongs to; `null` unlinks it. */
|
|
142
|
+
async link(toolId, appId) {
|
|
143
|
+
return linkTool(this, toolId, appId);
|
|
144
|
+
}
|
|
145
|
+
isSystemTool(toolId) { return this.system.tools.some((tool) => tool.id === toolId); }
|
|
141
146
|
async remove(recordId) {
|
|
142
147
|
const value = id(recordId, 'record id');
|
|
143
148
|
if (this.system.tools.some((tool) => tool.id === value)
|
package/dist/types.d.ts
CHANGED
|
@@ -75,6 +75,8 @@ interface ToolDefinition {
|
|
|
75
75
|
id: string;
|
|
76
76
|
name: string;
|
|
77
77
|
description?: string;
|
|
78
|
+
/** The app this tool belongs to: the reverse edge of the app manifest's `toolIds`. */
|
|
79
|
+
appId?: string;
|
|
78
80
|
owner?: string;
|
|
79
81
|
origin?: Origin;
|
|
80
82
|
status?: Status;
|
|
@@ -163,6 +165,8 @@ interface ToolboxOptions {
|
|
|
163
165
|
deploymentDir?: string;
|
|
164
166
|
systemTools?: ToolDefinition[];
|
|
165
167
|
drivers?: ToolDriver[];
|
|
168
|
+
/** Host-supplied process environment for one CLI tool call, such as where its linked app listens. */
|
|
169
|
+
environment?: (tool: ToolRecord) => Record<string, string> | Promise<Record<string, string>>;
|
|
166
170
|
onChange?: (catalog: Catalog) => void | Promise<void>;
|
|
167
171
|
/** Outbound local Live operation. Remote application never calls it. */
|
|
168
172
|
onDeployment?: (activation: ToolDeploymentActivation) => void | Promise<void>;
|
|
@@ -176,26 +180,11 @@ interface McpTool {
|
|
|
176
180
|
interface McpOptions extends CallOptions {
|
|
177
181
|
includeManagement?: boolean;
|
|
178
182
|
}
|
|
179
|
-
interface HostMcpToolDescriptor {
|
|
180
|
-
name: string;
|
|
181
|
-
description?: string;
|
|
182
|
-
inputSchema?: JsonSchema;
|
|
183
|
-
}
|
|
184
|
-
interface HostMcpToolDefinitionInput {
|
|
185
|
-
id: string;
|
|
186
|
-
name: string;
|
|
187
|
-
description?: string;
|
|
188
|
-
serverName: string;
|
|
189
|
-
route: string;
|
|
190
|
-
tools: readonly HostMcpToolDescriptor[];
|
|
191
|
-
owner?: string;
|
|
192
|
-
display?: Record<string, unknown>;
|
|
193
|
-
metadata?: Record<string, unknown>;
|
|
194
|
-
}
|
|
195
183
|
interface CliIo {
|
|
196
184
|
stdout?: Writable;
|
|
197
185
|
stderr?: Writable;
|
|
198
186
|
toolbox?: import('./toolbox.js').Toolbox;
|
|
199
187
|
}
|
|
200
|
-
export type { ActionDefinition, ActionRecord, ActionTarget, ApiSource, ApiTarget, ApplyResult, CallOptions, Catalog, CliIo, CliSource, CliTarget, DriverCall,
|
|
188
|
+
export type { ActionDefinition, ActionRecord, ActionTarget, ApiSource, ApiTarget, ApplyResult, CallOptions, Catalog, CliIo, CliSource, CliTarget, DriverCall, JsonSchema, Loadout, LoadoutInput, McpOptions, McpSource, McpTarget, McpTool, Origin, SecretResolver, Status, ToolDefinition, ToolDriver, ToolboxOptions, ToolRecord, ToolResult, ToolPatch, ActionPatch, ToolQuery, ToolSource, ToolType, };
|
|
201
189
|
export type { ToolDeployment, ToolDeploymentActivation, ToolDeploymentSnapshot, ToolDeploymentSurface, } from './deployment-types.js';
|
|
190
|
+
export type { HostMcpToolDefinitionInput, HostMcpToolDescriptor } from './host-mcp-tool.js';
|
package/dist/updates.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { Toolbox } from './toolbox.js';
|
|
2
|
-
import type { ActionDefinition, ActionPatch, ActionRecord, ApplyResult, ToolPatch } from './types.js';
|
|
2
|
+
import type { ActionDefinition, ActionPatch, ActionRecord, ApplyResult, ToolPatch, ToolRecord } from './types.js';
|
|
3
3
|
type UpdatePort = Pick<Toolbox, 'action' | 'apply' | 'get'>;
|
|
4
|
+
type LinkPort = UpdatePort & Pick<Toolbox, 'update'> & {
|
|
5
|
+
isSystemTool(toolId: string): boolean;
|
|
6
|
+
};
|
|
4
7
|
declare function updateTool(toolbox: UpdatePort, toolId: string, patch: ToolPatch): Promise<ApplyResult>;
|
|
8
|
+
/** Link one user tool to its app; `null` unlinks. The record is unchanged when the link already holds. */
|
|
9
|
+
declare function linkTool(toolbox: LinkPort, toolId: string, appId: string | null): Promise<ToolRecord>;
|
|
5
10
|
declare function upsertAction(toolbox: UpdatePort, toolId: string, definition: ActionDefinition): Promise<ActionRecord>;
|
|
6
11
|
declare function updateAction(toolbox: UpdatePort, actionId: string, patch: ActionPatch): Promise<ActionRecord>;
|
|
7
12
|
declare function removeAction(toolbox: UpdatePort, actionId: string): Promise<ActionRecord>;
|
|
8
|
-
export { removeAction, updateAction, updateTool, upsertAction };
|
|
13
|
+
export { linkTool, removeAction, updateAction, updateTool, upsertAction };
|
package/dist/updates.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { id } from './ids.js';
|
|
1
2
|
function actionDefinition(action) {
|
|
2
3
|
const { id, toolId: _toolId, createdAt: _createdAt, updatedAt: _updatedAt, ...definition } = action;
|
|
3
4
|
return { ...structuredClone(definition), id };
|
|
@@ -25,6 +26,19 @@ async function updateTool(toolbox, toolId, patch) {
|
|
|
25
26
|
actions: patch.actions === undefined ? definition.actions : patch.actions,
|
|
26
27
|
});
|
|
27
28
|
}
|
|
29
|
+
/** Link one user tool to its app; `null` unlinks. The record is unchanged when the link already holds. */
|
|
30
|
+
async function linkTool(toolbox, toolId, appId) {
|
|
31
|
+
const value = id(toolId, 'tool id');
|
|
32
|
+
if (toolbox.isSystemTool(value))
|
|
33
|
+
throw new Error(`System record is immutable: ${value}`);
|
|
34
|
+
const current = toolbox.get(value);
|
|
35
|
+
if (!current)
|
|
36
|
+
throw new Error(`Unknown tool: ${value}`);
|
|
37
|
+
const trimmed = appId?.trim() || null;
|
|
38
|
+
if ((current.tool.appId ?? null) === trimmed)
|
|
39
|
+
return current.tool;
|
|
40
|
+
return (await toolbox.update(value, { appId: trimmed ?? undefined })).tool;
|
|
41
|
+
}
|
|
28
42
|
async function upsertAction(toolbox, toolId, definition) {
|
|
29
43
|
const current = toolbox.get(toolId);
|
|
30
44
|
if (!current)
|
|
@@ -65,4 +79,4 @@ async function removeAction(toolbox, actionId) {
|
|
|
65
79
|
});
|
|
66
80
|
return action;
|
|
67
81
|
}
|
|
68
|
-
export { removeAction, updateAction, updateTool, upsertAction };
|
|
82
|
+
export { linkTool, removeAction, updateAction, updateTool, upsertAction };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amalgm/tools",
|
|
3
|
-
"version": "0.1.7-preview.
|
|
3
|
+
"version": "0.1.7-preview.34545371724",
|
|
4
4
|
"description": "Local-first tool definitions, Toolbox registry, and agent execution surfaces.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"node": ">=24"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@amalgm/core": "0.
|
|
59
|
+
"@amalgm/core": "0.5.1-preview.34403852460",
|
|
60
60
|
"better-sqlite3": "^12.6.2"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
@@ -87,11 +87,11 @@
|
|
|
87
87
|
"package.json"
|
|
88
88
|
]
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "53f469e2ce16c667c6883239cc3f98c0af6943fc",
|
|
91
91
|
"amalgmSource": {
|
|
92
92
|
"repository": "amalgm-inc/amalgm-tools",
|
|
93
93
|
"branch": "preview",
|
|
94
|
-
"commit": "
|
|
95
|
-
"occurrence": "
|
|
94
|
+
"commit": "53f469e2ce16c667c6883239cc3f98c0af6943fc",
|
|
95
|
+
"occurrence": "34545371724"
|
|
96
96
|
}
|
|
97
97
|
}
|
package/skills/tools/SKILL.md
CHANGED
|
@@ -144,10 +144,16 @@ amalgm-tools show hello.say
|
|
|
144
144
|
amalgm-tools enable hello.say
|
|
145
145
|
amalgm-tools disable hello.say
|
|
146
146
|
amalgm-tools remove hello
|
|
147
|
+
amalgm-tools link canvas app-3f1c
|
|
148
|
+
amalgm-tools unlink canvas
|
|
147
149
|
amalgm-tools run hello.say --input '{"name":"Ada"}'
|
|
148
150
|
amalgm-tools connections
|
|
149
151
|
```
|
|
150
152
|
|
|
153
|
+
`link` records the app a tool belongs to (`appId`, the reverse edge of the app
|
|
154
|
+
manifest's `toolIds`); sharing the app carries the tool and sharing the tool
|
|
155
|
+
carries the app. The MCP twins are `toolbox_tool_link` and `toolbox_tool_unlink`.
|
|
156
|
+
|
|
151
157
|
Use `--state-dir DIR` to select a Toolbox and `--loadout one,two` to bound
|
|
152
158
|
`list`, `run`, or connection projection.
|
|
153
159
|
|