@amalgm/tools 0.1.7-preview.37556891038 → 0.1.7-preview.39065361112

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 CHANGED
@@ -7,7 +7,7 @@ standalone product or inside Amalgm. It serves people building agents,
7
7
  automations, and applications that need one small local source of truth for
8
8
  CLI, HTTP API, GraphQL, and MCP tools. When the product is healthy, every callable
9
9
  action has one stable identity and one owning tool, a selected loadout exposes
10
- only its granted capabilities, and the SDK, CLI, and MCP surfaces all observe
10
+ only its granted capabilities, and the SDK, MCP, and HTTP surfaces all observe
11
11
  and execute the same catalog.
12
12
 
13
13
  Amalgm Shell is the active machine composition root. This repository owns the
@@ -22,8 +22,8 @@ and parity evidence only.
22
22
  - A **tool** is a stable provider or connector identity and its execution
23
23
  source.
24
24
  - An **action** is one model-callable capability owned by exactly one tool.
25
- - A **Toolbox** is the sole catalog and mutation authority for one local state
26
- directory.
25
+ - A **Toolbox** is the sole catalog and mutation authority for the folders its
26
+ host hands it.
27
27
  - A **tool deployment** is one immutable definition of a stable tool identity,
28
28
  including its complete authoritative action set; activation appends the
29
29
  deployment and moves that tool's current pointer atomically.
@@ -75,13 +75,13 @@ locked dependency graph on the supported Node toolchain.
75
75
  2. Tool ids are stable, globally unique within one Toolbox, and never change
76
76
  as a side effect of renaming display text.
77
77
  3. A tool's portable source of truth is its immutable deployment history and
78
- current deployment pointer. SQLite tables, WAL files, catalog indexes, and
79
- compatibility artifacts are local projections; SDK, CLI, MCP, HTTP, and UI
78
+ current deployment pointer. SQLite tables, WAL files, the catalog index, and
79
+ each tool's `.amalgm-tool.json` are projections; SDK, CLI, MCP, HTTP, and UI
80
80
  adapters never keep parallel registries.
81
81
  4. Applying a semantically changed tool definition mints one deployment and
82
82
  atomically activates its complete action set. Applying equal semantics is a
83
- no-op; rollback and deletion mint new deployments rather than rewriting or
84
- removing history.
83
+ no-op; rollback and deletion mint new deployments rather than rewriting
84
+ history.
85
85
  5. Deleting a tool deletes all of its actions in the same transaction; an
86
86
  orphan action can never be observed.
87
87
  6. Disabled tools expose and execute no actions. Disabled actions are likewise
@@ -122,17 +122,19 @@ locked dependency graph on the supported Node toolchain.
122
122
  official MCP descriptors or expose its explicitly legacy email adapter; it
123
123
  never becomes a second durable delivery authority.
124
124
  21. Reopening a Toolbox preserves the temporal fields of every semantically
125
- unchanged system projection already present in its portable index; boot
126
- never rewrites tracked bytes merely to stamp the current machine's time.
125
+ unchanged system projection already present in its index; boot never
126
+ rewrites those bytes merely to stamp the current time.
127
127
  22. The Toolbox exposes the versioned `deployment.activate` operation and its
128
128
  exact definition through one Live surface; SQLite pages are never part of
129
129
  that contract. A received activation materializes locally without echo,
130
130
  retries are idempotent, and an existing deployment id can never acquire
131
131
  different bytes.
132
- 23. A host may separate the synced deployment directory from its machine-local
133
- database. Amalgm Shell stores immutable deployment documents beneath
134
- `users/<email>/toolbox/<tool-id>/deployments/` while keeping SQLite
135
- coordination state below the machine boundary.
132
+ 23. The host hands the Toolbox three folders and Tools never picks one. `root`
133
+ holds one `<Tool Name>/` folder per user tool with `.amalgm-tool.json`,
134
+ immutable `history/<deployment-id>.json` records, and a computer-only
135
+ `.private/`; `dir` holds `tools.db` and `index.json`; `parked` receives a
136
+ deleted tool's `.private/`. A tool's folder follows its name, and deleting
137
+ the tool removes the files Tools wrote there.
136
138
  24. A Chat preparation selects one catalog `revisionId` derived from exact
137
139
  current deployment ids and system projections. Preparation either resolves
138
140
  that exact revision or fails; it never silently substitutes newer tools.
@@ -174,8 +176,7 @@ locked dependency graph on the supported Node toolchain.
174
176
 
