Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d456f29138 | ||
|
|
d37d2419d6 | ||
|
|
ee0b72f43b | ||
|
|
d3abc762fd | ||
|
|
d0eb2af183 |
@@ -36,7 +36,17 @@ jobs:
|
|||||||
- name: Set package version
|
- name: Set package version
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ steps.ver.outputs.version }}
|
VERSION: ${{ steps.ver.outputs.version }}
|
||||||
run: npm version --no-git-tag-version "$VERSION"
|
run: npm version --no-git-tag-version --allow-same-version "$VERSION"
|
||||||
|
|
||||||
|
- name: Sync plugin.json version
|
||||||
|
working-directory: ${{ github.workspace }}
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.ver.outputs.version }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
jq --arg v "$VERSION" '.version = $v' plugin/.claude-plugin/plugin.json > plugin/.claude-plugin/plugin.json.tmp
|
||||||
|
mv plugin/.claude-plugin/plugin.json.tmp plugin/.claude-plugin/plugin.json
|
||||||
|
cat plugin/.claude-plugin/plugin.json
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -44,9 +54,6 @@ jobs:
|
|||||||
- name: Test
|
- name: Test
|
||||||
run: npm test
|
run: npm test
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: Pack
|
- name: Pack
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ steps.ver.outputs.version }}
|
VERSION: ${{ steps.ver.outputs.version }}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ Then drop this into your project's `.mcp.json`:
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"mailbox": {
|
"mailbox": {
|
||||||
"type": "http",
|
"type": "http",
|
||||||
"url": "http://127.0.0.1:47822/mcp"
|
"url": "http://127.0.0.1:37849/mcp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ dotnet publish src/ClaudeMailbox -c Release -r win-x64 --self-contained -p:Publi
|
|||||||
Put the resulting `claude-mailbox.exe` on `PATH`. Windows-only `install-service` verbs (admin shell):
|
Put the resulting `claude-mailbox.exe` on `PATH`. Windows-only `install-service` verbs (admin shell):
|
||||||
|
|
||||||
```
|
```
|
||||||
claude-mailbox install-service [--port 47822] [--bind 127.0.0.1] [--db-path <path>]
|
claude-mailbox install-service [--port 37849] [--bind 127.0.0.1] [--db-path <path>]
|
||||||
claude-mailbox uninstall-service [--purge]
|
claude-mailbox uninstall-service [--purge]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ CLI flag > mailbox.json > built-in defaults
|
|||||||
|
|
||||||
`mailbox.json` is searched at `~/.claude-mailbox/mailbox.json` (per-user), and on Windows additionally at `%ProgramData%\ClaudeMailbox\mailbox.json` (machine-wide, written by `--service` install). Override with `--config <path>`.
|
`mailbox.json` is searched at `~/.claude-mailbox/mailbox.json` (per-user), and on Windows additionally at `%ProgramData%\ClaudeMailbox\mailbox.json` (machine-wide, written by `--service` install). Override with `--config <path>`.
|
||||||
|
|
||||||
Defaults: port `47822`, bind `127.0.0.1`, database at `~/.claude-mailbox/mailbox.db`.
|
Defaults: port `37849`, bind `127.0.0.1`, database at `~/.claude-mailbox/mailbox.db`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
4
node/package-lock.json
generated
4
node/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@kuns/claude-mailbox",
|
"name": "@kuns/claude-mailbox",
|
||||||
"version": "1.0.1",
|
"version": "1.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@kuns/claude-mailbox",
|
"name": "@kuns/claude-mailbox",
|
||||||
"version": "1.0.1",
|
"version": "1.2.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@kuns/claude-mailbox",
|
"name": "@kuns/claude-mailbox",
|
||||||
"version": "1.0.1",
|
"version": "1.2.0",
|
||||||
"description": "Standalone MCP mail server that lets parallel Claude sessions coordinate with each other.",
|
"description": "Standalone MCP mail server that lets parallel Claude sessions coordinate with each other.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ program
|
|||||||
program
|
program
|
||||||
.command("mcp-stdio")
|
.command("mcp-stdio")
|
||||||
.description(
|
.description(
|
||||||
"Run a stdio MCP server that proxies tool calls to the local daemon's REST API. The daemon URL comes from $CLAUDE_MAILBOX_URL (default http://127.0.0.1:47822). Used by the Claude Code plugin's .mcp.json so the URL is configurable per machine without env-substitution in the URL field.",
|
"Run a stdio MCP server that proxies tool calls to the local daemon's REST API. The daemon URL comes from $CLAUDE_MAILBOX_URL (default http://127.0.0.1:37849). Used by the Claude Code plugin's .mcp.json so the URL is configurable per machine without env-substitution in the URL field.",
|
||||||
)
|
)
|
||||||
.action(async () => {
|
.action(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -345,11 +345,49 @@ program
|
|||||||
.option("--port <port>", "Port to listen on", (v) => parseInt(v, 10))
|
.option("--port <port>", "Port to listen on", (v) => parseInt(v, 10))
|
||||||
.option("--bind <address>", "Bind address")
|
.option("--bind <address>", "Bind address")
|
||||||
.option("--db-path <path>", "SQLite database path")
|
.option("--db-path <path>", "SQLite database path")
|
||||||
.action(async (opts: { service?: boolean; port?: number; bind?: string; dbPath?: string }) => {
|
.option(
|
||||||
const mgr = await autostartManager(opts.service ? "service" : "default");
|
"--skip-port-check",
|
||||||
await mgr.install({ port: opts.port, bind: opts.bind, dbPath: opts.dbPath });
|
"Skip the pre-install probe for a foreign occupant on the daemon's port",
|
||||||
console.log("Autostart installed.");
|
)
|
||||||
});
|
.action(
|
||||||
|
async (opts: {
|
||||||
|
service?: boolean;
|
||||||
|
port?: number;
|
||||||
|
bind?: string;
|
||||||
|
dbPath?: string;
|
||||||
|
skipPortCheck?: boolean;
|
||||||
|
}) => {
|
||||||
|
if (!opts.skipPortCheck) {
|
||||||
|
const cfg = resolveConfig({ port: opts.port, bind: opts.bind, dbPath: opts.dbPath });
|
||||||
|
const probeUrl = `http://${cfg.bind}:${cfg.port}/health`;
|
||||||
|
try {
|
||||||
|
const res = await fetch(probeUrl, { headers: { Accept: "application/json" } });
|
||||||
|
const text = await res.text();
|
||||||
|
let parsed: { status?: string; version?: string } | null = null;
|
||||||
|
try {
|
||||||
|
parsed = text.length ? (JSON.parse(text) as { status?: string; version?: string }) : null;
|
||||||
|
} catch {
|
||||||
|
parsed = null;
|
||||||
|
}
|
||||||
|
if (res.ok && parsed?.status === "ok" && parsed.version) {
|
||||||
|
console.log(
|
||||||
|
`Port ${cfg.port} already serves a claude-mailbox daemon (version ${parsed.version}). Autostart will manage that one.`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`Port ${cfg.port} is held by a non-claude-mailbox service (status ${res.status}). Pick a free port via \`--port <n>\` or write {"port": <n>} to ~/.claude-mailbox/mailbox.json. Use --skip-port-check to bypass.`,
|
||||||
|
);
|
||||||
|
process.exit(4);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Connection refused or similar — port is free, proceed.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const mgr = await autostartManager(opts.service ? "service" : "default");
|
||||||
|
await mgr.install({ port: opts.port, bind: opts.bind, dbPath: opts.dbPath });
|
||||||
|
console.log("Autostart installed.");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
program
|
program
|
||||||
.command("uninstall-autostart")
|
.command("uninstall-autostart")
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|||||||
import { homedir } from "node:os";
|
import { homedir } from "node:os";
|
||||||
import { join, resolve } from "node:path";
|
import { join, resolve } from "node:path";
|
||||||
|
|
||||||
export const DEFAULT_PORT = 47822;
|
export const DEFAULT_PORT = 37849;
|
||||||
export const DEFAULT_BIND = "127.0.0.1";
|
export const DEFAULT_BIND = "127.0.0.1";
|
||||||
|
|
||||||
export interface FileConfig {
|
export interface FileConfig {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-mailbox",
|
"name": "claude-mailbox",
|
||||||
"version": "0.1.0",
|
"version": "1.2.0",
|
||||||
"description": "Auto-checks the local Claude-Mailbox daemon before every prompt and injects pending messages into the conversation context.",
|
"description": "Auto-checks the local Claude-Mailbox daemon before every prompt and injects pending messages into the conversation context.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Mika Kuns"
|
"name": "Mika Kuns"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ The doctor walks the rest:
|
|||||||
|
|
||||||
1. installs the `claude-mailbox` binary via `npm install -g @kuns/claude-mailbox` if missing (asks first)
|
1. installs the `claude-mailbox` binary via `npm install -g @kuns/claude-mailbox` if missing (asks first)
|
||||||
2. registers the daemon for autostart and starts it if needed
|
2. registers the daemon for autostart and starts it if needed
|
||||||
3. health-probes `http://127.0.0.1:47822/health`
|
3. health-probes `http://127.0.0.1:37849/health`
|
||||||
4. optionally lets you set a **base prefix** (e.g., `backend`) — without one, mailbox names are anonymous (`claude-XXXXXXXX`)
|
4. optionally lets you set a **base prefix** (e.g., `backend`) — without one, mailbox names are anonymous (`claude-XXXXXXXX`)
|
||||||
5. runs a self → self smoke test
|
5. runs a self → self smoke test
|
||||||
|
|
||||||
|
|||||||
@@ -29,19 +29,19 @@ Run: `claude-mailbox --version`
|
|||||||
|
|
||||||
## Step 2 — port-conflict check (before autostart!)
|
## Step 2 — port-conflict check (before autostart!)
|
||||||
|
|
||||||
Default port is 47822. Probe whether anything is already on it:
|
Default port is 37849. Probe whether anything is already on it:
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -sf http://127.0.0.1:47822/health
|
curl -sf http://127.0.0.1:37849/health
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Returns a JSON body with `"status":"ok"` and a `version` field that matches `claude-mailbox --version`** → it's already our daemon, ✓ skip to Step 4.
|
- **Returns a JSON body with `"status":"ok"` and a `version` field that matches `claude-mailbox --version`** → it's already our daemon, ✓ skip to Step 4.
|
||||||
- **Returns 200 with `"status":"ok"` but a different `version`** → it's an older claude-mailbox; treat as running, ✓.
|
- **Returns 200 with `"status":"ok"` but a different `version`** → it's an older claude-mailbox; treat as running, ✓.
|
||||||
- **Returns non-200, non-JSON, or any other foreign response** → **port conflict**. Some other process owns 47822.
|
- **Returns non-200, non-JSON, or any other foreign response** → **port conflict**. Some other process owns 37849.
|
||||||
- **Connection refused** → port is free, ✓ continue to Step 3.
|
- **Connection refused** → port is free, ✓ continue to Step 3.
|
||||||
|
|
||||||
If port conflict detected:
|
If port conflict detected:
|
||||||
1. Tell the user which process holds the port (Windows: `Get-NetTCPConnection -LocalPort 47822 | Select-Object OwningProcess`, then `Get-Process -Id <pid>`; macOS/Linux: `lsof -i :47822`).
|
1. Tell the user which process holds the port (Windows: `Get-NetTCPConnection -LocalPort 37849 | Select-Object OwningProcess`, then `Get-Process -Id <pid>`; macOS/Linux: `lsof -i :37849`).
|
||||||
2. Pick a free port. Default suggestion: **47900**. Verify it's free: `curl -sf http://127.0.0.1:47900/health` should fail with connection refused.
|
2. Pick a free port. Default suggestion: **47900**. Verify it's free: `curl -sf http://127.0.0.1:47900/health` should fail with connection refused.
|
||||||
3. Read `~/.claude-mailbox/mailbox.json` (create empty `{}` if missing) and merge `{"port": <chosen>}`. Write back.
|
3. Read `~/.claude-mailbox/mailbox.json` (create empty `{}` if missing) and merge `{"port": <chosen>}`. Write back.
|
||||||
4. Also write the override into `.claude/settings.json` env so the plugin's hooks find the right URL:
|
4. Also write the override into `.claude/settings.json` env so the plugin's hooks find the right URL:
|
||||||
@@ -65,7 +65,7 @@ If `install-autostart` still fails after both attempts (very rare — would mean
|
|||||||
|
|
||||||
## Step 4 — health probe
|
## Step 4 — health probe
|
||||||
|
|
||||||
Hit `http://127.0.0.1:<port>/health` (use the configured port, not necessarily 47822). Expect a JSON body with `"status":"ok"` AND a `version` matching `claude-mailbox --version`. If unreachable or version mismatch, stop and report.
|
Hit `http://127.0.0.1:<port>/health` (use the configured port, not necessarily 37849). Expect a JSON body with `"status":"ok"` AND a `version` matching `claude-mailbox --version`. If unreachable or version mismatch, stop and report.
|
||||||
|
|
||||||
## Step 5 — mailbox identity (base prefix)
|
## Step 5 — mailbox identity (base prefix)
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ Claude-Mailbox doctor
|
|||||||
binary: <version>
|
binary: <version>
|
||||||
daemon: Running (port: <port>, what you did if anything)
|
daemon: Running (port: <port>, what you did if anything)
|
||||||
health: ok
|
health: ok
|
||||||
port conflict: none | resolved (moved from 47822 to <port>)
|
port conflict: none | resolved (moved from 37849 to <port>)
|
||||||
base prefix: <name from settings, or "auto-derived (anonymous)">
|
base prefix: <name from settings, or "auto-derived (anonymous)">
|
||||||
smoke test: passed | failed
|
smoke test: passed | failed
|
||||||
restart hint: yes if restart_needed, otherwise no
|
restart hint: yes if restart_needed, otherwise no
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Print exactly this block, filling in each line:
|
|||||||
Claude-Mailbox status
|
Claude-Mailbox status
|
||||||
binary: <output of `claude-mailbox --version`, or "not installed">
|
binary: <output of `claude-mailbox --version`, or "not installed">
|
||||||
daemon: <output of `claude-mailbox status`>
|
daemon: <output of `claude-mailbox status`>
|
||||||
health: <"ok" if GET http://127.0.0.1:47822/health returns 200, else "unreachable">
|
health: <"ok" if GET http://127.0.0.1:37849/health returns 200, else "unreachable">
|
||||||
mailbox name: <value of env.CLAUDE_MAILBOX_NAME in ./.claude/settings.json, or "unset"; also note if ~/.claude/settings.json has a value>
|
mailbox name: <value of env.CLAUDE_MAILBOX_NAME in ./.claude/settings.json, or "unset"; also note if ~/.claude/settings.json has a value>
|
||||||
pending: <integer count from `claude-mailbox peek --name <resolved-name>` if name is set, else "n/a">
|
pending: <integer count from `claude-mailbox peek --name <resolved-name>` if name is set, else "n/a">
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace ClaudeMailbox.Cli;
|
|||||||
|
|
||||||
public static class ClientCommands
|
public static class ClientCommands
|
||||||
{
|
{
|
||||||
private const string DefaultUrl = "http://127.0.0.1:47822";
|
private const string DefaultUrl = "http://127.0.0.1:37849";
|
||||||
|
|
||||||
public static async Task<int> RunAsync(string[] args)
|
public static async Task<int> RunAsync(string[] args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public static class ServiceCommands
|
|||||||
if (!File.Exists(configPath))
|
if (!File.Exists(configPath))
|
||||||
{
|
{
|
||||||
var portStr = ClientCommands.GetOption(args, "--port");
|
var portStr = ClientCommands.GetOption(args, "--port");
|
||||||
var port = int.TryParse(portStr, out var p) ? p : 47822;
|
var port = int.TryParse(portStr, out var p) ? p : 37849;
|
||||||
var bind = ClientCommands.GetOption(args, "--bind") ?? "127.0.0.1";
|
var bind = ClientCommands.GetOption(args, "--bind") ?? "127.0.0.1";
|
||||||
var dbPath = ClientCommands.GetOption(args, "--db-path") ?? defaultDbPath;
|
var dbPath = ClientCommands.GetOption(args, "--db-path") ?? defaultDbPath;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ namespace ClaudeMailbox.Config;
|
|||||||
|
|
||||||
public sealed class DaemonConfig
|
public sealed class DaemonConfig
|
||||||
{
|
{
|
||||||
public const int DefaultPort = 47822;
|
public const int DefaultPort = 37849;
|
||||||
public const string DefaultBindAddress = "127.0.0.1";
|
public const string DefaultBindAddress = "127.0.0.1";
|
||||||
|
|
||||||
public int Port { get; init; } = DefaultPort;
|
public int Port { get; init; } = DefaultPort;
|
||||||
|
|||||||
Reference in New Issue
Block a user