cimux-mcp 0.1.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 +21 -0
- package/README.md +133 -0
- package/dist/cli/cimux-cli.d.ts +10 -0
- package/dist/cli/cimux-cli.js +201 -0
- package/dist/cli/cimux-cli.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/install/cimux-install-plan.d.ts +29 -0
- package/dist/install/cimux-install-plan.js +187 -0
- package/dist/install/cimux-install-plan.js.map +1 -0
- package/dist/mcp/cimux-mcp-server.d.ts +4 -0
- package/dist/mcp/cimux-mcp-server.js +59 -0
- package/dist/mcp/cimux-mcp-server.js.map +1 -0
- package/dist/model/context-package.d.ts +913 -0
- package/dist/model/context-package.js +153 -0
- package/dist/model/context-package.js.map +1 -0
- package/dist/registration/mailbox-registration.d.ts +30 -0
- package/dist/registration/mailbox-registration.js +48 -0
- package/dist/registration/mailbox-registration.js.map +1 -0
- package/dist/runtime/mailbox-runtime.d.ts +22 -0
- package/dist/runtime/mailbox-runtime.js +50 -0
- package/dist/runtime/mailbox-runtime.js.map +1 -0
- package/dist/service/cimux-mailbox-service.d.ts +87 -0
- package/dist/service/cimux-mailbox-service.js +126 -0
- package/dist/service/cimux-mailbox-service.js.map +1 -0
- package/dist/storage/mailbox-store.d.ts +22 -0
- package/dist/storage/mailbox-store.js +2 -0
- package/dist/storage/mailbox-store.js.map +1 -0
- package/dist/storage/sqlite-cimux-store.d.ts +21 -0
- package/dist/storage/sqlite-cimux-store.js +201 -0
- package/dist/storage/sqlite-cimux-store.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/docs/mvp-readiness.md +85 -0
- package/package.json +51 -0
- package/scripts/demo-local-handoff.mjs +73 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { DatabaseSync } from "node:sqlite";
|
|
4
|
+
import { createContextPackagePreview, contextPackageSchema, mailboxNameSchema, mailboxSchema, normalizeInboxPreviewLimit } from "../model/context-package.js";
|
|
5
|
+
export class SQLiteCimuxStore {
|
|
6
|
+
db;
|
|
7
|
+
constructor(databasePath) {
|
|
8
|
+
// The caller decides where the local Cimux database lives. Production code
|
|
9
|
+
// will point this at ~/.cimux/inbox.sqlite; tests can use a temp path.
|
|
10
|
+
fs.mkdirSync(path.dirname(databasePath), { recursive: true });
|
|
11
|
+
this.db = new DatabaseSync(databasePath);
|
|
12
|
+
this.db.exec("pragma foreign_keys = ON;");
|
|
13
|
+
this.migrate();
|
|
14
|
+
}
|
|
15
|
+
async createMailbox(name) {
|
|
16
|
+
const parsedName = mailboxNameSchema.parse(name);
|
|
17
|
+
const now = new Date().toISOString();
|
|
18
|
+
// Creating a mailbox is idempotent so repeated session registration can
|
|
19
|
+
// safely call this without resetting the durable mailbox record.
|
|
20
|
+
this.db
|
|
21
|
+
.prepare(`insert into mailboxes (name, created_at, last_seen_at)
|
|
22
|
+
values (?, ?, null)
|
|
23
|
+
on conflict(name) do nothing`)
|
|
24
|
+
.run(parsedName, now);
|
|
25
|
+
const mailbox = await this.getMailbox(parsedName);
|
|
26
|
+
if (!mailbox) {
|
|
27
|
+
throw new Error(`Mailbox was not created: ${parsedName}`);
|
|
28
|
+
}
|
|
29
|
+
return mailbox;
|
|
30
|
+
}
|
|
31
|
+
async getMailbox(name) {
|
|
32
|
+
const parsedName = mailboxNameSchema.parse(name);
|
|
33
|
+
const row = this.db
|
|
34
|
+
.prepare("select name, created_at, last_seen_at from mailboxes where name = ?")
|
|
35
|
+
.get(parsedName);
|
|
36
|
+
return row ? toMailbox(row) : null;
|
|
37
|
+
}
|
|
38
|
+
async listMailboxes() {
|
|
39
|
+
const rows = this.db
|
|
40
|
+
.prepare("select name, created_at, last_seen_at from mailboxes order by name asc")
|
|
41
|
+
.all();
|
|
42
|
+
return rows.map(toMailbox);
|
|
43
|
+
}
|
|
44
|
+
async createContextPackage(contextPackage) {
|
|
45
|
+
const parsed = contextPackageSchema.parse(contextPackage);
|
|
46
|
+
await this.assertMailboxExists(parsed.fromMailbox);
|
|
47
|
+
await this.assertMailboxExists(parsed.toMailbox);
|
|
48
|
+
this.db
|
|
49
|
+
.prepare(`insert into context_packages (
|
|
50
|
+
id,
|
|
51
|
+
from_mailbox,
|
|
52
|
+
to_mailbox,
|
|
53
|
+
title,
|
|
54
|
+
summary,
|
|
55
|
+
body,
|
|
56
|
+
tags_json,
|
|
57
|
+
artifacts_json,
|
|
58
|
+
payload_json,
|
|
59
|
+
created_at,
|
|
60
|
+
read_at,
|
|
61
|
+
ack_json
|
|
62
|
+
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
63
|
+
.run(parsed.id, parsed.fromMailbox, parsed.toMailbox, parsed.title, parsed.summary, parsed.body, JSON.stringify(parsed.tags), JSON.stringify(parsed.artifacts), JSON.stringify(parsed.payload), parsed.createdAt, parsed.readAt, JSON.stringify(parsed.ack));
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
66
|
+
async listInboxPreviews(mailboxName, options = {}) {
|
|
67
|
+
const parsedMailboxName = mailboxNameSchema.parse(mailboxName);
|
|
68
|
+
const limit = normalizeInboxPreviewLimit(options.limit);
|
|
69
|
+
const clauses = ["to_mailbox = ?"];
|
|
70
|
+
const params = [parsedMailboxName];
|
|
71
|
+
if (options.unreadOnly) {
|
|
72
|
+
clauses.push("read_at is null");
|
|
73
|
+
}
|
|
74
|
+
params.push(limit);
|
|
75
|
+
const rows = this.db
|
|
76
|
+
.prepare(`select * from context_packages
|
|
77
|
+
where ${clauses.join(" and ")}
|
|
78
|
+
order by created_at desc
|
|
79
|
+
limit ?`)
|
|
80
|
+
.all(...params);
|
|
81
|
+
return rows.map((row) => createContextPackagePreview(toContextPackage(row)));
|
|
82
|
+
}
|
|
83
|
+
async readContextPackage(id) {
|
|
84
|
+
const contextPackage = await this.getContextPackage(id);
|
|
85
|
+
if (!contextPackage) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
if (contextPackage.readAt) {
|
|
89
|
+
return contextPackage;
|
|
90
|
+
}
|
|
91
|
+
const readAt = new Date().toISOString();
|
|
92
|
+
this.db
|
|
93
|
+
.prepare("update context_packages set read_at = ? where id = ?")
|
|
94
|
+
.run(readAt, contextPackage.id);
|
|
95
|
+
return {
|
|
96
|
+
...contextPackage,
|
|
97
|
+
readAt
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async getContextPackage(id) {
|
|
101
|
+
const row = this.db
|
|
102
|
+
.prepare("select * from context_packages where id = ?")
|
|
103
|
+
.get(id);
|
|
104
|
+
return row ? toContextPackage(row) : null;
|
|
105
|
+
}
|
|
106
|
+
async ackContextPackage(id, options) {
|
|
107
|
+
const contextPackage = await this.getContextPackage(id);
|
|
108
|
+
if (!contextPackage) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const ackBy = mailboxNameSchema.parse(options.ackBy);
|
|
112
|
+
const ack = {
|
|
113
|
+
status: "acknowledged",
|
|
114
|
+
ackAt: new Date().toISOString(),
|
|
115
|
+
ackBy,
|
|
116
|
+
note: options.note ?? null
|
|
117
|
+
};
|
|
118
|
+
this.db
|
|
119
|
+
.prepare("update context_packages set ack_json = ? where id = ?")
|
|
120
|
+
.run(JSON.stringify(ack), id);
|
|
121
|
+
return {
|
|
122
|
+
...contextPackage,
|
|
123
|
+
ack
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
close() {
|
|
127
|
+
this.db.close();
|
|
128
|
+
}
|
|
129
|
+
async assertMailboxExists(name) {
|
|
130
|
+
const mailbox = await this.getMailbox(name);
|
|
131
|
+
if (!mailbox) {
|
|
132
|
+
throw new UnknownMailboxError(name);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
migrate() {
|
|
136
|
+
// Context Packages reference mailboxes by name. Unknown recipients are
|
|
137
|
+
// rejected at storage time instead of being silently auto-created.
|
|
138
|
+
this.db.exec(`
|
|
139
|
+
create table if not exists mailboxes (
|
|
140
|
+
name text primary key,
|
|
141
|
+
created_at text not null,
|
|
142
|
+
last_seen_at text
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
create table if not exists context_packages (
|
|
146
|
+
id text primary key,
|
|
147
|
+
from_mailbox text not null references mailboxes(name),
|
|
148
|
+
to_mailbox text not null references mailboxes(name),
|
|
149
|
+
title text not null,
|
|
150
|
+
summary text not null,
|
|
151
|
+
body text not null,
|
|
152
|
+
tags_json text not null,
|
|
153
|
+
artifacts_json text not null,
|
|
154
|
+
payload_json text not null,
|
|
155
|
+
created_at text not null,
|
|
156
|
+
read_at text,
|
|
157
|
+
ack_json text not null
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
create index if not exists idx_context_packages_id
|
|
161
|
+
on context_packages (id);
|
|
162
|
+
|
|
163
|
+
create index if not exists idx_context_packages_inbox_created
|
|
164
|
+
on context_packages (to_mailbox, created_at desc);
|
|
165
|
+
`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export class UnknownMailboxError extends Error {
|
|
169
|
+
mailboxName;
|
|
170
|
+
constructor(mailboxName) {
|
|
171
|
+
super(`Unknown mailbox: ${mailboxName}`);
|
|
172
|
+
this.mailboxName = mailboxName;
|
|
173
|
+
this.name = "UnknownMailboxError";
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function toMailbox(row) {
|
|
177
|
+
// Validate rows on the way out so database changes cannot silently drift
|
|
178
|
+
// away from the public model contract.
|
|
179
|
+
return mailboxSchema.parse({
|
|
180
|
+
name: row.name,
|
|
181
|
+
createdAt: row.created_at,
|
|
182
|
+
lastSeenAt: row.last_seen_at
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function toContextPackage(row) {
|
|
186
|
+
return contextPackageSchema.parse({
|
|
187
|
+
id: row.id,
|
|
188
|
+
fromMailbox: row.from_mailbox,
|
|
189
|
+
toMailbox: row.to_mailbox,
|
|
190
|
+
title: row.title,
|
|
191
|
+
summary: row.summary,
|
|
192
|
+
body: row.body,
|
|
193
|
+
tags: JSON.parse(row.tags_json),
|
|
194
|
+
artifacts: JSON.parse(row.artifacts_json),
|
|
195
|
+
payload: JSON.parse(row.payload_json),
|
|
196
|
+
createdAt: row.created_at,
|
|
197
|
+
readAt: row.read_at,
|
|
198
|
+
ack: JSON.parse(row.ack_json)
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=sqlite-cimux-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-cimux-store.js","sourceRoot":"","sources":["../../src/storage/sqlite-cimux-store.ts"],"names":[],"mappings":"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"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC;AAC5B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# MVP Readiness
|
|
2
|
+
|
|
3
|
+
This checklist defines the local Cimux MVP: agents can send intentional context to another local agent inbox; receivers can preview, read, and ack; empty inbox checks do not emit prompt context.
|
|
4
|
+
|
|
5
|
+
## Automated Checks
|
|
6
|
+
|
|
7
|
+
Run before every MVP release candidate:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm test
|
|
11
|
+
npm run typecheck
|
|
12
|
+
npm run build
|
|
13
|
+
npm run demo:local
|
|
14
|
+
npm pack --dry-run
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Expected result:
|
|
18
|
+
|
|
19
|
+
- all tests pass
|
|
20
|
+
- the demo sends, notifies, previews, reads, and acks one Context Package
|
|
21
|
+
- the npm tarball includes `dist`, `README.md`, `package.json`, and `scripts/demo-local-handoff.mjs`
|
|
22
|
+
|
|
23
|
+
## Manual Install Check
|
|
24
|
+
|
|
25
|
+
Run this from the repo on a local machine:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install
|
|
29
|
+
npm run build
|
|
30
|
+
npm link
|
|
31
|
+
cimux --help
|
|
32
|
+
cimux --version
|
|
33
|
+
cimux install --dry-run
|
|
34
|
+
cimux install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Expected result:
|
|
38
|
+
|
|
39
|
+
- `cimux --help` prints the command list
|
|
40
|
+
- `cimux --version` prints the package version
|
|
41
|
+
- `cimux install --dry-run` prints Codex and Claude config snippets
|
|
42
|
+
- `cimux install` writes config and creates `.cimux.bak` backups before updating existing files
|
|
43
|
+
- a new Codex or Claude session sees the Cimux MCP server after restart
|
|
44
|
+
|
|
45
|
+
## Harness Verification
|
|
46
|
+
|
|
47
|
+
After installing and restarting the target harness:
|
|
48
|
+
|
|
49
|
+
1. Confirm the Cimux MCP tools are visible:
|
|
50
|
+
- `register_session`
|
|
51
|
+
- `send_context`
|
|
52
|
+
- `check_inbox`
|
|
53
|
+
- `read_context`
|
|
54
|
+
- `ack_context`
|
|
55
|
+
2. Start or resume a session in a git repo.
|
|
56
|
+
3. Confirm the session can register as `harness/branch-name`.
|
|
57
|
+
4. Send a Context Package to that mailbox.
|
|
58
|
+
5. Submit a new user prompt to the receiving session.
|
|
59
|
+
6. Confirm the hook emits one short notification line.
|
|
60
|
+
7. Confirm `check_inbox` returns previews only.
|
|
61
|
+
8. Confirm `read_context` returns the full body.
|
|
62
|
+
9. Confirm `ack_context` marks the package acknowledged.
|
|
63
|
+
|
|
64
|
+
## Known Limits
|
|
65
|
+
|
|
66
|
+
- Local-only SQLite storage.
|
|
67
|
+
- No hosted auth, workspaces, or SaaS tenancy.
|
|
68
|
+
- No vector database or embeddings.
|
|
69
|
+
- No automatic routing.
|
|
70
|
+
- No remote mailbox sync.
|
|
71
|
+
- No read-only inspector UI yet.
|
|
72
|
+
- Hook notification depends on harness hook support and fires on the next user prompt, not as a real-time interrupt.
|
|
73
|
+
- The installer targets the first supported Codex and Claude config paths and may need more harness-specific hardening before a public release.
|
|
74
|
+
|
|
75
|
+
## MVP Complete Bar
|
|
76
|
+
|
|
77
|
+
Call the local MVP complete when:
|
|
78
|
+
|
|
79
|
+
- automated checks pass
|
|
80
|
+
- local demo passes
|
|
81
|
+
- manual install check passes on one machine
|
|
82
|
+
- at least one harness can see the MCP tools after install/restart
|
|
83
|
+
- hook notification is verified in that harness
|
|
84
|
+
- README and this checklist match the observed behavior
|
|
85
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cimux-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local-first mailbox for intentional AI agent context handoffs.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"agents",
|
|
8
|
+
"context",
|
|
9
|
+
"mailbox",
|
|
10
|
+
"codex",
|
|
11
|
+
"claude"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/jackkslash/cimux.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/jackkslash/cimux/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/jackkslash/cimux#readme",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"bin": {
|
|
24
|
+
"cimux": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"docs",
|
|
29
|
+
"scripts"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"clean": "node --eval \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
33
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
34
|
+
"demo:local": "npm run build && node scripts/demo-local-handoff.mjs",
|
|
35
|
+
"prepublishOnly": "npm run build && npm test",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"typecheck": "tsc --noEmit"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
|
+
"zod": "^3.25.76"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.13.14",
|
|
45
|
+
"typescript": "^5.8.3",
|
|
46
|
+
"vitest": "^3.2.4"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=22.13"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "cimux-demo-"));
|
|
7
|
+
const dbPath = path.join(tempDir, "cimux.sqlite");
|
|
8
|
+
const cliPath = path.join(process.cwd(), "dist", "index.js");
|
|
9
|
+
|
|
10
|
+
function run(args) {
|
|
11
|
+
return execFileSync(process.execPath, [cliPath, ...args], {
|
|
12
|
+
cwd: tempDir,
|
|
13
|
+
encoding: "utf8",
|
|
14
|
+
env: {
|
|
15
|
+
...process.env,
|
|
16
|
+
CIMUX_DB_PATH: dbPath
|
|
17
|
+
}
|
|
18
|
+
}).trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function runJson(args) {
|
|
22
|
+
return JSON.parse(run(args));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log("Cimux local handoff demo");
|
|
26
|
+
console.log(`Database: ${dbPath}`);
|
|
27
|
+
|
|
28
|
+
run(["register", "--mailbox", "codex/backend-auth"]);
|
|
29
|
+
run(["register", "--mailbox", "claude/frontend-login"]);
|
|
30
|
+
|
|
31
|
+
const sent = runJson([
|
|
32
|
+
"send",
|
|
33
|
+
"--from",
|
|
34
|
+
"codex/backend-auth",
|
|
35
|
+
"--to",
|
|
36
|
+
"claude/frontend-login",
|
|
37
|
+
"--title",
|
|
38
|
+
"Auth handoff",
|
|
39
|
+
"--summary",
|
|
40
|
+
"Frontend should handle the new auth error.",
|
|
41
|
+
"--body",
|
|
42
|
+
"validateSession now throws ExpiredSessionError.",
|
|
43
|
+
"--tags",
|
|
44
|
+
"auth,frontend"
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
console.log(`Sent: ${sent.contextPackage.id}`);
|
|
48
|
+
console.log(run(["notify", "--mailbox", "claude/frontend-login"]));
|
|
49
|
+
|
|
50
|
+
const inbox = runJson(["check", "--mailbox", "claude/frontend-login"]);
|
|
51
|
+
console.log(`Preview count: ${inbox.previews.length}`);
|
|
52
|
+
console.log(`Preview title: ${inbox.previews[0].title}`);
|
|
53
|
+
|
|
54
|
+
const read = runJson([
|
|
55
|
+
"read",
|
|
56
|
+
"--mailbox",
|
|
57
|
+
"claude/frontend-login",
|
|
58
|
+
"--id",
|
|
59
|
+
sent.contextPackage.id
|
|
60
|
+
]);
|
|
61
|
+
console.log(`Read body: ${read.contextPackage.body}`);
|
|
62
|
+
|
|
63
|
+
const acked = runJson([
|
|
64
|
+
"ack",
|
|
65
|
+
"--mailbox",
|
|
66
|
+
"claude/frontend-login",
|
|
67
|
+
"--id",
|
|
68
|
+
sent.contextPackage.id,
|
|
69
|
+
"--note",
|
|
70
|
+
"Loaded in demo."
|
|
71
|
+
]);
|
|
72
|
+
console.log(`Ack: ${acked.contextPackage.ack.status}`);
|
|
73
|
+
|