@telepath-computer/autofile 0.3.0 → 0.5.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/README.md +69 -36
- package/dist/blobs.d.ts +9 -24
- package/dist/blobs.js +60 -229
- package/dist/blobs.js.map +1 -1
- package/dist/cli.js +16 -10
- package/dist/cli.js.map +1 -1
- package/dist/http.d.ts +3 -3
- package/dist/http.js +141 -10
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +3 -1
- package/dist/json.js +81 -2
- package/dist/json.js.map +1 -1
- package/dist/mcp-resources.d.ts +35 -0
- package/dist/mcp-resources.js +127 -0
- package/dist/mcp-resources.js.map +1 -0
- package/dist/mcp-tools.d.ts +113 -0
- package/dist/mcp-tools.js +89 -0
- package/dist/mcp-tools.js.map +1 -0
- package/dist/mcp-upload.d.ts +16 -0
- package/dist/mcp-upload.js +81 -0
- package/dist/mcp-upload.js.map +1 -0
- package/dist/mcp-watch.d.ts +18 -0
- package/dist/mcp-watch.js +165 -0
- package/dist/mcp-watch.js.map +1 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +8 -2
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +3 -2
- package/dist/server.js +58 -38
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +102 -108
- package/dist/store.js +622 -530
- package/dist/store.js.map +1 -1
- package/dist/watch.d.ts +6 -18
- package/dist/watch.js +92 -213
- package/dist/watch.js.map +1 -1
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -1,69 +1,98 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/icon.svg" width="72" height="72" alt="Autofile icon">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
Autofile
|
|
5
|
+
<h1 align="center">Autofile</h1>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>A portable, open filesystem for agents.</strong>
|
|
9
|
+
</p>
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/@telepath-computer/autofile"><img src="https://img.shields.io/npm/v/@telepath-computer/autofile" alt="npm version"></a>
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/telepath-computer/autofile" alt="MIT licence"></a>
|
|
14
|
+
<img src="https://img.shields.io/badge/node-%E2%89%A524-339933" alt="Node 24 or later">
|
|
15
|
+
</p>
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
<p align="center">
|
|
18
|
+
<img src="assets/autofile-view.png" width="760" alt="A grid of records in Autofile: journal entries, contacts, events, topics and saved references">
|
|
19
|
+
<br>
|
|
20
|
+
<em>GUI coming soon</em>
|
|
21
|
+
</p>
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
**Agents file everything, and it never turns into a mess.** Every kind of information has one place and one shape, and anything that doesn't fit is turned away. A year of filing by any number of agents stays as coherent as the first day, and anything in it can still be found straight away.
|
|
14
24
|
|
|
15
|
-
Autofile
|
|
25
|
+
**The live data layer for the apps you vibe-code.** Point an app at Autofile and it has storage, search, links, file attachments and live updates, with nothing else to build. The screens agents put up on [Television](https://github.com/telepath-computer/television) work this way: they change the moment an agent files something.
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
npm install -g @telepath-computer/autofile
|
|
19
|
-
```
|
|
27
|
+
**Yours, wherever you take it.** Your records are plain files on your own machine, readable without Autofile and easy to move, back up or sync. Autofile is open source, and any agent that speaks [MCP](https://modelcontextprotocol.io) can use it.
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
## Get started
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
You need Node.js 24 or later.
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
1. Install Autofile:
|
|
26
34
|
|
|
27
|
-
```sh
|
|
28
|
-
|
|
29
|
-
```
|
|
35
|
+
```sh
|
|
36
|
+
npm install -g @telepath-computer/autofile
|
|
37
|
+
```
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
2. Add it to your agent. For Claude Code:
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
```sh
|
|
42
|
+
claude mcp add autofile --scope user -- autofile
|
|
43
|
+
```
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
For another MCP client, add a server whose command is `autofile`, with no arguments.
|
|
36
46
|
|
|
37
|
-
|
|
47
|
+
3. Ask your agent to remember something.
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
~/.autofile/data/
|
|
41
|
-
_types/contact.json the declaration of the type contact
|
|
42
|
-
contact/priya-narayan.json a record of that type
|
|
43
|
-
_blobs/9f86d081…0a08.pdf a file stored with a record
|
|
44
|
-
```
|
|
49
|
+
Autofile starts empty. Your agent proposes types as it needs them, and creates each one once you agree.
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
## File over app
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
autofile set storage ~/Documents/Autofile
|
|
50
|
-
```
|
|
53
|
+
Autofile follows [File over app](https://stephango.com/file-over-app), the philosophy of Steph Ango (kepano), CEO of Obsidian: "Apps are ephemeral, but your files have a chance to last."
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
Your records are plain JSON files in one Autofile folder, with attachments kept as the original files. Put the folder anywhere, such as Dropbox to sync it between machines, with `autofile set storage ~/Dropbox/Autofile`. Any program can read it, with or without Autofile, and the files are yours forever.
|
|
53
56
|
|
|
54
57
|
## Serve over HTTP
|
|
55
58
|
|
|
56
|
-
For
|
|
59
|
+
For apps and agents that connect over HTTP, run:
|
|
57
60
|
|
|
58
61
|
```sh
|
|
59
62
|
autofile serve
|
|
60
63
|
```
|
|
61
64
|
|
|
62
|
-
This serves the same tools and resources at `http://127.0.0.1:7319/mcp
|
|
65
|
+
This serves the same tools and resources at `http://127.0.0.1:7319/mcp`, and attachments next to it. Autofile does not authenticate HTTP clients, so anything that can reach the address can read and change every record. It listens only on this machine by default. [Serving over HTTP](spec/index.md#serving-over-http) explains how to change the address and which web pages it accepts.
|
|
66
|
+
|
|
67
|
+
## Use it as a library
|
|
68
|
+
|
|
69
|
+
Programs can use the same store directly:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
npm install @telepath-computer/autofile
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
import { Autofile } from "@telepath-computer/autofile";
|
|
77
|
+
|
|
78
|
+
const store = new Autofile({ folder: "./records" });
|
|
79
|
+
try {
|
|
80
|
+
const { records } = await store.records.find({ q: "Ada Park" });
|
|
81
|
+
for (const record of records) console.log(record.title ?? record.uri);
|
|
82
|
+
} finally {
|
|
83
|
+
await store.close();
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The [Library API](spec/index.md#library-api) covers writing records, declaring types, attachments and watching for changes.
|
|
88
|
+
|
|
89
|
+
## Status
|
|
90
|
+
|
|
91
|
+
Autofile is new and changing quickly. Until version 1.0, addresses, tools and the library API may change between minor versions.
|
|
63
92
|
|
|
64
93
|
## Specification
|
|
65
94
|
|
|
66
|
-
[spec/index.md](spec/index.md) describes
|
|
95
|
+
[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 folder format, and [Implementation](spec/implementation.md) describes the code.
|
|
67
96
|
|
|
68
97
|
## Development
|
|
69
98
|
|
|
@@ -73,3 +102,7 @@ npm test
|
|
|
73
102
|
```
|
|
74
103
|
|
|
75
104
|
`npm test` builds Autofile and runs the tests.
|
|
105
|
+
|
|
106
|
+
## Licence
|
|
107
|
+
|
|
108
|
+
[MIT](LICENSE)
|
package/dist/blobs.d.ts
CHANGED
|
@@ -1,34 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parses, checks, and persists blob-field inputs. Candidate preparation is
|
|
3
|
-
* deliberately separate from persistence so a refused record write cannot
|
|
4
|
-
* leave a blob behind.
|
|
5
|
-
*/
|
|
6
|
-
/** Largest blob that fits in one MCP message after base64 encoding. */
|
|
7
|
-
export declare const MAX_BLOB_BYTES = 7340032;
|
|
1
|
+
/** Stores explicitly uploaded attachments and checks their canonical addresses. */
|
|
8
2
|
/** Canonical names Autofile recognizes in its blob folder. */
|
|
9
3
|
export declare const BLOB_NAME_PATTERN: RegExp;
|
|
10
4
|
/** Canonical URIs Autofile recognizes for stored blobs. */
|
|
11
5
|
export declare const BLOB_URI_PATTERN: RegExp;
|
|
12
|
-
/**
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
message: string;
|
|
21
|
-
}
|
|
22
|
-
/** Returns whether the value has one of the three syntactic blob input forms. */
|
|
23
|
-
export declare function isBlobInput(value: unknown): value is string;
|
|
24
|
-
/** Checks and materializes one candidate without changing the blob folder. */
|
|
25
|
-
export declare function prepareBlob(value: string, blobFolder: string, allowLocalPaths: boolean): Promise<PreparedBlob | BlobRefusal>;
|
|
26
|
-
/** Stores checked blobs atomically, skipping any destination already present. */
|
|
27
|
-
export declare function writePreparedBlobs(blobFolder: string, blobs: Iterable<PreparedBlob>): Promise<void>;
|
|
6
|
+
/** Stores uploaded bytes through the same incremental writer as streamed sources. */
|
|
7
|
+
export declare function writeBlob(blobFolder: string, bytes: Buffer, mediaType: string): Promise<string>;
|
|
8
|
+
/** Hashes and stores chunks in order, publishing only a complete attachment. */
|
|
9
|
+
export declare function writeBlobStream(blobFolder: string, chunks: AsyncIterable<Uint8Array>, mediaType: string): Promise<string>;
|
|
10
|
+
/** Checks attachment existence without opening or reading its bytes. */
|
|
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;
|
|
28
14
|
/** Deletes the named canonical blob resources when they still exist. */
|
|
29
15
|
export declare function deleteBlobUris(blobFolder: string, uris: Iterable<string>): Promise<void>;
|
|
30
16
|
/** Returns the canonical blob name from a URI. */
|
|
31
17
|
export declare function blobNameFromUri(uri: string): string | undefined;
|
|
32
18
|
/** Builds the canonical URI for a recognized blob name. */
|
|
33
19
|
export declare function blobUri(name: string): string;
|
|
34
|
-
export {};
|
package/dist/blobs.js
CHANGED
|
@@ -1,83 +1,75 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parses, checks, and persists blob-field inputs. Candidate preparation is
|
|
3
|
-
* deliberately separate from persistence so a refused record write cannot
|
|
4
|
-
* leave a blob behind.
|
|
5
|
-
*/
|
|
1
|
+
/** Stores explicitly uploaded attachments and checks their canonical addresses. */
|
|
6
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { basename, dirname, extname, isAbsolute, join } from "node:path";
|
|
3
|
+
import { chmod, lstat, mkdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
10
5
|
import { extension as extensionForMimeType } from "mime-types";
|
|
11
6
|
const BLOB_EXTENSION_PATTERN_SOURCE = "[a-z0-9_-]+";
|
|
12
|
-
/** Largest blob that fits in one MCP message after base64 encoding. */
|
|
13
|
-
export const MAX_BLOB_BYTES = 7_340_032;
|
|
14
7
|
/** Canonical names Autofile recognizes in its blob folder. */
|
|
15
8
|
export const BLOB_NAME_PATTERN = new RegExp(`^[a-f0-9]{64}(?:\\.${BLOB_EXTENSION_PATTERN_SOURCE})?$`, "u");
|
|
16
9
|
/** Canonical URIs Autofile recognizes for stored blobs. */
|
|
17
|
-
export const BLOB_URI_PATTERN = new RegExp(`^autofile:///
|
|
18
|
-
const SOURCE_READ_CHUNK_BYTES = 64 * 1024;
|
|
10
|
+
export const BLOB_URI_PATTERN = new RegExp(`^autofile:///blobs/([a-f0-9]{64}(?:\\.${BLOB_EXTENSION_PATTERN_SOURCE})?)$`, "u");
|
|
19
11
|
const blobExtensionPattern = new RegExp(`^${BLOB_EXTENSION_PATTERN_SOURCE}$`, "u");
|
|
20
|
-
/**
|
|
21
|
-
export function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
export async function
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
12
|
+
/** Stores uploaded bytes through the same incremental writer as streamed sources. */
|
|
13
|
+
export async function writeBlob(blobFolder, bytes, mediaType) {
|
|
14
|
+
async function* chunks() { yield bytes; }
|
|
15
|
+
return writeBlobStream(blobFolder, chunks(), mediaType);
|
|
16
|
+
}
|
|
17
|
+
/** Hashes and stores chunks in order, publishing only a complete attachment. */
|
|
18
|
+
export async function writeBlobStream(blobFolder, chunks, mediaType) {
|
|
19
|
+
const extension = extensionForMimeType(mediaType.toLowerCase());
|
|
20
|
+
const suffix = extension === false ? undefined : normalizeExtension(extension);
|
|
21
|
+
const digest = createHash("sha256");
|
|
22
|
+
await mkdir(blobFolder, { recursive: true });
|
|
23
|
+
if (!await isDirectory(blobFolder)) {
|
|
24
|
+
throw Object.assign(new Error("blob folder is not a directory"), { code: "ENOTDIR" });
|
|
25
|
+
}
|
|
26
|
+
const temporaryPath = join(blobFolder, `.upload.${String(process.pid)}.${randomUUID()}`);
|
|
27
|
+
async function* hashedChunks() {
|
|
28
|
+
for await (const chunk of chunks) {
|
|
29
|
+
digest.update(chunk);
|
|
30
|
+
yield chunk;
|
|
31
|
+
}
|
|
35
32
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
try {
|
|
34
|
+
// writeFile awaits each chunk write before advancing the iterable, so the
|
|
35
|
+
// source is backpressured and attachments never accumulate in memory.
|
|
36
|
+
await writeFile(temporaryPath, hashedChunks(), { flag: "wx" });
|
|
37
|
+
const name = `${digest.digest("hex")}${suffix === undefined ? "" : `.${suffix}`}`;
|
|
38
|
+
const path = join(blobFolder, name);
|
|
39
|
+
if (await isRegularFile(path)) {
|
|
40
|
+
await unlink(temporaryPath);
|
|
39
41
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
else {
|
|
43
|
+
// Set the exact read-only mode before publishing the immutable attachment.
|
|
44
|
+
await chmod(temporaryPath, 0o444);
|
|
45
|
+
await rename(temporaryPath, path);
|
|
46
|
+
}
|
|
47
|
+
return blobUri(name);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
43
50
|
try {
|
|
44
|
-
|
|
45
|
-
return sizeRefusal(source.size);
|
|
46
|
-
const bytes = await readSourceFile(source.handle);
|
|
47
|
-
if ("message" in bytes)
|
|
48
|
-
return bytes;
|
|
49
|
-
return preparedBytes(bytes, pathExtension(value));
|
|
51
|
+
await unlink(temporaryPath);
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
catch (cleanupError) {
|
|
54
|
+
if (!hasCode(cleanupError, "ENOENT"))
|
|
55
|
+
throw cleanupError;
|
|
53
56
|
}
|
|
57
|
+
throw error;
|
|
54
58
|
}
|
|
55
|
-
const data = parseDataUri(value);
|
|
56
|
-
if (data === undefined)
|
|
57
|
-
return { message: "must be a blob URI, an absolute path, or a base64 data URI" };
|
|
58
|
-
if (data.size > MAX_BLOB_BYTES)
|
|
59
|
-
return sizeRefusal(data.size);
|
|
60
|
-
return preparedBytes(Buffer.from(data.base64, "base64"), data.extension);
|
|
61
59
|
}
|
|
62
|
-
/**
|
|
63
|
-
export async function
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
written.add(blob.name);
|
|
76
|
-
const path = join(blobFolder, blob.name);
|
|
77
|
-
if (await isRegularFile(path))
|
|
78
|
-
continue;
|
|
79
|
-
await writeBlobAtomically(path, blob.bytes ?? Buffer.alloc(0));
|
|
80
|
-
}
|
|
60
|
+
/** Checks attachment existence without opening or reading its bytes. */
|
|
61
|
+
export async function blobReferenceProblem(blobFolder, uri) {
|
|
62
|
+
const name = blobNameFromUri(uri);
|
|
63
|
+
return name !== undefined && await isDirectory(blobFolder) && await isRegularFile(join(blobFolder, name))
|
|
64
|
+
? undefined
|
|
65
|
+
: `references a blob that does not exist: ${uri}`;
|
|
66
|
+
}
|
|
67
|
+
/** Checks the bare media type accepted by explicit uploads. */
|
|
68
|
+
export function isMediaType(value) {
|
|
69
|
+
if (typeof value !== "string")
|
|
70
|
+
return false;
|
|
71
|
+
const token = "[!#$%&'*+.^_`|~0-9A-Za-z-]+";
|
|
72
|
+
return new RegExp(`^${token}/${token}$`, "u").test(value);
|
|
81
73
|
}
|
|
82
74
|
/** Deletes the named canonical blob resources when they still exist. */
|
|
83
75
|
export async function deleteBlobUris(blobFolder, uris) {
|
|
@@ -98,177 +90,16 @@ export async function deleteBlobUris(blobFolder, uris) {
|
|
|
98
90
|
}
|
|
99
91
|
/** Returns the canonical blob name from a URI. */
|
|
100
92
|
export function blobNameFromUri(uri) {
|
|
101
|
-
return BLOB_URI_PATTERN.exec(uri)?.[1];
|
|
93
|
+
return typeof uri === "string" ? BLOB_URI_PATTERN.exec(uri)?.[1] : undefined;
|
|
102
94
|
}
|
|
103
95
|
/** Builds the canonical URI for a recognized blob name. */
|
|
104
96
|
export function blobUri(name) {
|
|
105
|
-
return `autofile:///
|
|
106
|
-
}
|
|
107
|
-
function preparedBytes(bytes, extension) {
|
|
108
|
-
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
109
|
-
const name = `${digest}${extension === undefined ? "" : `.${extension}`}`;
|
|
110
|
-
return { uri: blobUri(name), name, bytes };
|
|
111
|
-
}
|
|
112
|
-
function parseDataUri(value) {
|
|
113
|
-
if (value.slice(0, "data:".length).toLowerCase() !== "data:")
|
|
114
|
-
return undefined;
|
|
115
|
-
const comma = value.indexOf(",", "data:".length);
|
|
116
|
-
if (comma === -1)
|
|
117
|
-
return undefined;
|
|
118
|
-
const header = value.slice("data:".length, comma);
|
|
119
|
-
const marker = ";base64";
|
|
120
|
-
if (header.slice(-marker.length).toLowerCase() !== marker)
|
|
121
|
-
return undefined;
|
|
122
|
-
const metadata = header.slice(0, -marker.length);
|
|
123
|
-
const base64 = value.slice(comma + 1);
|
|
124
|
-
if (!isCanonicalBase64(base64))
|
|
125
|
-
return undefined;
|
|
126
|
-
const [mediaType = "", ...parameters] = metadata.split(";");
|
|
127
|
-
if ((mediaType !== "" && !isMediaType(mediaType))
|
|
128
|
-
|| parameters.some((parameter) => !isMediaTypeParameter(parameter))) {
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
const normalizedMediaType = mediaType === "" ? "text/plain" : mediaType.toLowerCase();
|
|
132
|
-
const usualExtension = extensionForMimeType(normalizedMediaType);
|
|
133
|
-
const extension = usualExtension === false ? undefined : normalizeExtension(usualExtension);
|
|
134
|
-
return {
|
|
135
|
-
base64,
|
|
136
|
-
...(extension === undefined ? {} : { extension }),
|
|
137
|
-
size: decodedBase64Size(base64),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
function isCanonicalBase64(value) {
|
|
141
|
-
if (value.length % 4 !== 0)
|
|
142
|
-
return false;
|
|
143
|
-
const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
|
|
144
|
-
const contentLength = value.length - padding;
|
|
145
|
-
if (padding === 2 && contentLength % 4 !== 2)
|
|
146
|
-
return false;
|
|
147
|
-
if (padding === 1 && contentLength % 4 !== 3)
|
|
148
|
-
return false;
|
|
149
|
-
for (let index = 0; index < contentLength; index += 1) {
|
|
150
|
-
const code = value.charCodeAt(index);
|
|
151
|
-
if (!(code >= 0x41 && code <= 0x5a)
|
|
152
|
-
&& !(code >= 0x61 && code <= 0x7a)
|
|
153
|
-
&& !(code >= 0x30 && code <= 0x39)
|
|
154
|
-
&& code !== 0x2b
|
|
155
|
-
&& code !== 0x2f) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (padding > 0) {
|
|
160
|
-
const finalCode = value.charCodeAt(contentLength - 1);
|
|
161
|
-
const finalSextet = finalCode >= 0x41 && finalCode <= 0x5a
|
|
162
|
-
? finalCode - 0x41
|
|
163
|
-
: finalCode >= 0x61 && finalCode <= 0x7a
|
|
164
|
-
? finalCode - 0x61 + 26
|
|
165
|
-
: finalCode >= 0x30 && finalCode <= 0x39
|
|
166
|
-
? finalCode - 0x30 + 52
|
|
167
|
-
: finalCode === 0x2b ? 62 : 63;
|
|
168
|
-
const unusedBits = padding === 2 ? 4 : 2;
|
|
169
|
-
if ((finalSextet & ((1 << unusedBits) - 1)) !== 0)
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
function decodedBase64Size(value) {
|
|
175
|
-
if (value.length === 0)
|
|
176
|
-
return 0;
|
|
177
|
-
const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
|
|
178
|
-
return value.length / 4 * 3 - padding;
|
|
179
|
-
}
|
|
180
|
-
function isMediaType(value) {
|
|
181
|
-
const token = "[!#$%&'*+.^_`|~0-9A-Za-z-]+";
|
|
182
|
-
return new RegExp(`^${token}/${token}$`, "u").test(value);
|
|
183
|
-
}
|
|
184
|
-
function isMediaTypeParameter(value) {
|
|
185
|
-
return /^[!#$%&'*+.^_`|~0-9A-Za-z-]+=[^\s,;]+$/u.test(value);
|
|
186
|
-
}
|
|
187
|
-
function pathExtension(path) {
|
|
188
|
-
return normalizeExtension(extname(basename(path)).slice(1));
|
|
97
|
+
return `autofile:///blobs/${name}`;
|
|
189
98
|
}
|
|
190
99
|
function normalizeExtension(extension) {
|
|
191
100
|
const normalized = extension.toLowerCase();
|
|
192
101
|
return blobExtensionPattern.test(normalized) ? normalized : undefined;
|
|
193
102
|
}
|
|
194
|
-
function sizeRefusal(size) {
|
|
195
|
-
return { message: `blob is ${String(size)} bytes; limit is ${String(MAX_BLOB_BYTES)} bytes` };
|
|
196
|
-
}
|
|
197
|
-
async function storedBlobDetails(blobFolder, name) {
|
|
198
|
-
if (!await isDirectory(blobFolder))
|
|
199
|
-
return undefined;
|
|
200
|
-
const file = await openRegularFile(join(blobFolder, name), true);
|
|
201
|
-
if (file === undefined)
|
|
202
|
-
return undefined;
|
|
203
|
-
try {
|
|
204
|
-
return { size: file.size };
|
|
205
|
-
}
|
|
206
|
-
finally {
|
|
207
|
-
await file.handle.close();
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
async function readSourceFile(handle) {
|
|
211
|
-
const chunks = [];
|
|
212
|
-
let size = 0;
|
|
213
|
-
while (true) {
|
|
214
|
-
// The extra byte proves the source is too large without allowing a file that grew after stat,
|
|
215
|
-
// or a regular special file with an inaccurate size, to make this read unbounded.
|
|
216
|
-
const remainingWithSentinel = MAX_BLOB_BYTES + 1 - size;
|
|
217
|
-
const buffer = Buffer.alloc(Math.min(SOURCE_READ_CHUNK_BYTES, remainingWithSentinel));
|
|
218
|
-
const { bytesRead } = await handle.read(buffer, 0, buffer.byteLength, null);
|
|
219
|
-
if (bytesRead === 0)
|
|
220
|
-
return Buffer.concat(chunks, size);
|
|
221
|
-
size += bytesRead;
|
|
222
|
-
if (size > MAX_BLOB_BYTES)
|
|
223
|
-
return sizeRefusal(size);
|
|
224
|
-
chunks.push(bytesRead === buffer.byteLength ? buffer : buffer.subarray(0, bytesRead));
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
async function openRegularFile(path, noFollow) {
|
|
228
|
-
let handle;
|
|
229
|
-
try {
|
|
230
|
-
handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK | (noFollow ? constants.O_NOFOLLOW : 0));
|
|
231
|
-
}
|
|
232
|
-
catch (error) {
|
|
233
|
-
if (hasCode(error, "ENOENT")
|
|
234
|
-
|| hasCode(error, "ENOTDIR")
|
|
235
|
-
|| hasCode(error, "ELOOP")
|
|
236
|
-
|| hasCode(error, "ENXIO")
|
|
237
|
-
|| hasCode(error, "ENODEV")) {
|
|
238
|
-
return undefined;
|
|
239
|
-
}
|
|
240
|
-
throw error;
|
|
241
|
-
}
|
|
242
|
-
try {
|
|
243
|
-
const details = await handle.stat();
|
|
244
|
-
if (!details.isFile()) {
|
|
245
|
-
await handle.close();
|
|
246
|
-
return undefined;
|
|
247
|
-
}
|
|
248
|
-
return { handle, size: details.size };
|
|
249
|
-
}
|
|
250
|
-
catch (error) {
|
|
251
|
-
await handle.close();
|
|
252
|
-
throw error;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
async function writeBlobAtomically(path, bytes) {
|
|
256
|
-
const temporaryPath = join(dirname(path), `.${basename(path)}.${String(process.pid)}.${randomUUID()}`);
|
|
257
|
-
try {
|
|
258
|
-
await writeFile(temporaryPath, bytes, { flag: "wx" });
|
|
259
|
-
await rename(temporaryPath, path);
|
|
260
|
-
}
|
|
261
|
-
catch (error) {
|
|
262
|
-
try {
|
|
263
|
-
await unlink(temporaryPath);
|
|
264
|
-
}
|
|
265
|
-
catch (cleanupError) {
|
|
266
|
-
if (!hasCode(cleanupError, "ENOENT"))
|
|
267
|
-
throw cleanupError;
|
|
268
|
-
}
|
|
269
|
-
throw error;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
103
|
async function isDirectory(path) {
|
|
273
104
|
try {
|
|
274
105
|
return (await lstat(path)).isDirectory();
|
package/dist/blobs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -4,8 +4,8 @@ import { StdioServerTransport, serveStdio } from "@modelcontextprotocol/server/s
|
|
|
4
4
|
import { getSetting, getSettings, isSettingName, parsePort, setSetting, unsetSetting, } from "./config.js";
|
|
5
5
|
import { startHttpServer } from "./http.js";
|
|
6
6
|
import { buildServer } from "./server.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { Autofile } from "./index.js";
|
|
8
|
+
import { watchResources, } from "./mcp-watch.js";
|
|
9
9
|
const usage = `Usage:
|
|
10
10
|
autofile
|
|
11
11
|
autofile serve [--host <host>] [--port <port>]
|
|
@@ -64,24 +64,27 @@ async function main(args) {
|
|
|
64
64
|
}
|
|
65
65
|
async function runStdio() {
|
|
66
66
|
const settings = await getSettings();
|
|
67
|
-
const store =
|
|
67
|
+
const store = new Autofile({ folder: settings.storage });
|
|
68
68
|
let connectedServer;
|
|
69
69
|
let watcher;
|
|
70
70
|
let handle;
|
|
71
71
|
let stopping;
|
|
72
72
|
const stop = () => {
|
|
73
73
|
stopping ??= Promise.all([
|
|
74
|
-
|
|
74
|
+
(async () => {
|
|
75
|
+
await watcher?.close();
|
|
76
|
+
await store.close();
|
|
77
|
+
})(),
|
|
75
78
|
handle?.close() ?? Promise.resolve(),
|
|
76
79
|
]).then(() => undefined);
|
|
77
80
|
return stopping;
|
|
78
81
|
};
|
|
79
|
-
watcher = await
|
|
82
|
+
watcher = await watchResources(store, async (batch) => {
|
|
80
83
|
const server = connectedServer;
|
|
81
84
|
if (server === undefined || !server.isConnected())
|
|
82
85
|
return;
|
|
83
86
|
try {
|
|
84
|
-
const uris = new Set(batch.changes.
|
|
87
|
+
const uris = new Set(batch.changes.map(({ uri }) => uri));
|
|
85
88
|
for (const uri of uris) {
|
|
86
89
|
await server.server.sendResourceUpdated({ uri });
|
|
87
90
|
}
|
|
@@ -93,9 +96,12 @@ async function runStdio() {
|
|
|
93
96
|
if (server.isConnected())
|
|
94
97
|
throw error;
|
|
95
98
|
}
|
|
96
|
-
}, reportError)
|
|
99
|
+
}, reportError).catch(async (error) => {
|
|
100
|
+
await store.close();
|
|
101
|
+
throw error;
|
|
102
|
+
});
|
|
97
103
|
handle = serveStdio(async () => {
|
|
98
|
-
const server = await buildServer(store);
|
|
104
|
+
const server = await buildServer(store, { blobLocation: "stdio" });
|
|
99
105
|
connectedServer = server;
|
|
100
106
|
return server;
|
|
101
107
|
}, {
|
|
@@ -124,8 +130,8 @@ async function serve(args) {
|
|
|
124
130
|
...(overrides.host === undefined ? {} : { host: overrides.host }),
|
|
125
131
|
...(overrides.port === undefined ? {} : { port: overrides.port }),
|
|
126
132
|
};
|
|
127
|
-
const store =
|
|
128
|
-
const running = await startHttpServer(store,
|
|
133
|
+
const store = new Autofile({ folder: settings.storage });
|
|
134
|
+
const running = await startHttpServer(store, http, reportError);
|
|
129
135
|
process.stderr.write(`autofile: listening on ${running.endpoint.href}\n`);
|
|
130
136
|
const stop = () => {
|
|
131
137
|
void running.close().catch((error) => {
|