@telepath-computer/autofile 0.0.0-stage → 0.4.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Telepath Computer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,89 @@
1
- # Temporary Holding Version
1
+ # Autofile
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Autofile makes it easy for agents to store information in a structured, unambiguous way, and makes that information available to the services and interfaces that want to use it and show it.
4
+
5
+ Autofile is designed for:
6
+
7
+ - **No ambiguity on input.** Every kind of information has one defined place and type, with clear instructions for how it is filed.
8
+ - **Efficient retrieval.** Agents find what they need by keyword search, by matching on typed properties, and by following links between records.
9
+ - **Shared access.** Agents and programs use the same records, types and attachments through MCP or the library.
10
+
11
+ Autofile is an [MCP](https://modelcontextprotocol.io) server and a library. Agents use its tools and resources; programs can embed the same store through the `Autofile` class.
12
+
13
+ ## Install
14
+
15
+ Autofile needs Node.js 24 or later.
16
+
17
+ ```sh
18
+ npm install -g @telepath-computer/autofile
19
+ ```
20
+
21
+ This installs the `autofile` command.
22
+
23
+ ## Connect an agent
24
+
25
+ An MCP client starts Autofile itself by running `autofile`, and talks to it over stdio. For Claude Code:
26
+
27
+ ```sh
28
+ claude mcp add autofile --scope user -- autofile
29
+ ```
30
+
31
+ For another client, add an MCP server whose command is `autofile`, with no arguments.
32
+
33
+ Autofile starts with no types. Ask your agent to file something: it proposes a type, such as `contact` with the fields a contact needs, and creates it once you agree. It then files records of that type, and finds them again by search, by field value, or by following links between records.
34
+
35
+ ## Choose a store
36
+
37
+ Autofile uses a default store until the `storage` setting selects another. Changing that setting moves no records and takes effect when clients restart Autofile. See [storage configuration](spec/storage.md#folders) for the current implementation and [Commands](spec/index.md#commands) for other settings.
38
+
39
+ ## Serve over HTTP
40
+
41
+ For clients that connect over HTTP, such as a web page, run:
42
+
43
+ ```sh
44
+ autofile serve
45
+ ```
46
+
47
+ This serves the same tools and resources at `http://127.0.0.1:7319/mcp` until stopped. Autofile does not authenticate HTTP clients: anything that can reach the address can read and change every record. It therefore listens only on this machine by default, and accepts requests from web pages only when they are served from this machine. [Serving over HTTP](spec/index.md#serving-over-http) explains how to change the address, the port, and the web pages it accepts.
48
+
49
+ ## Use as a library
50
+
51
+ Install the package in your project with `npm install @telepath-computer/autofile`, then import the ES module:
52
+
53
+ ```js
54
+ import { Autofile } from "@telepath-computer/autofile";
55
+
56
+ const store = new Autofile({ folder: "./records" });
57
+ try {
58
+ const { records } = await store.records.find({ q: "dentist" });
59
+ for (const record of records) console.log(record.title ?? record.uri);
60
+ } finally {
61
+ await store.close();
62
+ }
63
+ ```
64
+
65
+ The `folder` option is the path of a store in the current implementation; [Storage](spec/storage.md) describes its format. Importing starts no server or watcher, and construction does no I/O. The first operation initializes the store if needed. [Library API](spec/index.md#library-api) covers writing records, declaring types, blobs, change subscriptions and errors.
66
+
67
+ Record addresses use `autofile:///<type>/<key>`, type declarations use `autofile:///_types/<name>`, and attachments use `autofile:///_blobs/<hash>.<ext>`. Keep and reuse these addresses as opaque identifiers; they do not tell a client how data is stored.
68
+
69
+ Upload an attachment before writing the record that holds it. `blobs.put(bytes, mediaType)` takes a `Uint8Array` and returns an address; put that address in a field marked `"format": "blob"` in the type schema. For an open store with a `document` type that declares `title` and `attachment` fields:
70
+
71
+ ```js
72
+ const uri = await store.blobs.put(new TextEncoder().encode("Meeting notes"), "text/plain");
73
+ await store.records.create("document", { title: "Meeting notes", attachment: uri });
74
+ ```
75
+
76
+ Records may share an attachment address. MCP clients use `upload_blob` with base64 bytes and a media type, or an absolute local file path over stdio, then put the returned address in the record. Record writes accept neither data URIs nor local paths in blob fields.
77
+
78
+ ## Specification
79
+
80
+ [spec/index.md](spec/index.md) describes records, types, links, attachments, the MCP tools and resources, and the commands. [Storage](spec/storage.md) specifies the on-disk format, and [Implementation](spec/implementation.md) describes the code.
81
+
82
+ ## Development
83
+
84
+ ```sh
85
+ npm install
86
+ npm test
87
+ ```
88
+
89
+ `npm test` builds Autofile and runs the tests.
@@ -0,0 +1,21 @@
1
+ /** Stores explicitly uploaded attachments and checks their canonical addresses. */
2
+ /** Largest blob that fits in one MCP message after base64 encoding. */
3
+ export declare const MAX_BLOB_BYTES = 7340032;
4
+ /** Canonical names Autofile recognizes in its blob folder. */
5
+ export declare const BLOB_NAME_PATTERN: RegExp;
6
+ /** Canonical URIs Autofile recognizes for stored blobs. */
7
+ export declare const BLOB_URI_PATTERN: RegExp;
8
+ /** Stores one attachment atomically, reusing an existing regular file. */
9
+ export declare function writeBlob(blobFolder: string, bytes: Buffer, mediaType: string): Promise<string>;
10
+ /** Reports unavailable or oversized bytes for a canonical attachment address. */
11
+ export declare function blobReferenceProblem(blobFolder: string, uri: string): Promise<string | undefined>;
12
+ /** Checks the bare media type accepted by explicit uploads. */
13
+ export declare function isMediaType(value: unknown): value is string;
14
+ /** Gives the upload size and the accepted limit in the existing refusal form. */
15
+ export declare function blobSizeProblem(size: number): string;
16
+ /** Deletes the named canonical blob resources when they still exist. */
17
+ export declare function deleteBlobUris(blobFolder: string, uris: Iterable<string>): Promise<void>;
18
+ /** Returns the canonical blob name from a URI. */
19
+ export declare function blobNameFromUri(uri: string): string | undefined;
20
+ /** Builds the canonical URI for a recognized blob name. */
21
+ export declare function blobUri(name: string): string;
package/dist/blobs.js ADDED
@@ -0,0 +1,159 @@
1
+ /** Stores explicitly uploaded attachments and checks their canonical addresses. */
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { constants } from "node:fs";
4
+ import { lstat, mkdir, open, rename, unlink, writeFile } from "node:fs/promises";
5
+ import { basename, dirname, join } from "node:path";
6
+ import { extension as extensionForMimeType } from "mime-types";
7
+ const BLOB_EXTENSION_PATTERN_SOURCE = "[a-z0-9_-]+";
8
+ /** Largest blob that fits in one MCP message after base64 encoding. */
9
+ export const MAX_BLOB_BYTES = 7_340_032;
10
+ /** Canonical names Autofile recognizes in its blob folder. */
11
+ export const BLOB_NAME_PATTERN = new RegExp(`^[a-f0-9]{64}(?:\\.${BLOB_EXTENSION_PATTERN_SOURCE})?$`, "u");
12
+ /** Canonical URIs Autofile recognizes for stored blobs. */
13
+ export const BLOB_URI_PATTERN = new RegExp(`^autofile:///_blobs/([a-f0-9]{64}(?:\\.${BLOB_EXTENSION_PATTERN_SOURCE})?)$`, "u");
14
+ const blobExtensionPattern = new RegExp(`^${BLOB_EXTENSION_PATTERN_SOURCE}$`, "u");
15
+ /** Stores one attachment atomically, reusing an existing regular file. */
16
+ export async function writeBlob(blobFolder, bytes, mediaType) {
17
+ const extension = extensionForMimeType(mediaType.toLowerCase());
18
+ const suffix = extension === false ? undefined : normalizeExtension(extension);
19
+ const digest = createHash("sha256").update(bytes).digest("hex");
20
+ const name = `${digest}${suffix === undefined ? "" : `.${suffix}`}`;
21
+ await mkdir(blobFolder, { recursive: true });
22
+ if (!await isDirectory(blobFolder)) {
23
+ throw Object.assign(new Error("blob folder is not a directory"), { code: "ENOTDIR" });
24
+ }
25
+ const path = join(blobFolder, name);
26
+ if (!await isRegularFile(path))
27
+ await writeBlobAtomically(path, bytes);
28
+ return blobUri(name);
29
+ }
30
+ /** Reports unavailable or oversized bytes for a canonical attachment address. */
31
+ export async function blobReferenceProblem(blobFolder, uri) {
32
+ const name = blobNameFromUri(uri);
33
+ const details = name === undefined ? undefined : await storedBlobDetails(blobFolder, name);
34
+ if (details === undefined)
35
+ return `references a blob that does not exist: ${uri}`;
36
+ return details.size > MAX_BLOB_BYTES ? blobSizeProblem(details.size) : undefined;
37
+ }
38
+ /** Checks the bare media type accepted by explicit uploads. */
39
+ export function isMediaType(value) {
40
+ if (typeof value !== "string")
41
+ return false;
42
+ const token = "[!#$%&'*+.^_`|~0-9A-Za-z-]+";
43
+ return new RegExp(`^${token}/${token}$`, "u").test(value);
44
+ }
45
+ /** Gives the upload size and the accepted limit in the existing refusal form. */
46
+ export function blobSizeProblem(size) {
47
+ return `blob is ${String(size)} bytes; limit is ${String(MAX_BLOB_BYTES)} bytes`;
48
+ }
49
+ /** Deletes the named canonical blob resources when they still exist. */
50
+ export async function deleteBlobUris(blobFolder, uris) {
51
+ if (!await isDirectory(blobFolder))
52
+ return;
53
+ for (const uri of uris) {
54
+ const name = blobNameFromUri(uri);
55
+ if (name === undefined)
56
+ continue;
57
+ try {
58
+ await unlink(join(blobFolder, name));
59
+ }
60
+ catch (error) {
61
+ if (!hasCode(error, "ENOENT") && !hasCode(error, "ENOTDIR"))
62
+ throw error;
63
+ }
64
+ }
65
+ }
66
+ /** Returns the canonical blob name from a URI. */
67
+ export function blobNameFromUri(uri) {
68
+ return typeof uri === "string" ? BLOB_URI_PATTERN.exec(uri)?.[1] : undefined;
69
+ }
70
+ /** Builds the canonical URI for a recognized blob name. */
71
+ export function blobUri(name) {
72
+ return `autofile:///_blobs/${name}`;
73
+ }
74
+ function normalizeExtension(extension) {
75
+ const normalized = extension.toLowerCase();
76
+ return blobExtensionPattern.test(normalized) ? normalized : undefined;
77
+ }
78
+ async function storedBlobDetails(blobFolder, name) {
79
+ if (!await isDirectory(blobFolder))
80
+ return undefined;
81
+ const file = await openRegularFile(join(blobFolder, name));
82
+ if (file === undefined)
83
+ return undefined;
84
+ try {
85
+ return { size: file.size };
86
+ }
87
+ finally {
88
+ await file.handle.close();
89
+ }
90
+ }
91
+ async function openRegularFile(path) {
92
+ let handle;
93
+ try {
94
+ handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);
95
+ }
96
+ catch (error) {
97
+ if (hasCode(error, "ENOENT")
98
+ || hasCode(error, "ENOTDIR")
99
+ || hasCode(error, "ELOOP")
100
+ || hasCode(error, "ENXIO")
101
+ || hasCode(error, "ENODEV")) {
102
+ return undefined;
103
+ }
104
+ throw error;
105
+ }
106
+ try {
107
+ const details = await handle.stat();
108
+ if (!details.isFile()) {
109
+ await handle.close();
110
+ return undefined;
111
+ }
112
+ return { handle, size: details.size };
113
+ }
114
+ catch (error) {
115
+ await handle.close();
116
+ throw error;
117
+ }
118
+ }
119
+ async function writeBlobAtomically(path, bytes) {
120
+ const temporaryPath = join(dirname(path), `.${basename(path)}.${String(process.pid)}.${randomUUID()}`);
121
+ try {
122
+ await writeFile(temporaryPath, bytes, { flag: "wx" });
123
+ await rename(temporaryPath, path);
124
+ }
125
+ catch (error) {
126
+ try {
127
+ await unlink(temporaryPath);
128
+ }
129
+ catch (cleanupError) {
130
+ if (!hasCode(cleanupError, "ENOENT"))
131
+ throw cleanupError;
132
+ }
133
+ throw error;
134
+ }
135
+ }
136
+ async function isDirectory(path) {
137
+ try {
138
+ return (await lstat(path)).isDirectory();
139
+ }
140
+ catch (error) {
141
+ if (hasCode(error, "ENOENT") || hasCode(error, "ENOTDIR"))
142
+ return false;
143
+ throw error;
144
+ }
145
+ }
146
+ async function isRegularFile(path) {
147
+ try {
148
+ return (await lstat(path)).isFile();
149
+ }
150
+ catch (error) {
151
+ if (hasCode(error, "ENOENT") || hasCode(error, "ENOTDIR"))
152
+ return false;
153
+ throw error;
154
+ }
155
+ }
156
+ function hasCode(error, code) {
157
+ return error instanceof Error && "code" in error && error.code === code;
158
+ }
159
+ //# sourceMappingURL=blobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blobs.js","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ /** Serves Autofile over stdio or HTTP and dispatches its settings commands. */
3
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env node
2
+ /** Serves Autofile over stdio or HTTP and dispatches its settings commands. */
3
+ import { StdioServerTransport, serveStdio } from "@modelcontextprotocol/server/stdio";
4
+ import { getSetting, getSettings, isSettingName, parsePort, setSetting, unsetSetting, } from "./config.js";
5
+ import { startHttpServer } from "./http.js";
6
+ import { buildServer } from "./server.js";
7
+ import { Autofile } from "./index.js";
8
+ import { watchResources, } from "./mcp-watch.js";
9
+ const usage = `Usage:
10
+ autofile
11
+ autofile serve [--host <host>] [--port <port>]
12
+ autofile set <setting> <value> [<value>...]
13
+ autofile get <setting>
14
+ autofile unset <setting>
15
+ `;
16
+ class UsageError extends Error {
17
+ }
18
+ try {
19
+ await main(process.argv.slice(2));
20
+ }
21
+ catch (error) {
22
+ if (error instanceof UsageError) {
23
+ process.stderr.write(usage);
24
+ }
25
+ else {
26
+ reportError(error);
27
+ }
28
+ process.exitCode = 1;
29
+ }
30
+ async function main(args) {
31
+ if (args.length === 0) {
32
+ await runStdio();
33
+ return;
34
+ }
35
+ const [command, setting, ...values] = args;
36
+ if (command === "serve") {
37
+ await serve(args.slice(1));
38
+ return;
39
+ }
40
+ if (command === "set") {
41
+ if (setting === undefined || !isSettingName(setting) || !hasValidSetArity(setting, values)) {
42
+ throw new UsageError();
43
+ }
44
+ await setSetting(setting, values);
45
+ return;
46
+ }
47
+ if (command === "get") {
48
+ if (setting === undefined || values.length !== 0 || !isSettingName(setting)) {
49
+ throw new UsageError();
50
+ }
51
+ const lines = await getSetting(setting);
52
+ if (lines.length > 0)
53
+ process.stdout.write(`${lines.join("\n")}\n`);
54
+ return;
55
+ }
56
+ if (command === "unset") {
57
+ if (setting === undefined || values.length !== 0 || !isSettingName(setting)) {
58
+ throw new UsageError();
59
+ }
60
+ await unsetSetting(setting);
61
+ return;
62
+ }
63
+ throw new UsageError();
64
+ }
65
+ async function runStdio() {
66
+ const settings = await getSettings();
67
+ const store = new Autofile({ folder: settings.storage });
68
+ let connectedServer;
69
+ let watcher;
70
+ let handle;
71
+ let stopping;
72
+ const stop = () => {
73
+ stopping ??= Promise.all([
74
+ (async () => {
75
+ await watcher?.close();
76
+ await store.close();
77
+ })(),
78
+ handle?.close() ?? Promise.resolve(),
79
+ ]).then(() => undefined);
80
+ return stopping;
81
+ };
82
+ watcher = await watchResources(store, async (batch) => {
83
+ const server = connectedServer;
84
+ if (server === undefined || !server.isConnected())
85
+ return;
86
+ try {
87
+ const uris = new Set(batch.changes.map(({ uri }) => uri));
88
+ for (const uri of uris) {
89
+ await server.server.sendResourceUpdated({ uri });
90
+ }
91
+ if (batch.listChanged)
92
+ await server.server.sendResourceListChanged();
93
+ }
94
+ catch (error) {
95
+ // Closing the connection can race an event already queued by Chokidar.
96
+ if (server.isConnected())
97
+ throw error;
98
+ }
99
+ }, reportError).catch(async (error) => {
100
+ await store.close();
101
+ throw error;
102
+ });
103
+ handle = serveStdio(async () => {
104
+ const server = await buildServer(store);
105
+ connectedServer = server;
106
+ return server;
107
+ }, {
108
+ legacy: "reject",
109
+ transport: new StdioServerTransport(process.stdin, process.stdout, {
110
+ maxBufferSize: 64 * 1024 * 1024,
111
+ }),
112
+ onerror: reportError,
113
+ });
114
+ const requestStop = () => {
115
+ void stop().catch((error) => {
116
+ reportError(error);
117
+ process.exitCode = 1;
118
+ });
119
+ };
120
+ process.stdin.once("end", requestStop);
121
+ process.stdin.once("close", requestStop);
122
+ process.once("SIGINT", requestStop);
123
+ process.once("SIGTERM", requestStop);
124
+ }
125
+ async function serve(args) {
126
+ const overrides = parseServeOptions(args);
127
+ const settings = await getSettings();
128
+ const http = {
129
+ ...settings.http,
130
+ ...(overrides.host === undefined ? {} : { host: overrides.host }),
131
+ ...(overrides.port === undefined ? {} : { port: overrides.port }),
132
+ };
133
+ const store = new Autofile({ folder: settings.storage });
134
+ const running = await startHttpServer(store, http, reportError);
135
+ process.stderr.write(`autofile: listening on ${running.endpoint.href}\n`);
136
+ const stop = () => {
137
+ void running.close().catch((error) => {
138
+ reportError(error);
139
+ process.exitCode = 1;
140
+ });
141
+ };
142
+ process.once("SIGINT", stop);
143
+ process.once("SIGTERM", stop);
144
+ try {
145
+ await running.closed;
146
+ }
147
+ finally {
148
+ process.off("SIGINT", stop);
149
+ process.off("SIGTERM", stop);
150
+ }
151
+ }
152
+ function parseServeOptions(args) {
153
+ let host;
154
+ let port;
155
+ for (let index = 0; index < args.length; index += 2) {
156
+ const option = args[index];
157
+ const value = args[index + 1];
158
+ if (value === undefined)
159
+ throw new UsageError();
160
+ if (option === "--host" && host === undefined) {
161
+ if (value === "")
162
+ throw new Error("http.host must be a non-empty string");
163
+ host = value;
164
+ }
165
+ else if (option === "--port" && port === undefined) {
166
+ port = parsePort(value);
167
+ }
168
+ else {
169
+ throw new UsageError();
170
+ }
171
+ }
172
+ return {
173
+ ...(host === undefined ? {} : { host }),
174
+ ...(port === undefined ? {} : { port }),
175
+ };
176
+ }
177
+ function hasValidSetArity(setting, values) {
178
+ if (setting === "http.origins")
179
+ return values.length > 0;
180
+ return values.length === 1;
181
+ }
182
+ function reportError(error) {
183
+ const message = error instanceof Error ? error.message : String(error);
184
+ process.stderr.write(`autofile: ${message.replace(/[\r\n]+/gu, " ")}\n`);
185
+ }
186
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /** Reads, validates, and writes Autofile's process-wide settings. */
2
+ declare const settingNames: readonly ["storage", "http.host", "http.port", "http.origins"];
3
+ export type SettingName = typeof settingNames[number];
4
+ export interface HttpSettings {
5
+ host: string;
6
+ port: number;
7
+ origins: string[];
8
+ }
9
+ export interface Settings {
10
+ storage: string;
11
+ http: HttpSettings;
12
+ }
13
+ /** Returns whether a command argument names one of Autofile's settings. */
14
+ export declare function isSettingName(value: string): value is SettingName;
15
+ /** Returns the path shared stores use to serialize writes between processes. */
16
+ export declare function getWriteLockPath(): string;
17
+ /** Returns every effective setting, applying defaults to settings that are absent. */
18
+ export declare function getSettings(): Promise<Settings>;
19
+ /** Returns the configured data folder, or the default folder when unset. */
20
+ export declare function getStorage(): Promise<string>;
21
+ /** Returns a setting as the lines its CLI `get` command prints. */
22
+ export declare function getSetting(name: SettingName): Promise<string[]>;
23
+ /** Validates and stores one setting while preserving every other setting. */
24
+ export declare function setSetting(name: SettingName, values: string[]): Promise<void>;
25
+ /** Removes one setting so its default applies, preserving its siblings. */
26
+ export declare function unsetSetting(name: SettingName): Promise<void>;
27
+ /** Parses a CLI port value and rejects anything outside the TCP port range. */
28
+ export declare function parsePort(value: string): number;
29
+ /** Returns the URL-normalized form of a strict HTTP origin, or undefined when invalid. */
30
+ export declare function normalizeHttpOrigin(value: string): string | undefined;
31
+ export {};