44 Commits

Author SHA1 Message Date
Mika Kuns
06a2ea6b7b chore(release): 1.4.1
All checks were successful
Release / release (push) Successful in 7s
CI (Node) / build-test (push) Successful in 8s
Release (Node) / release (push) Successful in 11s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.4.1
2026-05-20 13:34:34 +02:00
Mika Kuns
01c22ff9a3 fix(cli): lazy-load server module so non-serve commands skip node:sqlite
All checks were successful
CI (Node) / build-test (push) Successful in 8s
Importing server.js statically also imports db.ts, which pulls in
node:sqlite at startup. On Linux that emits an ExperimentalWarning to
stderr for every CLI invocation -- visible to users running the hook on
every prompt. Defer the server import into the serve action so check
--hook / session-announce / send / peek / list never touch sqlite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:30:04 +02:00
Mika Kuns
7b65545600 chore(release): 1.4.0
Some checks failed
CI (Node) / build-test (push) Failing after 7s
Release / release (push) Successful in 7s
Release (Node) / release (push) Failing after 8s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.4.0
2026-05-20 13:14:22 +02:00
Mika Kuns
b10ac36ed0 feat(naming)!: auto-derive mailbox name from project + runtime rename
Mailbox names are now built as <project>-<session-short>, where <project>
is the sanitized git-repo basename (or cwd basename) — no more env-var
prefix step. Sessions can re-tag themselves at runtime via the new
mcp__mailbox__rename tool (POST /v1/rename), which transfers all
pending messages to the new name in a single transaction. Peers using
the old name re-discover via list_mailboxes.

BREAKING: \$CLAUDE_MAILBOX_NAME is no longer read. Existing setups that
relied on the env-var prefix should remove it from .claude/settings.json;
the prefix now comes from the working directory automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:14:15 +02:00
Mika Kuns
8832eab6c7 refactor(node): migrate from better-sqlite3 to node:sqlite, require Node 24+
Some checks failed
CI (Node) / build-test (push) Failing after 8s
Native binding caused install pain on every new Node major (no prebuilts +
node-gyp needs VS+Windows SDK to fall back). For this project's workload
(a few ops/day, no advanced SQLite features) better-sqlite3's perf edge is
irrelevant — node:sqlite's bundled, ABI-stable sync API is the better fit.

- db.ts: DatabaseSync, db.exec("PRAGMA …"), explicit BEGIN/COMMIT helper to
  replace db.transaction(); row casts go through unknown because node:sqlite
  returns Record<string, SQLOutputValue>.