175
177
  Applying the same definition twice produces the same catalog and no second
176
178
  deployment. Reopening the
177
- same system projection produces the same portable index bytes on every
178
- machine. Applying a changed action set replaces the old set atomically.
179
+ same system projection leaves the index bytes unchanged. Applying a changed action set replaces the old set atomically.
179
180
  Selecting a whole tool
180
181
  grants all of its enabled actions; selecting one action grants only that
181
182
  action. Disabling or deleting a tool immediately removes all of its actions
package/README.md CHANGED
@@ -8,7 +8,7 @@ into the machine product by `@amalgm/shell`.
8
8
  ```js
9
9
  import { defineTool, Toolbox } from '@amalgm/tools';
10
10
 
11
- const toolbox = new Toolbox({ stateDir: './.tools' });
11
+ const toolbox = new Toolbox({ root: './toolbox', dir: './.tools', parked: './.tools/parked' });
12
12
  await toolbox.apply(defineTool({
13
13
  id: 'hello',
14
14
  name: 'Hello',
@@ -29,54 +29,53 @@ const result = await toolbox.call('hello.say', { name: 'Ada' });
29
29
  toolbox.close();
30
30
  ```
31
31
 
32
- ## State directory
32
+ ## Folders
33
33
 
34
- Given no options, the Toolbox resolves its state directory through the
35
- one product state-dir law in `@amalgm/core`: `AMALGM_TOOLS_DIR` is used
36
- verbatim when set, then `AMALGM_DIR/toolbox`, then the scoped layout
37
- `~/.amalgm/users/<scope>/toolbox`. Passing `stateDir` or `databaseFile`
38
- bypasses resolution entirely.
39
-
40
- Platform hosts should separate portable deployment documents from local
41
- coordination state:
34
+ The Toolbox never picks a folder; its host hands it three. In Amalgm, Shell
35
+ passes the user's folders from `@amalgm/core/identity`:
42
36
 
43
37
  ```js
38
+ const user = userLayout(userRoot);
44
39
  const toolbox = new Toolbox({
45
- deploymentDir: '/amalgm/users/person@example.com/toolbox',
46
- databaseFile: '/machine-state/services/tools/tools.db',
40
+ root: user.toolbox,
41
+ dir: user.computer.tools,
42
+ parked: user.computer.parked,
47
43
  });
48
44
  ```
49
45
 
50
- An intentional semantic change appends
51
- `<deploymentDir>/<tool-id>/deployments/<deployment-id>.json` and atomically
52
- advances the local head. The database, WAL, `toolbox.index.json`, and legacy
53
- flat artifacts are projections and must not be synchronized. `catalog()`
54
- exposes both a local numeric `revision` for presentation freshness and the
55
- immutable `revisionId` that Chat must use for preparation.
46
+ ```
47
+ <root>/<Tool Name>/.amalgm-tool.json the tool and every action it owns
48
+ <root>/<Tool Name>/history/<id>.json one immutable record per deployment
49
+ <root>/<Tool Name>/.private/ computer-only files for the tool
50
+ <dir>/tools.db the catalog of record
51
+ <dir>/index.json the whole catalog, system tools included
52
+ ```
53
+
54
+ A tool's folder is named for the tool and follows a rename; a second tool
55
+ with the same name gets `-2`. An intentional semantic change appends
56
+ `history/<deployment-id>.json` and atomically advances the local head.
57
+ Deleting a tool moves its `.private/` to `<parked>/tool/<id>/` and removes the
58
+ files Tools wrote. `tools.db`, its WAL and `index.json` stay on the computer.
59
+ `catalog()` exposes both a local numeric `revision` for presentation freshness
60
+ and the immutable `revisionId` that Chat must use for preparation.
56
61
 
57
62
  `deploymentSurface()` implements the `amalgm.tools.deployments@1` Live
58
63
  surface. Its operation is the shared `deployment.activate` envelope. Remote
59
64
  application is idempotent and does not echo; `deploymentSnapshot()` and
60
65
  `applyDeploymentSnapshot()` are the hydration/recovery boundary.
61
66
 
62
- ## CLI
63
-
64
- ```sh
65
- amalgm-tools apply ./tool.mjs
66
- amalgm-tools list
67
- amalgm-tools run hello.say --input '{"name":"Ada"}'
68
- amalgm-tools disable hello.say
69
- amalgm-tools link canvas app-3f1c
70
- amalgm-tools connections
71
- ```
67
+ ## App links
72
68
 
