@amalgm/tools 0.1.4 → 0.1.5
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/PURPOSE.md +12 -38
- package/README.md +0 -22
- package/dist/artifact-files.d.ts +1 -3
- package/dist/artifact-files.js +3 -11
- package/dist/artifacts.d.ts +6 -8
- package/dist/artifacts.js +6 -19
- package/dist/definition.js +0 -10
- package/dist/http.js +1 -6
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -3
- package/dist/mcp-server.d.ts +1 -2
- package/dist/mcp-server.js +2 -3
- package/dist/mcp.d.ts +1 -2
- package/dist/mcp.js +21 -33
- package/dist/notifications.js +3 -4
- package/dist/schema.js +0 -15
- package/dist/store.d.ts +4 -17
- package/dist/store.js +41 -105
- package/dist/toolbox.d.ts +5 -13
- package/dist/toolbox.js +114 -90
- package/dist/types.d.ts +1 -30
- package/dist/updates.d.ts +1 -2
- package/dist/updates.js +1 -12
- package/docs/ENGINE_INTEGRATION.md +2 -5
- package/package.json +4 -4
- package/dist/apply-definition.d.ts +0 -12
- package/dist/apply-definition.js +0 -33
- package/dist/deployment-files.d.ts +0 -10
- package/dist/deployment-files.js +0 -38
- package/dist/deployment-types.d.ts +0 -32
- package/dist/deployment-types.js +0 -1
- package/dist/deployments.d.ts +0 -19
- package/dist/deployments.js +0 -98
- package/dist/host-mcp-tool.d.ts +0 -8
- package/dist/host-mcp-tool.js +0 -40
- package/dist/toolbox-deployments.d.ts +0 -30
- package/dist/toolbox-deployments.js +0 -125
- package/dist/toolbox-projection.d.ts +0 -13
- package/dist/toolbox-projection.js +0 -41
- package/dist/toolbox-view.d.ts +0 -35
- package/dist/toolbox-view.js +0 -75
package/dist/apply-definition.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { portableRecordSemantic } from './artifacts.js';
|
|
2
|
-
import { normalizeDefinition } from './definition.js';
|
|
3
|
-
import { assertMcpNamesUnique, id } from './ids.js';
|
|
4
|
-
/** Normalize and deploy one authoritative user definition. */
|
|
5
|
-
async function applyDefinition(options) {
|
|
6
|
-
const { definition, store, deployments, systemTools, systemActions } = options;
|
|
7
|
-
const normalizedId = id(definition.id, 'tool.id', 64);
|
|
8
|
-
if (definition.origin === 'system')
|
|
9
|
-
throw new Error('System tools can only be supplied by the embedder');
|
|
10
|
-
if (systemTools.some((tool) => tool.id === normalizedId))
|
|
11
|
-
throw new Error(`System tool is immutable: ${normalizedId}`);
|
|
12
|
-
const existing = store.getTool(normalizedId);
|
|
13
|
-
const oldActions = new Map(store.actionsFor(normalizedId).map((action) => [action.id, action]));
|
|
14
|
-
const normalized = normalizeDefinition(definition, existing || undefined);
|
|
15
|
-
normalized.actions = normalized.actions.map((action) => ({
|
|
16
|
-
...action, createdAt: oldActions.get(action.id)?.createdAt || action.createdAt,
|
|
17
|
-
}));
|
|
18
|
-
assertMcpNamesUnique([
|
|
19
|
-
...systemActions,
|
|
20
|
-
...store.catalog().actions.filter((action) => action.toolId !== normalized.tool.id),
|
|
21
|
-
...normalized.actions,
|
|
22
|
-
]);
|
|
23
|
-
const unchanged = existing && portableRecordSemantic(existing) === portableRecordSemantic(normalized.tool)
|
|
24
|
-
&& normalized.actions.length === oldActions.size
|
|
25
|
-
&& normalized.actions.every((action) => portableRecordSemantic(action)
|
|
26
|
-
=== portableRecordSemantic(oldActions.get(action.id)));
|
|
27
|
-
if (unchanged) {
|
|
28
|
-
return { tool: existing, actions: [...oldActions.values()].sort((a, b) => a.id.localeCompare(b.id)) };
|
|
29
|
-
}
|
|
30
|
-
await deployments.activateLocal(normalized);
|
|
31
|
-
return normalized;
|
|
32
|
-
}
|
|
33
|
-
export { applyDefinition };
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ToolDeployment } from './types.js';
|
|
2
|
-
/** Host effect for the portable, immutable deployment document tree. */
|
|
3
|
-
declare class DeploymentFiles {
|
|
4
|
-
private readonly root;
|
|
5
|
-
constructor(root: string);
|
|
6
|
-
file(deployment: ToolDeployment): string;
|
|
7
|
-
write(deployment: ToolDeployment): string;
|
|
8
|
-
materialize(deployments: readonly ToolDeployment[]): void;
|
|
9
|
-
}
|
|
10
|
-
export { DeploymentFiles };
|
package/dist/deployment-files.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { canonicalJson } from './deployments.js';
|
|
4
|
-
/** Host effect for the portable, immutable deployment document tree. */
|
|
5
|
-
class DeploymentFiles {
|
|
6
|
-
root;
|
|
7
|
-
constructor(root) {
|
|
8
|
-
this.root = root;
|
|
9
|
-
}
|
|
10
|
-
file(deployment) {
|
|
11
|
-
return path.join(this.root, deployment.subjectId, 'deployments', `${deployment.id}.json`);
|
|
12
|
-
}
|
|
13
|
-
write(deployment) {
|
|
14
|
-
const target = this.file(deployment);
|
|
15
|
-
const bytes = `${JSON.stringify(deployment, null, 2)}\n`;
|
|
16
|
-
try {
|
|
17
|
-
const existing = fs.readFileSync(target, 'utf8');
|
|
18
|
-
if (canonicalJson(JSON.parse(existing)) !== canonicalJson(deployment)) {
|
|
19
|
-
throw new Error(`Deployment file is immutable: ${deployment.id}`);
|
|
20
|
-
}
|
|
21
|
-
return target;
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
if (error.code !== 'ENOENT')
|
|
25
|
-
throw error;
|
|
26
|
-
}
|
|
27
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
28
|
-
const temporary = `${target}.tmp`;
|
|
29
|
-
fs.writeFileSync(temporary, bytes, { flag: 'wx' });
|
|
30
|
-
fs.renameSync(temporary, target);
|
|
31
|
-
return target;
|
|
32
|
-
}
|
|
33
|
-
materialize(deployments) {
|
|
34
|
-
for (const deployment of deployments)
|
|
35
|
-
this.write(deployment);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
export { DeploymentFiles };
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { ApplyResult } from './types.js';
|
|
2
|
-
interface ToolDeployment {
|
|
3
|
-
schemaVersion: 1;
|
|
4
|
-
kind: 'amalgm-tool-deployment';
|
|
5
|
-
id: string;
|
|
6
|
-
/** The stable tool id, named generically to match @amalgm/live. */
|
|
7
|
-
subjectId: string;
|
|
8
|
-
previousDeploymentId: string | null;
|
|
9
|
-
definition: ApplyResult | null;
|
|
10
|
-
contentHash: string;
|
|
11
|
-
createdAt: string;
|
|
12
|
-
}
|
|
13
|
-
interface ToolDeploymentActivation {
|
|
14
|
-
type: 'deployment.activate';
|
|
15
|
-
deployment: ToolDeployment;
|
|
16
|
-
}
|
|
17
|
-
interface ToolDeploymentSnapshot {
|
|
18
|
-
version: 1;
|
|
19
|
-
deployments: Record<string, ToolDeployment>;
|
|
20
|
-
heads: Record<string, string>;
|
|
21
|
-
}
|
|
22
|
-
interface ToolDeploymentSurface {
|
|
23
|
-
readonly contract: 'amalgm.tools.deployments@1';
|
|
24
|
-
observeEdits(emit: (operation: ToolDeploymentActivation) => void): () => void;
|
|
25
|
-
applyRemote(operation: ToolDeploymentActivation, context: {
|
|
26
|
-
readonly hydrating: boolean;
|
|
27
|
-
}): void | Promise<void>;
|
|
28
|
-
applySnapshot(snapshot: ToolDeploymentSnapshot, context: {
|
|
29
|
-
readonly reason: 'hydration' | 'recovery';
|
|
30
|
-
}): void | Promise<void>;
|
|
31
|
-
}
|
|
32
|
-
export type { ToolDeployment, ToolDeploymentActivation, ToolDeploymentSnapshot, ToolDeploymentSurface, };
|
package/dist/deployment-types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/deployments.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { ActionRecord, ApplyResult, ToolDeploymentActivation, ToolDeploymentSnapshot, ToolRecord } from './types.js';
|
|
2
|
-
declare const TOOL_DEPLOYMENT_CONTRACT: "amalgm.tools.deployments@1";
|
|
3
|
-
declare const TOOL_DEPLOYMENT_KIND: "amalgm-tool-deployment";
|
|
4
|
-
declare const TOOL_DEPLOYMENT_SCHEMA_VERSION: 1;
|
|
5
|
-
declare function canonicalJson(value: unknown): string;
|
|
6
|
-
declare function createToolDeployment(input: {
|
|
7
|
-
toolId: string;
|
|
8
|
-
previousDeploymentId: string | null;
|
|
9
|
-
definition: ApplyResult | null;
|
|
10
|
-
createdAt: string;
|
|
11
|
-
}): ToolDeploymentActivation;
|
|
12
|
-
declare function assertToolDeploymentActivation(value: unknown): asserts value is ToolDeploymentActivation;
|
|
13
|
-
declare function deploymentRevisionId(input: {
|
|
14
|
-
heads: Readonly<Record<string, string>>;
|
|
15
|
-
systemTools?: readonly ToolRecord[];
|
|
16
|
-
systemActions?: readonly ActionRecord[];
|
|
17
|
-
}): string;
|
|
18
|
-
declare function emptyToolDeploymentSnapshot(): ToolDeploymentSnapshot;
|
|
19
|
-
export { TOOL_DEPLOYMENT_CONTRACT, TOOL_DEPLOYMENT_KIND, TOOL_DEPLOYMENT_SCHEMA_VERSION, assertToolDeploymentActivation, canonicalJson, createToolDeployment, deploymentRevisionId, emptyToolDeploymentSnapshot, };
|
package/dist/deployments.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
const TOOL_DEPLOYMENT_CONTRACT = 'amalgm.tools.deployments@1';
|
|
3
|
-
const TOOL_DEPLOYMENT_KIND = 'amalgm-tool-deployment';
|
|
4
|
-
const TOOL_DEPLOYMENT_SCHEMA_VERSION = 1;
|
|
5
|
-
function canonical(value) {
|
|
6
|
-
if (Array.isArray(value))
|
|
7
|
-
return value.map(canonical);
|
|
8
|
-
if (!value || typeof value !== 'object')
|
|
9
|
-
return value;
|
|
10
|
-
return Object.fromEntries(Object.entries(value)
|
|
11
|
-
.filter(([, item]) => item !== undefined)
|
|
12
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
13
|
-
.map(([key, item]) => [key, canonical(item)]));
|
|
14
|
-
}
|
|
15
|
-
function canonicalJson(value) {
|
|
16
|
-
return JSON.stringify(canonical(value));
|
|
17
|
-
}
|
|
18
|
-
function sha256(value) {
|
|
19
|
-
return createHash('sha256').update(canonicalJson(value)).digest('hex');
|
|
20
|
-
}
|
|
21
|
-
function createToolDeployment(input) {
|
|
22
|
-
const contentHash = sha256(input.definition);
|
|
23
|
-
const identity = sha256({
|
|
24
|
-
subjectId: input.toolId,
|
|
25
|
-
previousDeploymentId: input.previousDeploymentId,
|
|
26
|
-
contentHash,
|
|
27
|
-
createdAt: input.createdAt,
|
|
28
|
-
});
|
|
29
|
-
return Object.freeze({
|
|
30
|
-
type: 'deployment.activate',
|
|
31
|
-
deployment: Object.freeze({
|
|
32
|
-
schemaVersion: TOOL_DEPLOYMENT_SCHEMA_VERSION,
|
|
33
|
-
kind: TOOL_DEPLOYMENT_KIND,
|
|
34
|
-
id: `tooldep_${identity}`,
|
|
35
|
-
subjectId: input.toolId,
|
|
36
|
-
previousDeploymentId: input.previousDeploymentId,
|
|
37
|
-
definition: input.definition,
|
|
38
|
-
contentHash,
|
|
39
|
-
createdAt: input.createdAt,
|
|
40
|
-
}),
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
function assertRecord(value, label) {
|
|
44
|
-
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
45
|
-
throw new Error(`${label} must be an object`);
|
|
46
|
-
}
|
|
47
|
-
function assertToolDeploymentActivation(value) {
|
|
48
|
-
assertRecord(value, 'Tool deployment activation');
|
|
49
|
-
if (value.type !== 'deployment.activate')
|
|
50
|
-
throw new Error('Tool deployment operation must be deployment.activate');
|
|
51
|
-
assertRecord(value.deployment, 'Tool deployment');
|
|
52
|
-
const deployment = value.deployment;
|
|
53
|
-
if (deployment.schemaVersion !== TOOL_DEPLOYMENT_SCHEMA_VERSION || deployment.kind !== TOOL_DEPLOYMENT_KIND) {
|
|
54
|
-
throw new Error('Unsupported tool deployment document');
|
|
55
|
-
}
|
|
56
|
-
if (typeof deployment.id !== 'string' || !deployment.id
|
|
57
|
-
|| typeof deployment.subjectId !== 'string' || !deployment.subjectId
|
|
58
|
-
|| typeof deployment.createdAt !== 'string' || !deployment.createdAt
|
|
59
|
-
|| (deployment.previousDeploymentId !== null && typeof deployment.previousDeploymentId !== 'string')) {
|
|
60
|
-
throw new Error('Tool deployment identity is incomplete');
|
|
61
|
-
}
|
|
62
|
-
if (deployment.definition !== null) {
|
|
63
|
-
assertRecord(deployment.definition, 'Tool deployment definition');
|
|
64
|
-
assertRecord(deployment.definition.tool, 'Tool deployment tool');
|
|
65
|
-
if (deployment.definition.tool.id !== deployment.subjectId) {
|
|
66
|
-
throw new Error('Tool deployment subject does not match its tool');
|
|
67
|
-
}
|
|
68
|
-
if (deployment.definition.tool.origin === 'system') {
|
|
69
|
-
throw new Error('System tools cannot arrive as user deployments');
|
|
70
|
-
}
|
|
71
|
-
if (!Array.isArray(deployment.definition.actions)
|
|
72
|
-
|| deployment.definition.actions.some((action) => action.toolId !== deployment.subjectId)) {
|
|
73
|
-
throw new Error('Tool deployment actions must all belong to its subject');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (deployment.contentHash !== sha256(deployment.definition)) {
|
|
77
|
-
throw new Error(`Tool deployment content hash is invalid: ${deployment.id}`);
|
|
78
|
-
}
|
|
79
|
-
const expected = createToolDeployment({
|
|
80
|
-
toolId: deployment.subjectId,
|
|
81
|
-
previousDeploymentId: deployment.previousDeploymentId,
|
|
82
|
-
definition: deployment.definition,
|
|
83
|
-
createdAt: deployment.createdAt,
|
|
84
|
-
}).deployment.id;
|
|
85
|
-
if (deployment.id !== expected)
|
|
86
|
-
throw new Error(`Tool deployment id is invalid: ${deployment.id}`);
|
|
87
|
-
}
|
|
88
|
-
function deploymentRevisionId(input) {
|
|
89
|
-
return `toolbox_${sha256({
|
|
90
|
-
heads: input.heads,
|
|
91
|
-
systemTools: input.systemTools || [],
|
|
92
|
-
systemActions: input.systemActions || [],
|
|
93
|
-
})}`;
|
|
94
|
-
}
|
|
95
|
-
function emptyToolDeploymentSnapshot() {
|
|
96
|
-
return { version: 1, deployments: {}, heads: {} };
|
|
97
|
-
}
|
|
98
|
-
export { TOOL_DEPLOYMENT_CONTRACT, TOOL_DEPLOYMENT_KIND, TOOL_DEPLOYMENT_SCHEMA_VERSION, assertToolDeploymentActivation, canonicalJson, createToolDeployment, deploymentRevisionId, emptyToolDeploymentSnapshot, };
|
package/dist/host-mcp-tool.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { HostMcpToolDefinitionInput, ToolDefinition } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Project an owning SDK's MCP descriptors into one immutable first-party
|
|
4
|
-
* Toolbox tool. The descriptors remain authoritative; this adapter does not
|
|
5
|
-
* copy or reinterpret action schemas.
|
|
6
|
-
*/
|
|
7
|
-
declare function defineHostMcpTool(input: HostMcpToolDefinitionInput): ToolDefinition;
|
|
8
|
-
export { defineHostMcpTool };
|
package/dist/host-mcp-tool.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { defineTool } from './definition.js';
|
|
2
|
-
const EMPTY_INPUT = {
|
|
3
|
-
type: 'object',
|
|
4
|
-
properties: {},
|
|
5
|
-
additionalProperties: false,
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Project an owning SDK's MCP descriptors into one immutable first-party
|
|
9
|
-
* Toolbox tool. The descriptors remain authoritative; this adapter does not
|
|
10
|
-
* copy or reinterpret action schemas.
|
|
11
|
-
*/
|
|
12
|
-
function defineHostMcpTool(input) {
|
|
13
|
-
const actions = input.tools.map((tool) => ({
|
|
14
|
-
name: tool.name,
|
|
15
|
-
...(tool.description ? { description: tool.description } : {}),
|
|
16
|
-
inputSchema: tool.inputSchema || EMPTY_INPUT,
|
|
17
|
-
target: { name: tool.name },
|
|
18
|
-
}));
|
|
19
|
-
return defineTool({
|
|
20
|
-
id: input.id,
|
|
21
|
-
name: input.name,
|
|
22
|
-
...(input.description ? { description: input.description } : {}),
|
|
23
|
-
owner: input.owner || 'amalgm',
|
|
24
|
-
origin: 'system',
|
|
25
|
-
source: {
|
|
26
|
-
type: 'mcp',
|
|
27
|
-
transport: 'host',
|
|
28
|
-
serverName: input.serverName,
|
|
29
|
-
route: input.route,
|
|
30
|
-
},
|
|
31
|
-
actions,
|
|
32
|
-
policy: { firstParty: true },
|
|
33
|
-
...(input.display ? { display: structuredClone(input.display) } : {}),
|
|
34
|
-
metadata: {
|
|
35
|
-
platform: true,
|
|
36
|
-
...(input.metadata ? structuredClone(input.metadata) : {}),
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
export { defineHostMcpTool };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { DeploymentFiles } from './deployment-files.js';
|
|
2
|
-
import { Store } from './store.js';
|
|
3
|
-
import type { ActionRecord, ApplyResult, ToolDeployment, ToolDeploymentActivation, ToolDeploymentSnapshot, ToolDeploymentSurface, ToolRecord, ToolboxOptions } from './types.js';
|
|
4
|
-
interface DeploymentServiceOptions {
|
|
5
|
-
store: Store;
|
|
6
|
-
files: DeploymentFiles;
|
|
7
|
-
systemTools: readonly ToolRecord[];
|
|
8
|
-
systemActions: readonly ActionRecord[];
|
|
9
|
-
project(toolId: string): Promise<void>;
|
|
10
|
-
replaceProjection(previousToolIds: readonly string[]): Promise<void>;
|
|
11
|
-
onDeployment?: ToolboxOptions['onDeployment'];
|
|
12
|
-
}
|
|
13
|
-
/** The Toolbox deployment state machine; adapters only observe its operations. */
|
|
14
|
-
declare class ToolboxDeployments {
|
|
15
|
-
private readonly options;
|
|
16
|
-
private readonly observers;
|
|
17
|
-
constructor(options: DeploymentServiceOptions);
|
|
18
|
-
adoptLegacy(): void;
|
|
19
|
-
activateLocal(definition: ApplyResult | null, deletedToolId?: string): Promise<void>;
|
|
20
|
-
current(toolId: string): ToolDeployment | null;
|
|
21
|
-
get(deploymentId: string): ToolDeployment | null;
|
|
22
|
-
history(toolId: string): ToolDeployment[];
|
|
23
|
-
snapshot(): ToolDeploymentSnapshot;
|
|
24
|
-
activateRemote(activation: ToolDeploymentActivation): Promise<ApplyResult | null>;
|
|
25
|
-
applySnapshot(snapshot: ToolDeploymentSnapshot): Promise<void>;
|
|
26
|
-
surface(): ToolDeploymentSurface;
|
|
27
|
-
private validateActivation;
|
|
28
|
-
private assertNotSystem;
|
|
29
|
-
}
|
|
30
|
-
export { ToolboxDeployments };
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { TOOL_DEPLOYMENT_CONTRACT, assertToolDeploymentActivation, createToolDeployment, } from './deployments.js';
|
|
2
|
-
import { assertMcpNamesUnique, id } from './ids.js';
|
|
3
|
-
/** The Toolbox deployment state machine; adapters only observe its operations. */
|
|
4
|
-
class ToolboxDeployments {
|
|
5
|
-
options;
|
|
6
|
-
observers = new Set();
|
|
7
|
-
constructor(options) {
|
|
8
|
-
this.options = options;
|
|
9
|
-
}
|
|
10
|
-
adoptLegacy() {
|
|
11
|
-
const { store, systemTools, files } = this.options;
|
|
12
|
-
for (const tool of store.catalog().tools) {
|
|
13
|
-
if (store.currentDeploymentId(tool.id) || systemTools.some((system) => system.id === tool.id))
|
|
14
|
-
continue;
|
|
15
|
-
store.adoptDeployment(createToolDeployment({
|
|
16
|
-
toolId: tool.id,
|
|
17
|
-
previousDeploymentId: null,
|
|
18
|
-
definition: { tool, actions: store.actionsFor(tool.id) },
|
|
19
|
-
createdAt: tool.updatedAt,
|
|
20
|
-
}));
|
|
21
|
-
}
|
|
22
|
-
files.materialize(store.allDeployments());
|
|
23
|
-
}
|
|
24
|
-
async activateLocal(definition, deletedToolId) {
|
|
25
|
-
const toolId = definition?.tool.id || deletedToolId;
|
|
26
|
-
if (!toolId)
|
|
27
|
-
throw new Error('Tool deployment requires a stable tool id');
|
|
28
|
-
const activation = createToolDeployment({
|
|
29
|
-
toolId,
|
|
30
|
-
previousDeploymentId: this.options.store.currentDeploymentId(toolId),
|
|
31
|
-
definition,
|
|
32
|
-
createdAt: definition?.tool.updatedAt || new Date().toISOString(),
|
|
33
|
-
});
|
|
34
|
-
const applied = this.options.store.applyDeployment(activation);
|
|
35
|
-
if (!applied.changed)
|
|
36
|
-
return;
|
|
37
|
-
this.options.files.write(activation.deployment);
|
|
38
|
-
await this.options.project(toolId);
|
|
39
|
-
for (const observer of this.observers)
|
|
40
|
-
observer(activation);
|
|
41
|
-
await this.options.onDeployment?.(activation);
|
|
42
|
-
}
|
|
43
|
-
current(toolId) {
|
|
44
|
-
const value = id(toolId, 'tool id');
|
|
45
|
-
const deploymentId = this.options.store.currentDeploymentId(value);
|
|
46
|
-
return deploymentId ? this.options.store.getDeployment(deploymentId) : null;
|
|
47
|
-
}
|
|
48
|
-
get(deploymentId) {
|
|
49
|
-
return this.options.store.getDeployment(id(deploymentId, 'deployment id', 96));
|
|
50
|
-
}
|
|
51
|
-
history(toolId) {
|
|
52
|
-
return this.options.store.deploymentsFor(id(toolId, 'tool id'));
|
|
53
|
-
}
|
|
54
|
-
snapshot() {
|
|
55
|
-
return this.options.store.deploymentSnapshot();
|
|
56
|
-
}
|
|
57
|
-
async activateRemote(activation) {
|
|
58
|
-
this.validateActivation(activation);
|
|
59
|
-
const applied = this.options.store.applyDeployment(activation);
|
|
60
|
-
if (!applied.changed)
|
|
61
|
-
return applied.result;
|
|
62
|
-
this.options.files.write(activation.deployment);
|
|
63
|
-
await this.options.project(activation.deployment.subjectId);
|
|
64
|
-
return applied.result;
|
|
65
|
-
}
|
|
66
|
-
async applySnapshot(snapshot) {
|
|
67
|
-
if (!snapshot || snapshot.version !== 1 || !snapshot.deployments || !snapshot.heads) {
|
|
68
|
-
throw new Error('Invalid tool deployment snapshot');
|
|
69
|
-
}
|
|
70
|
-
for (const [deploymentId, deployment] of Object.entries(snapshot.deployments)) {
|
|
71
|
-
this.validateActivation({ type: 'deployment.activate', deployment }, false);
|
|
72
|
-
if (deploymentId !== deployment.id)
|
|
73
|
-
throw new Error(`Deployment snapshot key mismatch: ${deploymentId}`);
|
|
74
|
-
}
|
|
75
|
-
const currentDefinitions = [];
|
|
76
|
-
for (const [toolId, deploymentId] of Object.entries(snapshot.heads)) {
|
|
77
|
-
const deployment = snapshot.deployments[deploymentId];
|
|
78
|
-
if (!deployment || deployment.subjectId !== toolId) {
|
|
79
|
-
throw new Error(`Deployment snapshot head is invalid: ${toolId}`);
|
|
80
|
-
}
|
|
81
|
-
this.assertNotSystem(toolId);
|
|
82
|
-
if (deployment.definition)
|
|
83
|
-
currentDefinitions.push(deployment.definition);
|
|
84
|
-
}
|
|
85
|
-
assertMcpNamesUnique([
|
|
86
|
-
...this.options.systemActions,
|
|
87
|
-
...currentDefinitions.flatMap((definition) => definition.actions),
|
|
88
|
-
]);
|
|
89
|
-
const previousToolIds = this.options.store.catalog().tools.map((tool) => tool.id);
|
|
90
|
-
this.options.store.replaceDeploymentSnapshot(snapshot);
|
|
91
|
-
this.options.files.materialize(Object.values(snapshot.deployments));
|
|
92
|
-
await this.options.replaceProjection(previousToolIds);
|
|
93
|
-
}
|
|
94
|
-
surface() {
|
|
95
|
-
return Object.freeze({
|
|
96
|
-
contract: TOOL_DEPLOYMENT_CONTRACT,
|
|
97
|
-
observeEdits: (emit) => {
|
|
98
|
-
this.observers.add(emit);
|
|
99
|
-
return () => this.observers.delete(emit);
|
|
100
|
-
},
|
|
101
|
-
applyRemote: async (operation) => {
|
|
102
|
-
await this.activateRemote(operation);
|
|
103
|
-
},
|
|
104
|
-
applySnapshot: (snapshot) => this.applySnapshot(snapshot),
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
validateActivation(activation, checkNames = true) {
|
|
108
|
-
assertToolDeploymentActivation(activation);
|
|
109
|
-
const deployment = activation.deployment;
|
|
110
|
-
this.assertNotSystem(deployment.subjectId);
|
|
111
|
-
if (checkNames && deployment.definition) {
|
|
112
|
-
assertMcpNamesUnique([
|
|
113
|
-
...this.options.systemActions,
|
|
114
|
-
...this.options.store.catalog().actions.filter((action) => action.toolId !== deployment.subjectId),
|
|
115
|
-
...deployment.definition.actions,
|
|
116
|
-
]);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
assertNotSystem(toolId) {
|
|
120
|
-
if (this.options.systemTools.some((tool) => tool.id === toolId)) {
|
|
121
|
-
throw new Error(`System tool is immutable: ${toolId}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
export { ToolboxDeployments };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { ArtifactFiles } from './artifact-files.js';
|
|
2
|
-
import type { Catalog, ToolboxOptions } from './types.js';
|
|
3
|
-
/** Current-catalog compatibility projections; deployments remain authority. */
|
|
4
|
-
declare class ToolboxProjection {
|
|
5
|
-
private readonly artifacts;
|
|
6
|
-
private readonly catalog;
|
|
7
|
-
private readonly onChange?;
|
|
8
|
-
constructor(artifacts: ArtifactFiles, catalog: () => Catalog, onChange?: ToolboxOptions['onChange']);
|
|
9
|
-
boot(): void;
|
|
10
|
-
changed(toolId: string): Promise<void>;
|
|
11
|
-
replaced(previousToolIds: readonly string[]): Promise<void>;
|
|
12
|
-
}
|
|
13
|
-
export { ToolboxProjection };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/** Current-catalog compatibility projections; deployments remain authority. */
|
|
2
|
-
class ToolboxProjection {
|
|
3
|
-
artifacts;
|
|
4
|
-
catalog;
|
|
5
|
-
onChange;
|
|
6
|
-
constructor(artifacts, catalog, onChange) {
|
|
7
|
-
this.artifacts = artifacts;
|
|
8
|
-
this.catalog = catalog;
|
|
9
|
-
this.onChange = onChange;
|
|
10
|
-
}
|
|
11
|
-
boot() {
|
|
12
|
-
this.artifacts.migrateLegacy();
|
|
13
|
-
this.artifacts.materialize(this.catalog());
|
|
14
|
-
}
|
|
15
|
-
async changed(toolId) {
|
|
16
|
-
const catalog = this.catalog();
|
|
17
|
-
const tool = catalog.tools.find((candidate) => candidate.id === toolId);
|
|
18
|
-
if (tool && tool.origin !== 'system') {
|
|
19
|
-
this.artifacts.writeTool({
|
|
20
|
-
tool,
|
|
21
|
-
actions: catalog.actions.filter((action) => action.toolId === toolId),
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
else if (!tool) {
|
|
25
|
-
this.artifacts.removeTool(toolId);
|
|
26
|
-
}
|
|
27
|
-
this.artifacts.writeIndex(catalog);
|
|
28
|
-
await this.onChange?.(catalog);
|
|
29
|
-
}
|
|
30
|
-
async replaced(previousToolIds) {
|
|
31
|
-
const catalog = this.catalog();
|
|
32
|
-
const currentToolIds = new Set(catalog.tools.map((tool) => tool.id));
|
|
33
|
-
for (const toolId of previousToolIds) {
|
|
34
|
-
if (!currentToolIds.has(toolId))
|
|
35
|
-
this.artifacts.removeTool(toolId);
|
|
36
|
-
}
|
|
37
|
-
this.artifacts.materialize(catalog);
|
|
38
|
-
await this.onChange?.(catalog);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export { ToolboxProjection };
|
package/dist/toolbox-view.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { ActionRecord, ApplyResult, CallOptions, Catalog, LoadoutInput, ToolDriver, ToolQuery, ToolRecord, ToolResult } from './types.js';
|
|
2
|
-
declare class ToolboxView {
|
|
3
|
-
private readonly readCatalog;
|
|
4
|
-
private readonly drivers;
|
|
5
|
-
constructor(readCatalog: () => Catalog, drivers: ReadonlyMap<string, ToolDriver>);
|
|
6
|
-
catalog(): Catalog;
|
|
7
|
-
list(loadout?: LoadoutInput): Array<{
|
|
8
|
-
tool: ToolRecord;
|
|
9
|
-
actions: ActionRecord[];
|
|
10
|
-
}>;
|
|
11
|
-
query(filters?: ToolQuery): {
|
|
12
|
-
tool: ToolRecord;
|
|
13
|
-
actions: ActionRecord[];
|
|
14
|
-
}[];
|
|
15
|
-
callable(loadout?: LoadoutInput, filters?: ToolQuery): {
|
|
16
|
-
tool: ToolRecord;
|
|
17
|
-
action: ActionRecord;
|
|
18
|
-
}[];
|
|
19
|
-
get(toolId: string): ApplyResult | null;
|
|
20
|
-
action(actionId: string): ActionRecord | null;
|
|
21
|
-
resolve(toolId: string, actionReference: string, loadout?: LoadoutInput): {
|
|
22
|
-
tool: ToolRecord;
|
|
23
|
-
action: ActionRecord;
|
|
24
|
-
} | null;
|
|
25
|
-
resolveCallable(toolId: string, actionReference: string, loadout?: LoadoutInput, filters?: ToolQuery): {
|
|
26
|
-
tool: ToolRecord;
|
|
27
|
-
action: ActionRecord;
|
|
28
|
-
} | null;
|
|
29
|
-
connections(loadout?: LoadoutInput): ToolRecord[];
|
|
30
|
-
call(actionId: string, input?: unknown, options?: CallOptions): Promise<ToolResult>;
|
|
31
|
-
hasDriver(tool: ToolRecord): boolean;
|
|
32
|
-
callMcp(name: string, input?: unknown, options?: CallOptions): Promise<ToolResult>;
|
|
33
|
-
private driverFor;
|
|
34
|
-
}
|
|
35
|
-
export { ToolboxView };
|
package/dist/toolbox-view.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { id, mcpName } from './ids.js';
|
|
2
|
-
import { validateInput } from './input.js';
|
|
3
|
-
import { callableActions, queryTools, resolveAction, resolveCallableAction } from './query.js';
|
|
4
|
-
import { findSelected, selected } from './selection.js';
|
|
5
|
-
class ToolboxView {
|
|
6
|
-
readCatalog;
|
|
7
|
-
drivers;
|
|
8
|
-
constructor(readCatalog, drivers) {
|
|
9
|
-
this.readCatalog = readCatalog;
|
|
10
|
-
this.drivers = drivers;
|
|
11
|
-
}
|
|
12
|
-
catalog() { return this.readCatalog(); }
|
|
13
|
-
list(loadout) {
|
|
14
|
-
const catalog = this.catalog();
|
|
15
|
-
const runnable = selected(catalog, loadout);
|
|
16
|
-
return catalog.tools.flatMap((tool) => {
|
|
17
|
-
const actions = runnable.filter((item) => item.tool.id === tool.id).map((item) => item.action);
|
|
18
|
-
if (loadout !== undefined && actions.length === 0)
|
|
19
|
-
return [];
|
|
20
|
-
return [{ tool, actions }];
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
query(filters = {}) { return queryTools(this, filters); }
|
|
24
|
-
callable(loadout, filters = {}) {
|
|
25
|
-
return callableActions(this, loadout, filters);
|
|
26
|
-
}
|
|
27
|
-
get(toolId) {
|
|
28
|
-
const value = id(toolId, 'tool id');
|
|
29
|
-
const catalog = this.catalog();
|
|
30
|
-
const tool = catalog.tools.find((candidate) => candidate.id === value);
|
|
31
|
-
return tool ? { tool, actions: catalog.actions.filter((action) => action.toolId === value) } : null;
|
|
32
|
-
}
|
|
33
|
-
action(actionId) {
|
|
34
|
-
const value = id(actionId, 'action id');
|
|
35
|
-
return this.catalog().actions.find((action) => action.id === value) || null;
|
|
36
|
-
}
|
|
37
|
-
resolve(toolId, actionReference, loadout) {
|
|
38
|
-
return resolveAction(this, toolId, actionReference, loadout);
|
|
39
|
-
}
|
|
40
|
-
resolveCallable(toolId, actionReference, loadout, filters = {}) {
|
|
41
|
-
return resolveCallableAction(this, toolId, actionReference, loadout, filters);
|
|
42
|
-
}
|
|
43
|
-
connections(loadout) {
|
|
44
|
-
const catalog = this.catalog();
|
|
45
|
-
const ids = loadout === undefined ? null : new Set(Array.isArray(loadout) ? loadout : loadout.toolIds);
|
|
46
|
-
return catalog.tools.filter((tool) => {
|
|
47
|
-
if (tool.status !== 'enabled' || tool.source.type !== 'mcp' || tool.origin === 'system')
|
|
48
|
-
return false;
|
|
49
|
-
if (!ids)
|
|
50
|
-
return true;
|
|
51
|
-
return ids.has(tool.id) || catalog.actions.some((action) => action.toolId === tool.id && ids.has(action.id));
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
async call(actionId, input = {}, options = {}) {
|
|
55
|
-
const resolved = findSelected(this.catalog(), id(actionId, 'action id'), options.loadout);
|
|
56
|
-
if (!resolved)
|
|
57
|
-
throw new Error(`Action is unavailable: ${actionId}`);
|
|
58
|
-
const driver = this.driverFor(resolved.tool);
|
|
59
|
-
if (!driver)
|
|
60
|
-
throw new Error(`No ${resolved.tool.source.type} driver is configured for ${resolved.tool.id}`);
|
|
61
|
-
return driver.call({ ...resolved, input: validateInput(resolved.action.inputSchema, input), options });
|
|
62
|
-
}
|
|
63
|
-
hasDriver(tool) { return this.driverFor(tool) !== null; }
|
|
64
|
-
async callMcp(name, input = {}, options = {}) {
|
|
65
|
-
const resolved = selected(this.catalog(), options.loadout).find(({ action }) => mcpName(action) === name);
|
|
66
|
-
if (!resolved)
|
|
67
|
-
throw new Error(`Unknown MCP tool: ${name}`);
|
|
68
|
-
return this.call(resolved.action.id, input, options);
|
|
69
|
-
}
|
|
70
|
-
driverFor(tool) {
|
|
71
|
-
const driver = this.drivers.get(tool.source.type);
|
|
72
|
-
return driver && (driver.supports?.(tool) ?? true) ? driver : null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export { ToolboxView };
|