- package.json: drop better-sqlite3 + @types/better-sqlite3, bump
  engines.node to >=24, vitest 2 → 4 (2.x couldn't resolve `node:sqlite`).
- mailbox-doctor: add Step 1 that enforces Node ≥24 with a concrete fix
  message, renumbers downstream steps.

Node 1.2.0 → 1.3.0. 35 transitive packages removed from the lockfile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:07:21 +02:00
Mika Kuns
8747d638fb feat(plugin): add SubagentStop hook to auto-check inbox after subagent runs
Delivers peer messages that arrive during a long-running subagent into the
parent context the moment the Task tool returns, instead of waiting until
the next user prompt. Reuses the existing `claude-mailbox check --hook` so
the mailbox identity stays consistent with UserPromptSubmit.

Plugin 1.2.0 → 1.3.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:06:55 +02:00
Mika Kuns
d456f29138 fix(plugin): sync plugin.json version with releases
All checks were successful
Release / release (push) Successful in 8s
Release (Node) / release (push) Successful in 12s
plugin.json was stuck at 0.1.0 across every release, so Claude Code's
per-version plugin cache never refreshed and clients kept running the
original .mcp.json (http://127.0.0.1:47822/mcp). Bump to 1.2.0 to match
the node package and add a release-workflow step that derives plugin.json
from the tag on every future release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.2.1
2026-05-19 14:51:34 +02:00
Mika Kuns
d37d2419d6 feat(cli): pre-install port check in install-autostart
All checks were successful
CI (Node) / build-test (push) Successful in 9s
Release / release (push) Successful in 8s
Release (Node) / release (push) Successful in 12s
Before registering the Scheduled Task / Run-key / launchd / systemd unit,
probe /health on the resolved port. If a non-claude-mailbox service
answers, refuse with a helpful hint (`--port <n>` or mailbox.json) so
users don't end up with autostart firing against an occupied port.
Pass --skip-port-check to bypass.

The doctor already had this logic in Step 2; now standalone
install-autostart invocations are protected too.
v1.2.0
2026-05-19 14:09:21 +02:00
Mika Kuns
ee0b72f43b feat: change default port from 47822 to 37849 (v1.2.0)
All checks were successful
CI (Node) / build-test (push) Successful in 10s
CI (.NET) / build (push) Successful in 11s
47822 collided with ClaudeDo.Worker.exe on at least one user's machine.
37849 is high, registered to nobody, and avoids the prior conflict.
Both the Node port and the .NET port move together (still
wire-compatible). Defaults change only — if a user has a custom port
in mailbox.json, that stays.
2026-05-19 14:07:56 +02:00
Mika Kuns
d3abc762fd fix(ci): allow same-version npm version call (idempotent when source already bumped)
Some checks failed
Release / release (push) Failing after 6s
Release (Node) / release (push) Successful in 11s
v1.1.0
2026-05-19 13:55:11 +02:00
Mika Kuns
d0eb2af183 chore(node): release v1.1.0
Some checks failed
CI (Node) / build-test (push) Successful in 9s
Release / release (push) Successful in 6s
Release (Node) / release (push) Failing after 4s
2026-05-19 13:53:34 +02:00
Mika Kuns
42237149a1 feat: stdio MCP wrapper + Windows Run-key autostart fallback (v1.0.1)
Some checks failed
CI (Node) / build-test (push) Successful in 9s
Release (Node) / release (push) Failing after 1s
Release / release (push) Successful in 7s
Two production-readiness fixes so colleagues can install cleanly:

1. Plugin's MCP server now spawns `claude-mailbox mcp-stdio`, a small
   stdio MCP wrapper that proxies tool calls to the daemon's REST API.
   Claude Code does not support env-var substitution in HTTP MCP `url`
   fields (issue #46889), so the wrapper is the only way to make the
   daemon URL configurable per machine via CLAUDE_MAILBOX_URL.

2. Windows `install-autostart` now falls back from `schtasks /Create`
   to an HKCU\Software\Microsoft\Windows\CurrentVersion\Run entry
   when Group Policy blocks the Scheduled Task path. Both modes are
   per-user, no admin, persist across logoffs. The chosen mode is
   recorded in ~/.claude-mailbox/autostart-mode so status/start/stop/
   uninstall-autostart pick the right cleanup path.

Also bumps the npm version to 1.0.1 to align with the published 1.0.0
plus this patch.
v1.0.1
2026-05-19 13:43:55 +02:00
Mika Kuns
ac626f678b fix(cli,plugin): CLAUDE_MAILBOX_URL env override + port-conflict-aware doctor
All checks were successful
CI (Node) / build-test (push) Successful in 9s
The plugin's UserPromptSubmit and SessionStart hooks call `claude-mailbox`
with no --url flag, so they previously always hit the hardcoded
http://127.0.0.1:47822/mcp default. If port 47822 was held by another
local service (e.g. ClaudeDo), the daemon couldn't bind there and every
hook was talking to the wrong process.

CLI default for --url now resolves to $CLAUDE_MAILBOX_URL when set,
falling back to http://127.0.0.1:47822. Doctor gained a Step 2 that
probes /health on 47822, identifies foreign occupants, picks a free
port, writes both ~/.claude-mailbox/mailbox.json and the
CLAUDE_MAILBOX_URL entry in .claude/settings.json env so the hooks
follow along automatically.

Also adds a fallback hint when Windows schtasks /Create fails with
Access is denied (Group Policy restricts non-admin task creation): run
install-autostart from an elevated shell, or accept an ephemeral serve
for the current session.
2026-05-19 13:30:51 +02:00
Mika Kuns
73a49e405f docs(readme): use .git suffix on marketplace clone URL 2026-05-19 13:18:52 +02:00
Mika Kuns
43e8d0d4ca fix(ci): add pretest hook so vitest sees built dist/cli.js
All checks were successful
CI (Node) / build-test (push) Successful in 8s
Release / release (push) Successful in 8s
Release (Node) / release (push) Successful in 13s
v1.0.0
2026-05-19 13:12:59 +02:00
Mika Kuns
50f2b5a7cb docs(readme): restructure for getting-started flow
Some checks failed
CI (Node) / build-test (push) Failing after 5s
Release (Node) / release (push) Failing after 5s
Release / release (push) Successful in 7s
2026-05-19 12:56:27 +02:00
Mika Kuns
19d7a591df chore(node): release v0.1.0 2026-05-19 12:01:41 +02:00
Mika Kuns
48b6ba6452 feat(plugin): SessionStart hook discovers and announces active peers
session-announce now calls /v1/list with the session's X-Mailbox header,
which both registers the session with the daemon and returns all known
mailboxes in one round-trip. The output appends an "Active peers" block
listing mailboxes seen within the last hour (configurable via
--peer-window-minutes), capped at 10 entries by default. Self is
filtered out; the list is sorted most-recent-first.

So when the user says "I started a second session, coordinate with it",
Claude already has the peer's mailbox name in context — no manual
list_mailboxes call needed.

The peer-formatting logic is extracted into formatActivePeerList for
unit testing; CLI tests now pin --url to an unreachable port to keep
assertions stable on machines that have a real daemon running.
2026-05-19 11:59:31 +02:00
Mika Kuns
9fd321043f feat(mcp): identity-via-arg + plugin ships .mcp.json
MCP tools (send/check_inbox/peek_inbox/list_mailboxes) now accept the
caller's mailbox name as an explicit argument (from/name), falling back
to the X-Mailbox header for legacy single-session HTTP setups. This
unblocks multi-session coordination through a shared .mcp.json — each
Claude session passes its own session-derived name on every call,
instead of relying on a single transport header that all sessions
would share.

The plugin now ships .mcp.json (no header), and the SessionStart
announcement spells out the exact args to pass to each mcp__mailbox__*
tool so Claude wires it up automatically.
2026-05-19 11:50:58 +02:00
Mika Kuns
462d6561e1 feat(plugin): per-session mailbox identity + mailbox-update command
The hook now derives a unique mailbox name from the session_id supplied
on hook stdin, so two parallel Claude Code sessions in the same project
get distinct mailboxes (e.g. `claude-a8b3c1d2`, `claude-d4e5f6a7`)
instead of colliding on a shared env value. An optional
CLAUDE_MAILBOX_NAME base prefix flavors the names as `<base>-<sid>`.

Adds:
- `claude-mailbox session-announce` subcommand for the new SessionStart
  hook, which prints the current session's mailbox name to context
- `/claude-mailbox:mailbox-update` slash command for `npm update` +
  daemon restart
- stdin parsing helpers (parseHookStdin, deriveSessionName) with unit
  tests; the doctor no longer needs a mandatory name prompt
2026-05-19 11:39:14 +02:00
Mika Kuns
c231f8c18c feat(plugin): add /claude-mailbox:mailbox-doctor for one-command setup
The doctor command runs entirely inside Claude Code and walks through:
binary install via npm, daemon autostart, mailbox-name prompt with write
to per-project `.claude/settings.json` env, and a self → self smoke test.
Also adds `/claude-mailbox:mailbox-status` as a read-only health check.

Reduces the colleague onboarding to: add marketplace, install plugin,
run the doctor — no terminal context-switch required.
2026-05-19 10:55:05 +02:00
Mika Kuns
5c5843e62d feat(plugin): ship Claude Code plugin + marketplace manifest
Adds a /plugin marketplace at the repo root and a `claude-mailbox` plugin under
plugin/ that wires the UserPromptSubmit hook without needing the per-user
`install-hook` step. The hook command (`claude-mailbox check --hook`) now reads
the mailbox name from $CLAUDE_MAILBOX_NAME when --name is omitted and emits a
one-line setup hint when the daemon is unreachable, so a missing daemon is loud
instead of invisible.

The plugin only contains the Claude Code glue — the daemon binary is still a
separate prerequisite (`npm i -g @kuns/claude-mailbox` + install-autostart),
and the plugin/README plus main README spell out the three-step setup.
2026-05-19 10:49:36 +02:00
Mika Kuns
66967167bc feat(node): add Claude Code UserPromptSubmit hook for auto inbox-check
Adds `install-hook` / `uninstall-hook` subcommands that idempotently patch
~/.claude/settings.json (or .claude/settings.json with --project), plus a
`--hook` flag on `check` that emits human-readable output and stays silent
on empty inbox or unreachable daemon.
2026-05-19 10:09:30 +02:00
a5a2895725 fix(ci): use NPM_PUBLISH_TOKEN for Gitea npm registry auth
All checks were successful
Release / release (push) Successful in 7s
Release (Node) / release (push) Successful in 10s
The auto-generated secrets.GITEA_TOKEN lacks write:package scope,
causing npm publish to fail with E401. Use a dedicated repo secret
NPM_PUBLISH_TOKEN with a personal access token that has write:package.
v0.2.1
2026-04-30 12:20:51 +00:00
mika kuns
05d87d2aa7 feat(node): add TypeScript sibling project for npm-based install
Some checks failed
CI (Node) / build-test (push) Successful in 6s
CI (.NET) / build (push) Successful in 10s
Release / release (push) Successful in 8s
Release (Node) / release (push) Failing after 10s
Introduces @kuns/claude-mailbox under node/, a wire-compatible TypeScript
port of the .NET daemon that distributes via the public Gitea npm registry.
The .NET project stays in src/ClaudeMailbox/ untouched; users pick whichever
flavor they prefer.

- node/ project: fastify + @modelcontextprotocol/sdk StreamableHTTPServerTransport
  + better-sqlite3, schema and wire surface match the C# version (port 47822,
  X-Mailbox header, MCP tool names, snake_case SQLite columns)
- Cross-platform autostart: Scheduled Task (Win, no admin) / Windows Service
  (Win, --service) / launchd (mac) / systemd --user (linux)
- 9/9 vitest tests pass; end-to-end /health + send/check round-trip verified
- CI split: existing ci.yml/release.yml renamed to *-dotnet.yml with path
  filters, new ci-node.yml and release-node.yml publish to Gitea npm registry
- install.ps1 / install.sh bootstrap one-liners at repo root; homebrew/
  contains a tap formula template
- README install section reordered: npm path primary, dotnet publish secondary

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.2.0
2026-04-30 14:06:46 +02:00
mika kuns
757a095c10 fix(ci): use full GitHub URL for actions/checkout
All checks were successful
CI / build (push) Successful in 12s
Release / release (push) Successful in 7s
Gitea Actions resolves bare action names against the local Gitea
instance by default. Using the full github.com URL makes the runner
pull the action from upstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.1.0
2026-04-24 19:50:22 +02:00
mika kuns
83afd0ddb3 refactor(ci): use actions/checkout for public repo release flow
Some checks failed
CI / build (push) Failing after 0s
Drops the manual mktemp + git-clone-with-token dance (not needed for a
public repo) in favor of actions/checkout@v4. GITEA_TOKEN is still
required for the release-creation and asset-upload API calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 19:46:11 +02:00
mika kuns
8cdc7bac16 fix(ci): build test csproj instead of .slnx for .NET 8 runner
.slnx requires .NET 9 SDK / MSBuild 17.8+. The Gitea runner has only
.NET 8, so build the test project directly — its ProjectReference
transitively builds ClaudeMailbox.csproj.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 19:43:12 +02:00
mika kuns
e3b51122ae fix(service): explain 1073 (service exists) on install-service 2026-04-24 19:40:38 +02:00
mika kuns
e7407b1b3a docs(readme): document install-service verbs and config precedence 2026-04-24 19:36:54 +02:00
mika kuns
c3e5bc2ba2 ci: add tag-triggered Gitea release workflow 2026-04-24 19:35:48 +02:00
mika kuns
202bb692e0 ci: add build+test workflow for main and PRs 2026-04-24 19:34:41 +02:00
mika kuns
dbc6844db6 feat(service): dispatch service verbs from Program entrypoint 2026-04-24 19:33:32 +02:00
mika kuns
ebc0319384 feat(service): implement uninstall-service and status verbs 2026-04-24 19:29:08 +02:00
mika kuns
452dc8514b fix(service): escape bind value and parse port as int in seeded config 2026-04-24 19:27:34 +02:00
mika kuns
f91d3644fb feat(service): implement install-service verb 2026-04-24 19:22:45 +02:00
mika kuns
5c6f4b8b6e feat(service): add ServiceCommands skeleton with platform/admin gates 2026-04-24 19:18:18 +02:00
mika kuns
d8f25dc01b feat(service): enable Windows Service hosting lifetime 2026-04-24 19:14:39 +02:00
mika kuns
870431d0b8 feat(config): load mailbox.json with CLI override in Program 2026-04-24 19:10:54 +02:00
mika kuns
81906e7274 feat(config): add ConfigResolver with CLI>file>default precedence
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 19:06:25 +02:00
mika kuns
f397008ff5 feat(config): add FileConfig model and JSON loader 2026-04-24 19:01:36 +02:00
mika kuns
948c6d4abe docs(plan): implementation plan for gitea release and windows service
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 18:57:56 +02:00
mika kuns
0586d67a41 docs(spec): gitea release flow and windows service support
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 18:53:13 +02:00
mika kuns
ec42e8e4bd Initial 2026-04-24 18:26:11 +02:00