73
69
  A tool may belong to an app: `appId` on the tool is the reverse edge of the
74
70
  app manifest's `toolIds`, and sharing either side carries the other. The host
75
71
  that composes Tools and Apps may pass `environment(tool)` so a linked tool
76
72
  runs knowing where its app listens.
77
73
 
78
- `amalgm-tools-mcp` serves Toolbox management and enabled action tools over
79
- newline-delimited MCP stdio.
74
+ ## MCP
75
+
76
+ `createMcpServer({ toolbox })` from `@amalgm/tools` answers MCP JSON-RPC
77
+ over the one Toolbox the host already holds. The Amalgm runtime serves it at
78
+ `/mcp/tools`, and the `amalgm tools …` command calls it there.
80
79
 
81
80
  ## HTTP
82
81
 
@@ -84,14 +83,14 @@ newline-delimited MCP stdio.
84
83
  import { Toolbox } from '@amalgm/tools';
85
84
  import { createToolboxHttpServer } from '@amalgm/tools/http';
86
85
 
87
- const toolbox = new Toolbox({ stateDir: './.tools' });
86
+ const toolbox = new Toolbox({ root: './toolbox', dir: './.tools', parked: './.tools/parked' });
88
87
  const server = createToolboxHttpServer({ toolbox });
89
88
  await server.listen(8083);
90
89
  ```
91
90
 
92
91
  The adapter serves `GET /toolbox`,
93
92
  `GET /toolbox/tools?id=...`, and `GET /toolbox/actions?id=...` routes over
94
- the same live Toolbox used by CLI and MCP consumers. `POST /toolbox/tools`
93
+ the same live Toolbox used by MCP consumers. `POST /toolbox/tools`
95
94
  connects a definition with optional write-only credentials. `PATCH /toolbox/tools`
96
95
  with `{ id, status: "disabled" }` disconnects it. `DELETE /toolbox/tools` removes
97
96
  it. `POST /toolbox/actions/call` invokes `{ id, input }`.
@@ -150,7 +149,7 @@ once, and installs that tarball on Linux, macOS and Windows before publication.
150
149
  `preview` has no checks: a push to it builds, packs and publishes directly.
151
150
  The `candidate-main`/`candidate-preview` tags are release-assembly inputs and
152
151
  never select installed runtimes. `package.json` declares this owner's gates,
153
- CLI probes, peer-only exports and lifecycle permissions. The standalone runner
152
+ peer-only exports and lifecycle permissions. The standalone runner
154
153
  under `scripts/release/` is intentionally copied across owners to preserve
155
154
  private repository access boundaries. The final publish step uses the `NPM_TOKEN`
156
155
  secret in the `npm-release` environment. Where npm trusted publishing is
@@ -2,14 +2,13 @@ import type { ActionRecord, Catalog, ToolRecord } from './types.js';
2
2
  /**
3
3
  * Tool artifact format laws — the portable representation of a tool.
4
4
  *
5
- * One compatibility artifact projects one current tool and every action it
6
- * owns together; a file never carries a second tool. Immutable deployment
7
- * documents are the portable source of truth. These artifacts, the Toolbox
8
- * database, and `toolbox.index.json` are derived views retained for current
9
- * Engine/UI readers.
5
+ * One artifact (a tool folder's `.amalgm-tool.json`) holds one current tool
6
+ * and every action it owns together; a file never carries a second tool.
7
+ * Immutable deployment documents are the portable source of truth. These
8
+ * artifacts and the index are derived views of the Toolbox database.
10
9
  *
11
- * Pure laws only: nothing here touches the filesystem. `artifact-files.ts`
12
- * is the host adapter that executes these documents and plans.
10
+ * Pure laws only: nothing here touches the filesystem. `tool-files.ts`
11
+ * writes these documents.
13
12
  *
14
13
  * DELIBERATE DEVIATION: Engine recognizes system tools by its managed
15
14
  * artifact list; this product's system tools are embedder projections
@@ -20,9 +19,7 @@ import type { ActionRecord, Catalog, ToolRecord } from './types.js';
20
19
  */
21
20
  declare const TOOL_ARTIFACT_SCHEMA_VERSION = 1;
22
21
  declare const TOOL_ARTIFACT_KIND = "amalgm-tool";
23
- declare const LEGACY_TOOLBOX_FILE_NAME = "toolbox.json";
24
- declare const LEGACY_TOOLBOX_BACKUP_FILE_NAME = "toolbox.legacy.json";
25
- declare const TOOLBOX_INDEX_FILE_NAME = "toolbox.index.json";
22
+ declare const TOOLBOX_INDEX_FILE_NAME = "index.json";
26
23
  type ArtifactRecord = Record<string, unknown>;
27
24
  interface ToolArtifactDocument {
28
25
  schemaVersion: typeof TOOL_ARTIFACT_SCHEMA_VERSION;
@@ -35,21 +32,7 @@ interface ToolboxIndexDocument {
35
32
  tools: Record<string, unknown>;
36
33
  toolActions: Record<string, unknown>;
37
34
  }
38
- interface ArtifactFileWrite {
39
- fileName: string;
40
- document: ToolArtifactDocument;
41
- }
42
- interface LegacyMigrationPlan {
43
- migrated: boolean;
44
- files: ArtifactFileWrite[];
45
- index: ToolboxIndexDocument | null;
46
- rename: {
47
- from: string;
48
- to: string;
49
- } | null;
50
- }
51
35
  declare function safeToolId(value: unknown): string;
52
- declare function userArtifactFileName(toolId: unknown): string;
53
36
  declare function artifactDocument(input: {
54
37
  tool: ToolRecord;
55
38
  actions?: readonly ActionRecord[];
@@ -59,10 +42,5 @@ declare function toolboxIndexDocument(tools: Record<string, unknown>, toolAction
59
42
  declare function catalogIndexDocument(catalog: Pick<Catalog, 'tools' | 'actions'>): ToolboxIndexDocument;
60
43
  declare function portableRecordSemantic(value: ToolRecord | ActionRecord): string;
61
44
  declare function preserveProjectionTime<T extends ToolRecord | ActionRecord>(candidate: T, previous: unknown): T;
62
- /** The migration of one legacy aggregate `toolbox.json` catalog, as a pure
63
- * plan: every user tool becomes a per-tool artifact write, the whole legacy
64
- * catalog becomes the index, and the aggregate file is renamed out of the
65
- * way only after each record has a per-tool replacement. */
66
- declare function legacyMigrationPlan(legacy: unknown): LegacyMigrationPlan;
67
- export { LEGACY_TOOLBOX_BACKUP_FILE_NAME, LEGACY_TOOLBOX_FILE_NAME, TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, legacyMigrationPlan, safeToolId, portableRecordSemantic, preserveProjectionTime, toolboxIndexDocument, userArtifactFileName, };
68
- export type { ArtifactFileWrite, LegacyMigrationPlan, ToolArtifactDocument, ToolboxIndexDocument };
45
+ export { TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, safeToolId, portableRecordSemantic, preserveProjectionTime, toolboxIndexDocument, };
46
+ export type { ToolArtifactDocument, ToolboxIndexDocument };
package/dist/artifacts.js CHANGED
@@ -1,14 +1,13 @@
1
1
  /**
2
2
  * Tool artifact format laws — the portable representation of a tool.
3
3
  *
4
- * One compatibility artifact projects one current tool and every action it
5
- * owns together; a file never carries a second tool. Immutable deployment
6
- * documents are the portable source of truth. These artifacts, the Toolbox
7
- * database, and `toolbox.index.json` are derived views retained for current
8
- * Engine/UI readers.
4
+ * One artifact (a tool folder's `.amalgm-tool.json`) holds one current tool
5
+ * and every action it owns together; a file never carries a second tool.
6
+ * Immutable deployment documents are the portable source of truth. These
7
+ * artifacts and the index are derived views of the Toolbox database.
9
8
  *
10
- * Pure laws only: nothing here touches the filesystem. `artifact-files.ts`
11
- * is the host adapter that executes these documents and plans.
9
+ * Pure laws only: nothing here touches the filesystem. `tool-files.ts`
10
+ * writes these documents.
12
11
  *
13
12
  * DELIBERATE DEVIATION: Engine recognizes system tools by its managed
14
13
  * artifact list; this product's system tools are embedder projections
@@ -19,9 +18,7 @@
19
18
  */
20
19
  const TOOL_ARTIFACT_SCHEMA_VERSION = 1;
21
20
  const TOOL_ARTIFACT_KIND = 'amalgm-tool';
22
- const LEGACY_TOOLBOX_FILE_NAME = 'toolbox.json';
23
- const LEGACY_TOOLBOX_BACKUP_FILE_NAME = 'toolbox.legacy.json';
24
- const TOOLBOX_INDEX_FILE_NAME = 'toolbox.index.json';
21
+ const TOOLBOX_INDEX_FILE_NAME = 'index.json';
25
22
  function safeToolId(value) {
26
23
  return String(value || '')
27
24
  .trim()
@@ -30,12 +27,6 @@ function safeToolId(value) {
30
27
  .replace(/\.+/g, '.')
31
28
  .replace(/^[._-]+|[._-]+$/g, '');
32
29
  }
33
- function userArtifactFileName(toolId) {
34
- const id = safeToolId(toolId);
35
- if (!id)
36
- throw new Error('tool artifact requires a stable tool id');
37
- return `tool-${id}.json`;
38
- }
39
30
  function artifactDocument(input) {
40
31
  const { tool, actions = [] } = input;
41
32
  if (!tool || typeof tool !== 'object' || !safeToolId(tool.id)) {
@@ -94,32 +85,4 @@ function preserveProjectionTime(candidate, previous) {
94
85
  return candidate;
95
86
  return { ...candidate, createdAt: record.createdAt, updatedAt: record.updatedAt };
96
87
  }
97
- /** The migration of one legacy aggregate `toolbox.json` catalog, as a pure
98
- * plan: every user tool becomes a per-tool artifact write, the whole legacy
99
- * catalog becomes the index, and the aggregate file is renamed out of the
100
- * way only after each record has a per-tool replacement. */
101
- function legacyMigrationPlan(legacy) {
102
- const parsed = legacy;
103
- if (!parsed || typeof parsed !== 'object' || !parsed.tools || typeof parsed.tools !== 'object') {
104
- return { migrated: false, files: [], index: null, rename: null };
105
- }
106
- const files = [];
107
- for (const [rawId, rawTool] of Object.entries(parsed.tools)) {
108
- const toolId = safeToolId(rawTool?.id || rawId);
109
- if (!toolId || !rawTool || typeof rawTool !== 'object' || rawTool.origin === 'system')
110
- continue;
111
- const actions = Object.values(parsed.toolActions || {})
112
- .filter((action) => action && action.toolId === toolId);
113
- files.push({
114
- fileName: userArtifactFileName(toolId),
115
- document: artifactDocument({ tool: { ...rawTool, id: toolId }, actions }),
116
- });
117
- }
118
- return {
119
- migrated: true,
120
- files,
121
- index: toolboxIndexDocument(parsed.tools || {}, parsed.toolActions || {}),
122
- rename: { from: LEGACY_TOOLBOX_FILE_NAME, to: LEGACY_TOOLBOX_BACKUP_FILE_NAME },
123
- };
124
- }
125
- export { LEGACY_TOOLBOX_BACKUP_FILE_NAME, LEGACY_TOOLBOX_FILE_NAME, TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, legacyMigrationPlan, safeToolId, portableRecordSemantic, preserveProjectionTime, toolboxIndexDocument, userArtifactFileName, };
88
+ export { TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, safeToolId, portableRecordSemantic, preserveProjectionTime, toolboxIndexDocument, };
package/dist/http.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Toolbox } from './toolbox.js';
2
- import type { Catalog, ToolboxOptions } from './types.js';
1
+ import type { Toolbox } from './toolbox.js';
2
+ import type { Catalog } from './types.js';
3
3
  /**
4
4
  * Toolbox read API.
5
5
  *
@@ -13,7 +13,7 @@ import type { Catalog, ToolboxOptions } from './types.js';
13
13
  * - domain errors are JSON with status 400; unknown routes are 404.
14
14
  *
15
15
  * Mutation routes consume current SDK definitions. The authenticated composing
16
- * host supplies the Toolbox owner; request bodies cannot select one.
16
+ * host supplies the one Toolbox it holds; request bodies cannot select one.
17
17
  */
18
18
  type Json = Record<string, unknown>;
19
19
  interface ToolboxHttpServer {
@@ -23,8 +23,8 @@ interface ToolboxHttpServer {
23
23
  close(): Promise<void>;
24
24
  }
25
25
  declare function catalogDocument(catalog: Catalog): Json;
26
- declare function createToolboxHttpServer(options?: ToolboxOptions & {
27
- toolbox?: Toolbox;
26
+ declare function createToolboxHttpServer({ toolbox }: {
27
+ toolbox: Toolbox;
28
28
  }): ToolboxHttpServer;
29
29
  export { catalogDocument, createToolboxHttpServer };
30
30
  export type { ToolboxHttpServer };
package/dist/http.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { createServer } from 'node:http';
2
2
  import { toolboxIndexDocument } from './artifacts.js';
3
- import { Toolbox } from './toolbox.js';
4
3
  import { mutateToolbox } from './http-mutations.js';
5
4
  function sourceWithoutType(source) {
6
5
  const { type: _type, ...value } = source;
@@ -37,9 +36,7 @@ async function readBody(req) {
37
36
  return {};
38
37
  return JSON.parse(Buffer.concat(chunks).toString('utf8'));
39
38
  }
40
- function createToolboxHttpServer(options = {}) {
41
- const toolbox = options.toolbox ?? new Toolbox(options);
42
- const ownsToolbox = options.toolbox === undefined;
39
+ function createToolboxHttpServer({ toolbox }) {
43
40
  const server = createServer((req, res) => {
44
41
  void (async () => {
45
42
  const method = req.method ?? 'GET';
@@ -112,8 +109,6 @@ function createToolboxHttpServer(options = {}) {
112
109
  close() {
113
110
  return new Promise((resolve, reject) => {
114
111
  server.close((error) => {
115
- if (ownsToolbox)
116
- toolbox.close();
117
112
  if (error)
118
113
  reject(error);
119
114
  else
package/dist/index.d.ts CHANGED
@@ -1,9 +1,5 @@
1
- export { ArtifactFiles } from './artifact-files.js';
2
- export { LEGACY_TOOLBOX_BACKUP_FILE_NAME, LEGACY_TOOLBOX_FILE_NAME, TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, legacyMigrationPlan, safeToolId, toolboxIndexDocument, userArtifactFileName, } from './artifacts.js';
3
- export type { ArtifactFileWrite, LegacyMigrationPlan, ToolArtifactDocument, ToolboxIndexDocument, } from './artifacts.js';
4
- export { runCli } from './cli.js';
5
- export { createToolboxCommands } from './commands.js';
6
- export type { ToolCommands } from './commands.js';
1
+ export { TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, safeToolId, toolboxIndexDocument, } from './artifacts.js';
2
+ export type { ToolArtifactDocument, ToolboxIndexDocument } from './artifacts.js';
7
3
  export { defineTool, normalizeDefinition } from './definition.js';
8
4
  export { defineHostMcpTool } from './host-mcp-tool.js';
9
5
  export { TOOL_DEPLOYMENT_CONTRACT, TOOL_DEPLOYMENT_KIND, TOOL_DEPLOYMENT_SCHEMA_VERSION, assertToolDeploymentActivation, createToolDeployment, deploymentRevisionId, emptyToolDeploymentSnapshot, } from './deployments.js';
package/dist/index.js CHANGED
@@ -1,7 +1,4 @@
1
- export { ArtifactFiles } from './artifact-files.js';
2
- export { LEGACY_TOOLBOX_BACKUP_FILE_NAME, LEGACY_TOOLBOX_FILE_NAME, TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, legacyMigrationPlan, safeToolId, toolboxIndexDocument, userArtifactFileName, } from './artifacts.js';
3
- export { runCli } from './cli.js';
4
- export { createToolboxCommands } from './commands.js';
1
+ export { TOOL_ARTIFACT_KIND, TOOL_ARTIFACT_SCHEMA_VERSION, TOOLBOX_INDEX_FILE_NAME, artifactDocument, catalogIndexDocument, isToolArtifactDocument, safeToolId, toolboxIndexDocument, } from './artifacts.js';
5
2
  export { defineTool, normalizeDefinition } from './definition.js';
6
3
  export { defineHostMcpTool } from './host-mcp-tool.js';
7
4
  export { TOOL_DEPLOYMENT_CONTRACT, TOOL_DEPLOYMENT_KIND, TOOL_DEPLOYMENT_SCHEMA_VERSION, assertToolDeploymentActivation, createToolDeployment, deploymentRevisionId, emptyToolDeploymentSnapshot, } from './deployments.js';
@@ -1,20 +1,18 @@
1
- import readline from 'node:readline';
2
- import type { Readable, Writable } from 'node:stream';
3
- import { Toolbox } from './toolbox.js';
1
+ import type { Toolbox } from './toolbox.js';
4
2
  import type { ToolboxView } from './toolbox-view.js';
5
- import type { McpOptions, ToolboxOptions } from './types.js';
3
+ import type { McpOptions } from './types.js';
6
4
  interface Request {
7
5
  jsonrpc?: string;
8
6
  id?: string | number;
9
7
  method: string;
10
8
  params?: Record<string, any>;
11
9
  }
12
- declare function createMcpServer<T extends Toolbox | ToolboxView = Toolbox>(options?: ToolboxOptions & {
13
- toolbox?: T;
10
+ /** MCP JSON-RPC over the one Toolbox (or prepared view) the host already holds. */
11
+ declare function createMcpServer<T extends Toolbox | ToolboxView>(options: {
12
+ toolbox: T;
14
13
  mcp?: McpOptions;
15
14
  }): {
16
15
  toolbox: T;
17
16
  handle: (request: Request, context?: unknown) => Promise<unknown>;
18
- start: (input?: Readable, output?: Writable) => readline.Interface;
19
17
  };
20
18
  export { createMcpServer };
@@ -1,12 +1,11 @@
1
- import readline from 'node:readline';
2
1
  import { callMcpTool, createMcpTools } from './mcp.js';
3
- import { Toolbox } from './toolbox.js';
4
2
  function descriptor(tool) {
5
3
  const { handler, ...definition } = tool;
6
4
  return definition;
7
5
  }
8
- function createMcpServer(options = {}) {
9
- const toolbox = options.toolbox || new Toolbox(options);
6
+ /** MCP JSON-RPC over the one Toolbox (or prepared view) the host already holds. */
7
+ function createMcpServer(options) {
8
+ const { toolbox } = options;
10
9
  const mcpOptions = options.mcp || {};
11
10
  /** Context is supplied by the trusted transport host, never parsed from MCP input. */
12
11
  async function handle(request, context) {
@@ -37,27 +36,6 @@ function createMcpServer(options = {}) {
37
36
  return undefined;
38
37
  throw Object.assign(new Error(`Method not found: ${request.method}`), { code: -32601 });
39
38
  }
40
- function start(input = process.stdin, output = process.stdout) {
41
- const lines = readline.createInterface({ input, crlfDelay: Infinity });
42
- lines.on('line', async (line) => {
43
- let request;
44
- try {
45
- request = JSON.parse(line);
46
- const result = await handle(request);
47
- if (request.id !== undefined && result !== undefined)
48
- output.write(`${JSON.stringify({ jsonrpc: '2.0', id: request.id, result })}\n`);
49
- }
50
- catch (error) {
51
- if (request?.id === undefined)
52
- return;
53
- output.write(`${JSON.stringify({
54
- jsonrpc: '2.0', id: request.id,
55
- error: { code: error?.code || -32603, message: error instanceof Error ? error.message : String(error) },
56
- })}\n`);
57
- }
58
- });
59
- return lines;
60
- }
61
- return { toolbox, handle, start };
39
+ return { toolbox, handle };
62
40
  }
63
41
  export { createMcpServer };
package/dist/results.d.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import type { ToolResult } from './types.js';
2
2
  declare function textResult(value: unknown): ToolResult;
3
3
  declare function structuredResult(value: unknown): ToolResult;
4
- /** The inverse of `structuredResult`'s envelope: a value that is not a plain
5
- * object is carried as `{ result: value }`, and this returns it unchanged. */
6
- declare function structuredValue(structuredContent: ToolResult['structuredContent']): unknown;
7
4
  declare function errorResult(value: unknown): ToolResult;
8
5
  declare function boundedResult(result: ToolResult, maximum: number): ToolResult;
9
- export { boundedResult, errorResult, structuredResult, structuredValue, textResult };
6
+ export { boundedResult, errorResult, structuredResult, textResult };
package/dist/results.js CHANGED
@@ -7,14 +7,6 @@ function structuredResult(value) {
7
7
  ? value : { result: value ?? null };
8
8
  return { ...textResult(value), structuredContent };
9
9
  }
10
- /** The inverse of `structuredResult`'s envelope: a value that is not a plain
11
- * object is carried as `{ result: value }`, and this returns it unchanged. */
12
- function structuredValue(structuredContent) {
13
- return structuredContent
14
- && Object.keys(structuredContent).length === 1
15
- && 'result' in structuredContent
16
- ? structuredContent.result : structuredContent;
17
- }
18
10
  function errorResult(value) {
19
11
  return { ...textResult(value instanceof Error ? value.message : value), isError: true };
20
12
  }
@@ -29,4 +21,4 @@ function boundedResult(result, maximum) {
29
21
  ...(result.isError ? { isError: true } : {}), truncated: true,
30
22
  };
31
23
  }
32
- export { boundedResult, errorResult, structuredResult, structuredValue, textResult };
24
+ export { boundedResult, errorResult, structuredResult, textResult };
package/dist/store.d.ts CHANGED
@@ -6,7 +6,6 @@ declare class Store {
6
6
  revision(): number;
7
7
  private bump;
8
8
  getTool(id: string): ToolRecord | null;
9
- getAction(id: string): ActionRecord | null;
10
9
  actionsFor(toolId: string): ActionRecord[];
11
10
  heads(): Record<string, string>;
12
11
  catalog(): Catalog;
@@ -15,8 +14,6 @@ declare class Store {
15
14
  deploymentsFor(toolId: string): ToolDeployment[];
16
15
  allDeployments(): ToolDeployment[];
17
16
  deploymentSnapshot(): ToolDeploymentSnapshot;
18
- /** Add a baseline for a pre-deployment database without changing its catalog bytes. */
19
- adoptDeployment(activation: ToolDeploymentActivation): void;
20
17
  applyDeployment(activation: ToolDeploymentActivation): {
21
18
  changed: boolean;
22
19
  result: ApplyResult | null;
package/dist/store.js CHANGED
@@ -26,9 +26,6 @@ class Store {
26
26
  getTool(id) {
27
27
  return parse(this.db.prepare('SELECT record_json FROM tools WHERE id = ?').get(id));
28
28
  }
29
- getAction(id) {
30
- return parse(this.db.prepare('SELECT record_json FROM actions WHERE id = ?').get(id));
31
- }
32
29
  actionsFor(toolId) {
33
30
  return this.db.prepare('SELECT record_json FROM actions WHERE tool_id = ? ORDER BY id')
34
31
  .all(toolId).map((row) => parse(row)).filter(Boolean);
@@ -77,16 +74,6 @@ class Store {
77
74
  heads: this.heads(),
78
75
  };
79
76
  }
80
- /** Add a baseline for a pre-deployment database without changing its catalog bytes. */
81
- adoptDeployment(activation) {
82
- const deployment = activation.deployment;
83
- this.db.transaction(() => {
84
- if (this.getDeployment(deployment.id))
85
- return;
86
- this.insertDeployment(deployment);
87
- this.setHead(deployment.subjectId, deployment.id);
88
- })();
89
- }
90
77
  applyDeployment(activation) {
91
78
  const deployment = activation.deployment;
92
79
  return this.db.transaction(() => {
@@ -0,0 +1,40 @@
1
+ import type { ToolboxIndexDocument } from './artifacts.js';
2
+ import type { ActionRecord, Catalog, ToolDeployment, ToolRecord } from './types.js';
3
+ /**
4
+ * The Toolbox's files, written from `tools.db` (the catalog of record) and
5
+ * never read back as catalog:
6
+ *
7
+ * <root>/<Tool Name>/.amalgm-tool.json the tool and every action it owns
8
+ * <root>/<Tool Name>/history/<id>.json each of its deployments, immutable
9
+ * <root>/<Tool Name>/.private/ computer-only; parked when it is deleted
10
+ * <dir>/index.json the whole catalog, system tools included
11
+ *
12
+ * A tool's folder is found by the id in its identity file and follows the
13
+ * tool's name. Writes go through a temporary file and are skipped when the
14
+ * bytes are unchanged.
15
+ */
16
+ declare class ToolFiles {
17
+ private readonly folders;
18
+ constructor(folders: {
19
+ root: string;
20
+ dir: string;
21
+ parked: string;
22
+ });
23
+ writeTool(entry: {
24
+ tool: ToolRecord;
25
+ actions: ActionRecord[];
26
+ }, history: readonly ToolDeployment[]): void;
27
+ /** Park the tool's `.private/`, then remove the files Tools wrote. The
28
+ * folder goes too unless the user keeps files of their own in it. */
29
+ removeTool(toolId: string): void;
30
+ writeIndex(catalog: Catalog): void;
31
+ readIndex(): ToolboxIndexDocument | null;
32
+ private indexFile;
33
+ /** The tool's folder, created or renamed to follow its name. */
34
+ private place;
35
+ private entries;
36
+ private folderOf;
37
+ /** Tool ids can be used again, so a second parking of one id gets "-2", "-3", …. */
38
+ private parkTarget;
39
+ }
40
+ export { ToolFiles };