From 7f7677bbedf4424c914d4b322b8d3b32c8463d9b Mon Sep 17 00:00:00 2001 From: claude Date: Wed, 22 Apr 2026 21:20:40 +0200 Subject: [PATCH 1/3] fix(ci): use GitHub Packages registry instead of npmjs.org MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - registry-url → npm.pkg.github.com - NODE_AUTH_TOKEN → GITHUB_TOKEN - Add packages: write permission Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/dev-publish.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dev-publish.yml b/.github/workflows/dev-publish.yml index 8aac999..a5a1b78 100644 --- a/.github/workflows/dev-publish.yml +++ b/.github/workflows/dev-publish.yml @@ -10,6 +10,7 @@ on: permissions: contents: read + packages: write concurrency: group: dev-publish-${{ github.ref }} @@ -27,7 +28,7 @@ jobs: - uses: actions/setup-node@v5 with: node-version: 22 - registry-url: https://registry.npmjs.org + registry-url: https://npm.pkg.github.com scope: '@focusmcp' - name: Compute dev version id: version @@ -46,4 +47,4 @@ jobs: - name: Publish with dev tag run: npm publish --tag dev --access public env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From d4a26d13dd100556d66e02f5cdd120f937915612 Mon Sep 17 00:00:00 2001 From: claude Date: Wed, 22 Apr 2026 21:29:10 +0200 Subject: [PATCH 2/3] fix: rename scope to @focus-mcp + npmjs.org for dev publish - All refs: @focus-mcp/{cli,core} - dev-publish.yml: registry.npmjs.org + NPM_TOKEN - Update deps, docs, workflows, imports Co-Authored-By: Claude Opus 4.6 (1M context) --- .changeset/README.md | 4 +-- .github/actions/setup/action.yml | 14 +++++----- .github/workflows/dev-publish.yml | 8 +++--- .github/workflows/publish-dev.yml | 8 +++--- AGENTS.md | 12 ++++---- CLAUDE.md | 32 +++++++++++----------- CONTRIBUTING.md | 2 +- PRD.md | 32 +++++++++++----------- README.md | 14 +++++----- SECURITY.md | 8 +++--- package.json | 4 +-- pnpm-lock.yaml | 6 ++-- src/adapters/catalog-store-adapter.ts | 4 +-- src/adapters/http-fetch-adapter.ts | 2 +- src/adapters/npm-installer-adapter.test.ts | 26 +++++++++--------- src/adapters/npm-installer-adapter.ts | 2 +- src/bin/focus.ts | 2 +- src/center.ts | 2 +- src/commands/add.test.ts | 12 ++++---- src/commands/add.ts | 2 +- src/commands/catalog.test.ts | 4 +-- src/commands/catalog.ts | 2 +- src/commands/remove.test.ts | 4 +-- src/commands/remove.ts | 2 +- src/commands/search.test.ts | 2 +- src/commands/search.ts | 2 +- src/commands/start.test.ts | 4 +-- src/commands/start.ts | 6 ++-- src/source/filesystem-source.ts | 2 +- tsup.config.ts | 6 ++-- 30 files changed, 115 insertions(+), 115 deletions(-) diff --git a/.changeset/README.md b/.changeset/README.md index 8baceff..51c7abd 100644 --- a/.changeset/README.md +++ b/.changeset/README.md @@ -7,8 +7,8 @@ SPDX-License-Identifier: MIT This folder holds the FocusMCP CLI changesets. Every PR that changes user-facing behaviour must add a changeset via `pnpm changeset`. -- Mode: **single package** — `@focusmcp/cli` is published as one npm package. -- `access: public` — published to the public npm registry on the `@focusmcp/` scope. +- Mode: **single package** — `@focus-mcp/cli` is published as one npm package. +- `access: public` — published to the public npm registry on the `@focus-mcp/` scope. - `baseBranch: develop` — changesets are opened against `develop` and promoted to `main` at release time. Format: Markdown with frontmatter listing the package + bump level (patch / minor / major). diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 157a287..730c038 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -3,9 +3,9 @@ name: Setup toolchain description: | - Clone @focusmcp/core as a sibling directory (../core), install and build it, + Clone @focus-mcp/core as a sibling directory (../core), install and build it, then set up pnpm + Node and install this repo's dependencies. - The CLI depends on `@focusmcp/core` via a `file:../core/packages/core` path, + The CLI depends on `@focus-mcp/core` via a `file:../core/packages/core` path, so the sibling must exist and have a built `dist/` before `pnpm install`. inputs: @@ -17,7 +17,7 @@ inputs: runs: using: composite steps: - - name: Checkout @focusmcp/core (inside workspace — actions/checkout restriction) + - name: Checkout @focus-mcp/core (inside workspace — actions/checkout restriction) uses: actions/checkout@v4 with: repository: focus-mcp/core @@ -26,7 +26,7 @@ runs: fetch-depth: 1 # actions/checkout refuses paths outside the workspace; move it to the real sibling now. - - name: Move @focusmcp/core to sibling location + - name: Move @focus-mcp/core to sibling location shell: bash run: | mv "$GITHUB_WORKSPACE/.core-sibling" "$GITHUB_WORKSPACE/../core" @@ -41,15 +41,15 @@ runs: cache: pnpm registry-url: 'https://registry.npmjs.org' - - name: Install @focusmcp/core dependencies + - name: Install @focus-mcp/core dependencies shell: bash working-directory: ../core run: pnpm install --frozen-lockfile - - name: Build @focusmcp/core + - name: Build @focus-mcp/core shell: bash working-directory: ../core - run: pnpm --filter "@focusmcp/core" build + run: pnpm --filter "@focus-mcp/core" build - name: Install CLI dependencies shell: bash diff --git a/.github/workflows/dev-publish.yml b/.github/workflows/dev-publish.yml index a5a1b78..f12975d 100644 --- a/.github/workflows/dev-publish.yml +++ b/.github/workflows/dev-publish.yml @@ -18,7 +18,7 @@ concurrency: jobs: publish-dev: - name: Publish @focusmcp/cli@dev + name: Publish @focus-mcp/cli@dev runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -28,8 +28,8 @@ jobs: - uses: actions/setup-node@v5 with: node-version: 22 - registry-url: https://npm.pkg.github.com - scope: '@focusmcp' + registry-url: https://registry.npmjs.org + scope: '@focus-mcp' - name: Compute dev version id: version run: | @@ -47,4 +47,4 @@ jobs: - name: Publish with dev tag run: npm publish --tag dev --access public env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish-dev.yml b/.github/workflows/publish-dev.yml index 9700d32..3f65fc3 100644 --- a/.github/workflows/publish-dev.yml +++ b/.github/workflows/publish-dev.yml @@ -15,7 +15,7 @@ permissions: jobs: publish: - name: Publish @focusmcp/cli to GitHub Packages + name: Publish @focus-mcp/cli to npmjs.org runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -24,9 +24,9 @@ jobs: with: node-version: 22 cache: pnpm - registry-url: https://npm.pkg.github.com - scope: '@focusmcp' + registry-url: https://registry.npmjs.org + scope: '@focus-mcp' - run: pnpm build - run: npm publish --access public 2>&1 || echo "→ skipped (already published or error)" env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index 210fd03..f08c83a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,7 +17,7 @@ Read [PRD.md](./PRD.md) for the complete CLI vision (commands, transport, distri - **Node.js ≥ 22** (LTS), **pnpm ≥ 10**, **TypeScript 5.7+** strict - **ESM only** (`"type": "module"`) -- **Single package** — `@focusmcp/cli` published to npm under the `@focusmcp` scope +- **Single package** — `@focus-mcp/cli` published to npm under the `@focusmcp` scope - Tests: **Vitest** - Lint/format: **Biome 2.x** - Build: **tsup** (ESM, Node 22 target, dts for the programmatic entry only) @@ -38,14 +38,14 @@ Source code lives in `src/`: 1. **Strict TDD** — write the test BEFORE the code (Red → Green → Refactor). Coverage ≥ 80 % global. 2. **No `any`**, no untyped catch, no `!` non-null assertions. -3. **No `console.log` outside `src/bin/` and `src/commands/`.** The Biome override allows console in those two folders (they are the CLI surface); everywhere else, use structured logging via `@focusmcp/core`. +3. **No `console.log` outside `src/bin/` and `src/commands/`.** The Biome override allows console in those two folders (they are the CLI surface); everywhere else, use structured logging via `@focus-mcp/core`. 4. **SPDX header** in every source file: `SPDX-FileCopyrightText: 2026 FocusMCP contributors` + `SPDX-License-Identifier: MIT`. For JSON files (no comment support), create a sibling `.license` file (REUSE convention). 5. **Imports**: `node:` protocol (`import { parseArgs } from 'node:util'`). 6. **Commits**: [Conventional Commits](https://www.conventionalcommits.org/) — allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. 7. **No unsolicited features** — stick strictly to the requested scope. 8. **stdio MCP is the canonical transport.** An HTTP admin API is Phase 2, gated behind an explicit flag; it is not the way AI clients attach. -9. **`@focusmcp/core` is a git dependency** (`github:focus-mcp/core`). Do not try to publish `@focusmcp/core` to npm from this repo. +9. **`@focus-mcp/core` is a git dependency** (`github:focus-mcp/core`). Do not try to publish `@focus-mcp/core` to npm from this repo. 10. **Pure command functions.** Every `src/commands/.ts` exports a function that takes already-parsed state (or structured input) and returns the string to print — no I/O, no `process.exit`. The binary in `src/bin/focus.ts` is the only layer allowed to touch `process.*`, stdin/stdout, and the filesystem. ## Commands @@ -68,9 +68,9 @@ pnpm changeset # create a changeset before merging AI client (Claude Code, Cursor, …) │ stdio (JSON-RPC / MCP) ▼ -@focusmcp/cli (focus start) +@focus-mcp/cli (focus start) ├─ @modelcontextprotocol/sdk StdioServerTransport - ├─ @focusmcp/core (createFocusMcp) + ├─ @focus-mcp/core (createFocusMcp) │ Registry + EventBus + Router + bricks └─ ~/.focus/center.json + ~/.focus/center.lock ``` @@ -87,7 +87,7 @@ AI client (Claude Code, Cursor, …) - **No secrets** in the code (gitleaks blocks in pre-commit and CI). - **No `eval`**, no `new Function()`. -- Every external input (center.json, center.lock) is validated structurally before reaching `@focusmcp/core`. +- Every external input (center.json, center.lock) is validated structurally before reaching `@focus-mcp/core`. ## Git remote diff --git a/CLAUDE.md b/CLAUDE.md index 4d6e896..5be8a4e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,7 +3,7 @@ SPDX-FileCopyrightText: 2026 FocusMCP contributors SPDX-License-Identifier: MIT --> -# CLAUDE.md — @focusmcp/cli +# CLAUDE.md — @focus-mcp/cli > Auto-loaded by Claude Code (and any agents.md-compatible tool) when working in this repo. > This file is the **source of truth for AI agent behaviour** on this project. It replaces the @@ -14,8 +14,8 @@ SPDX-License-Identifier: MIT **FocusMCP** — orchestrateur MCP. Reduces AI-agent context from 200k to ~2k tokens by composing **briques** (atomic MCP modules). Site [focusmcp.dev](https://focusmcp.dev). -Ce repo est **le point d'entrée primaire** : `@focusmcp/cli`, une CLI Node publiée sur npm, -qui embarque `@focusmcp/core` et parle **stdio MCP** (via `@modelcontextprotocol/sdk`) aux +Ce repo est **le point d'entrée primaire** : `@focus-mcp/cli`, une CLI Node publiée sur npm, +qui embarque `@focus-mcp/core` et parle **stdio MCP** (via `@modelcontextprotocol/sdk`) aux clients AI (Claude Code, Cursor, Codex, Gemini CLI…). ## Écosystème (3 repos actifs + 1 archivé) @@ -23,7 +23,7 @@ clients AI (Claude Code, Cursor, Codex, Gemini CLI…). | Repo | Rôle | |---|---| | `focus-mcp/core` | Monorepo lib TS — 3 piliers (Registry/EventBus/Router) + SDK/Validator/Marketplace resolver. Importé par ce repo via `file:../core/packages/core`. | -| `focus-mcp/cli` (ici) | `@focusmcp/cli` — stdio MCP, brick manager (`focus list/info/add/remove/...`). Publié npm. | +| `focus-mcp/cli` (ici) | `@focus-mcp/cli` — stdio MCP, brick manager (`focus list/info/add/remove/...`). Publié npm. | | `focus-mcp/marketplace` | Catalogue officiel + `bricks/*` + `modules/*` (dont `manager` = dashboard optionnel). | | `focus-mcp/client` | **archivé** — ex desktop Tauri, gelé post-pivot CLI-first. | @@ -33,13 +33,13 @@ clients AI (Claude Code, Cursor, Codex, Gemini CLI…). AI client (Claude Code, Cursor, Codex, Gemini…) │ stdio (JSON-RPC MCP) ▼ -@focusmcp/cli (ce repo) +@focus-mcp/cli (ce repo) ├─ @modelcontextprotocol/sdk StdioServerTransport - ├─ @focusmcp/core (Registry + EventBus + Router + bricks loader) + ├─ @focus-mcp/core (Registry + EventBus + Router + bricks loader) └─ (opt-in P1) admin API HTTP côté latéral (consommé par marketplace/modules/manager) ``` -**Distribution** : `npm install -g @focusmcp/cli` ou `npx @focusmcp/cli start`. +**Distribution** : `npm install -g @focus-mcp/cli` ou `npx @focus-mcp/cli start`. **Claude Code plugin** natif via `.claude-plugin/plugin.json` : ```json @@ -47,7 +47,7 @@ AI client (Claude Code, Cursor, Codex, Gemini…) "mcpServers": { "focus": { "command": "npx", - "args": ["@focusmcp/cli", "start"] + "args": ["@focus-mcp/cli", "start"] } } } @@ -67,8 +67,8 @@ AI client (Claude Code, Cursor, Codex, Gemini…) `PRD.md` et `CLAUDE.md` (ce fichier) restent en français (docs internes). 6. **Git-flow strict** — `develop` est **permanente**, jamais `--delete-branch` sur PR `develop→main`. -7. **npm orgs** — `focusmcp` + `focus-mcp` réservées (squatting). `@focusmcp/cli` est LE package - publié au MVP (primary distribution). Scope canonique : `@focusmcp/*`. +7. **npm orgs** — `focusmcp` + `focus-mcp` réservées (squatting). `@focus-mcp/cli` est LE package + publié au MVP (primary distribution). Scope canonique : `@focus-mcp/*`. 8. **Rulesets GitHub** (identiques sur les 3 repos actifs) : - `main protection` cible **UNIQUEMENT `refs/heads/main`** (status checks, PR, CodeQL, Code Quality, linear history, pas de `required_signatures`). @@ -80,16 +80,16 @@ AI client (Claude Code, Cursor, Codex, Gemini…) ## Dans ce repo (cli) **Stack** : Node ≥ 22, pnpm ≥ 10, TS 5.7+ strict, ESM, Vitest, Biome 2.x, tsup, Changesets, -`@modelcontextprotocol/sdk` (stdio transport), `@focusmcp/core` en file: dep. +`@modelcontextprotocol/sdk` (stdio transport), `@focus-mcp/core` en file: dep. -**Dépendance critique** : `@focusmcp/core` est consommé via `file:../core/packages/core`. Cela +**Dépendance critique** : `@focus-mcp/core` est consommé via `file:../core/packages/core`. Cela implique : - **Dev local** : le user doit avoir `focus-mcp/core` cloné comme repo sibling de ce repo (layout attendu : `../core`, avec le package à `../core/packages/core`). Indépendant de l'OS. - **CI** : action composite `.github/actions/setup` qui clone `focus-mcp/core` comme sibling, le build (pnpm filter), puis install ce repo. -- **Publish npm** : `tsup --noExternal '@focusmcp/core'` bundle le core dans le dist de la CLI, - donc les users finaux installent uniquement `@focusmcp/cli`. +- **Publish npm** : `tsup --noExternal '@focus-mcp/core'` bundle le core dans le dist de la CLI, + donc les users finaux installent uniquement `@focus-mcp/cli`. **Commandes** : ```bash @@ -120,7 +120,7 @@ pnpm changeset # avant toute PR qui change l'API publique focus add ├─ http-fetch-adapter → catalog.json (URL source) ├─ catalog-store-adapter → cache local + résolution brique - └─ npm-installer-adapter → npm install @focusmcp/ + └─ npm-installer-adapter → npm install @focus-mcp/ ``` ## Workflow pour une feature @@ -137,7 +137,7 @@ focus add - Aucun secret commité (gitleaks en CI) - Le sandbox OS vient du parent process (Claude Code spawn en stdio via Seatbelt/bubblewrap) -- EventBus guards (couche 1 sécurité) intactes, fournies par `@focusmcp/core` +- EventBus guards (couche 1 sécurité) intactes, fournies par `@focus-mcp/core` - Pour run des briques non-reviewed : ajouter `isolated-vm` Phase 2 (pas au MVP) ## Documentation à lire en priorité diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2d0b1d3..360378b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,7 +36,7 @@ pnpm reuse # REUSE compliance (SPDX headers) 1. **Strict TDD** — tests first. Coverage ≥ 80 % global (the `vitest` config enforces this). 2. **No `any`**, no `!` non-null assertion, no untyped `catch`. -3. **No `console.*` outside `src/bin/` and `src/commands/`.** Use structured logging from `@focusmcp/core` everywhere else. +3. **No `console.*` outside `src/bin/` and `src/commands/`.** Use structured logging from `@focus-mcp/core` everywhere else. 4. **ESM only**, `node:` protocol for Node built-ins. 5. **SPDX headers** in every source file (`SPDX-FileCopyrightText: 2026 FocusMCP contributors` + `SPDX-License-Identifier: MIT`). For JSON files, add a sibling `.license` file (REUSE convention). 6. **Conventional Commits** — enforced by commitlint (`feat(list): ...`, `fix(info): ...`, `docs(readme): ...`). Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. diff --git a/PRD.md b/PRD.md index 31f4f7f..4514c3a 100644 --- a/PRD.md +++ b/PRD.md @@ -5,8 +5,8 @@ SPDX-License-Identifier: MIT # FocusMCP CLI — Product Requirements Document -> Périmètre : le **CLI officiel `@focusmcp/cli`** (repo `cli/`). -> Pour la lib `@focusmcp/core` : voir [`core/PRD.md`](../core/PRD.md). Pour le catalogue : voir [`marketplace/PRD.md`](../marketplace/PRD.md). Le client Tauri (repo `client/`) est **gelé** — pas de UI bundlée au MVP. +> Périmètre : le **CLI officiel `@focus-mcp/cli`** (repo `cli/`). +> Pour la lib `@focus-mcp/core` : voir [`core/PRD.md`](../core/PRD.md). Pour le catalogue : voir [`marketplace/PRD.md`](../marketplace/PRD.md). Le client Tauri (repo `client/`) est **gelé** — pas de UI bundlée au MVP. ## Vision (rappel) @@ -22,12 +22,12 @@ Le CLI est **le point d'entrée principal** de FocusMCP. Pivot CLI-first : tout Le repo `cli/` contient : -1. **Le binaire `focus`** — publié sous `@focusmcp/cli` sur npm, consommé via `npx` ou `npm install -g`. -2. **Le transport stdio MCP** — `focus start` démarre un `StdioServerTransport` du SDK officiel MCP, routé vers le `createFocusMcp()` de `@focusmcp/core`. +1. **Le binaire `focus`** — publié sous `@focus-mcp/cli` sur npm, consommé via `npx` ou `npm install -g`. +2. **Le transport stdio MCP** — `focus start` démarre un `StdioServerTransport` du SDK officiel MCP, routé vers le `createFocusMcp()` de `@focus-mcp/core`. 3. **Le brick manager local** — `focus list`, `focus info`, `focus add`, `focus remove`, `focus update` opèrent sur `~/.focus/center.json` + `~/.focus/center.lock`. 4. **Le client marketplace** — résolution des briques depuis le catalogue officiel (et les catalogues tiers en P2). -Le CLI **embarque `@focusmcp/core`**, il n'y a **pas** d'HTTP par défaut, et **pas** de UI bundlée (un `cli-manager` séparé existera en Phase 2 pour administrer le CLI à distance). +Le CLI **embarque `@focus-mcp/core`**, il n'y a **pas** d'HTTP par défaut, et **pas** de UI bundlée (un `cli-manager` séparé existera en Phase 2 pour administrer le CLI à distance). --- @@ -37,9 +37,9 @@ Le CLI **embarque `@focusmcp/core`**, il n'y a **pas** d'HTTP par défaut, et ** AI client (Claude Code, Cursor, etc.) │ stdio (JSON-RPC) ▼ -@focusmcp/cli +@focus-mcp/cli ├─ @modelcontextprotocol/sdk StdioServerTransport - ├─ @focusmcp/core (createFocusMcp) + ├─ @focus-mcp/core (createFocusMcp) │ Registry + EventBus + Router + bricks └─ center.json + center.lock (~/.focus/) ``` @@ -75,7 +75,7 @@ AI client (Claude Code, Cursor, etc.) } ``` -Les deux fichiers sont parsés par `src/center.ts` — validation structurelle uniquement ; la sémantique (semver, catalog URL, signature) est gérée par `@focusmcp/core`. +Les deux fichiers sont parsés par `src/center.ts` — validation structurelle uniquement ; la sémantique (semver, catalog URL, signature) est gérée par `@focus-mcp/core`. --- @@ -107,10 +107,10 @@ Toutes les sous-commandes métier sont des **fonctions pures** (input structuré ## Distribution -- **Package npm** : `@focusmcp/cli` sous le scope `@focusmcp` (org npm réservée). +- **Package npm** : `@focus-mcp/cli` sous le scope `@focusmcp` (org npm réservée). - **Installation** : - - `npx @focusmcp/cli start` — one-shot, idéal pour Claude Code. - - `npm install -g @focusmcp/cli` — installation globale, `focus` dans le `$PATH`. + - `npx @focus-mcp/cli start` — one-shot, idéal pour Claude Code. + - `npm install -g @focus-mcp/cli` — installation globale, `focus` dans le `$PATH`. - **Publish** : via Changesets (single package mode) + `release.yml` sur push `main`. Secret `NPM_TOKEN` requis. - **Provenance npm** activée (`publishConfig.provenance: true`) pour signer les tarballs via Sigstore. @@ -120,7 +120,7 @@ Toutes les sous-commandes métier sont des **fonctions pures** (input structuré Trois couches de défense, empilées : -1. **EventBus guards** (hérités de `@focusmcp/core`) — une brique ne peut émettre ni consommer que des événements déclarés dans son manifeste. Mismatch → fail fast au boot. +1. **EventBus guards** (hérités de `@focus-mcp/core`) — une brique ne peut émettre ni consommer que des événements déclarés dans son manifeste. Mismatch → fail fast au boot. 2. **Permissions utilisateur via `center.json`** — une brique désactivée (`enabled: false`) ne boote pas. `config` par brique est validé contre le manifeste avant forwarding. 3. **Sandbox du process parent** — Claude Code et Cursor sandboxent déjà les serveurs MCP stdio (FS restreint, réseau filtré). Le CLI **ne cherche pas** à s'en échapper. @@ -135,7 +135,7 @@ Parsers `center.json` / `center.lock` : validation structurelle stricte, rejet f - [x] Scaffolding repo (structure, CI, REUSE, biome, changesets) - [x] `focus list` + `focus info` + parsers `center.*` - [ ] `focus start` — transport stdio MCP fonctionnel (raccorde `createFocusMcp` + `StdioServerTransport`) -- [ ] Publication `@focusmcp/cli@0.1.0` sur npm +- [ ] Publication `@focus-mcp/cli@0.1.0` sur npm - [ ] README + docs d'install pour Claude Code ### P1 @@ -162,7 +162,7 @@ Parsers `center.json` / `center.lock` : validation structurelle stricte, rejet f | Build | **tsup** | Bundling (ESM, Node 22, dts pour l'API programmatique) | | Tests | **Vitest** | Unit (≥ 80 % coverage) | | Transport MCP | **@modelcontextprotocol/sdk** | `StdioServerTransport` officiel | -| Lib FocusMCP | **@focusmcp/core** (git dep) | Registry + EventBus + Router | +| Lib FocusMCP | **@focus-mcp/core** (git dep) | Registry + EventBus + Router | | Parsing CLI | **node:util `parseArgs`** | Dispatch sous-commandes (pas de dep externe) | | Lint | **Biome 2.x** | Style + qualité | | License | **REUSE** | SPDX headers | @@ -179,8 +179,8 @@ Parsers `center.json` / `center.lock` : validation structurelle stricte, rejet f | **Transport primaire** | stdio MCP | Standard MCP ; Claude Code/Cursor spawnent des sous-processus stdio, pas des serveurs HTTP | | **HTTP** | Phase 2, derrière un flag | Gardé pour `cli-manager`, pas exposé par défaut pour limiter la surface | | **UI** | Pas bundlée | Séparation CLI ↔ UI ; `cli-manager` sera un repo dédié en P2 | -| **`@focusmcp/core`** | Git dependency | Core n'est pas publié sur npm au MVP — git dep évite un release coupling prématuré | -| **Changesets** | Single-package mode | `@focusmcp/cli` est un package unique ; `independent` n'a pas de sens ici | +| **`@focus-mcp/core`** | Git dependency | Core n'est pas publié sur npm au MVP — git dep évite un release coupling prématuré | +| **Changesets** | Single-package mode | `@focus-mcp/cli` est un package unique ; `independent` n'a pas de sens ici | | **npm org** | `@focusmcp` | Scope officiel réservé ; distribution via npm, pas GitHub Releases (contrairement aux briques) | | **CLI parsing** | `node:util` `parseArgs` | Pas de dépendance externe (commander, yargs) — API Node stable suffit | | **Coverage gate** | 80 % | Aligné sur marketplace/core ; `src/bin/` et `src/index.ts` sont exclus (surface fine, testée e2e) | diff --git a/README.md b/README.md index ed2ae54..371f126 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ SPDX-License-Identifier: MIT > > [focusmcp.dev](https://focusmcp.dev) · [PRD](./PRD.md) · [Core](https://github.com/focus-mcp/core) · [Marketplace](https://github.com/focus-mcp/marketplace) -`@focusmcp/cli` is the fourth pillar of FocusMCP (after `core`, `client` and `marketplace`). It is the **primary, canonical entry point** of FocusMCP — the same binary is invoked by AI clients (Claude Code, Cursor, etc.) to bring FocusMCP's bricks into any MCP-compatible agent. +`@focus-mcp/cli` is the fourth pillar of FocusMCP (after `core`, `client` and `marketplace`). It is the **primary, canonical entry point** of FocusMCP — the same binary is invoked by AI clients (Claude Code, Cursor, etc.) to bring FocusMCP's bricks into any MCP-compatible agent. ## Status @@ -19,10 +19,10 @@ Active development — pre-MVP. `focus list` and `focus info` are functional; `f ```bash # One-shot -npx @focusmcp/cli start +npx @focus-mcp/cli start # Or install globally -npm install -g @focusmcp/cli +npm install -g @focus-mcp/cli focus --version ``` @@ -46,7 +46,7 @@ Add FocusMCP as an MCP server in your Claude Code config: "mcpServers": { "focusmcp": { "command": "npx", - "args": ["-y", "@focusmcp/cli", "start"] + "args": ["-y", "@focus-mcp/cli", "start"] } } } @@ -83,11 +83,11 @@ pnpm changeset # create a changeset before merging ## Versioning & publishing -`@focusmcp/cli` is a single npm package versioned via Changesets. `develop` is the base branch; merging a "Version Packages" PR on `main` triggers `release.yml`, which publishes to npm and creates a GitHub Release (requires the `NPM_TOKEN` repo secret). +`@focus-mcp/cli` is a single npm package versioned via Changesets. `develop` is the base branch; merging a "Version Packages" PR on `main` triggers `release.yml`, which publishes to npm and creates a GitHub Release (requires the `NPM_TOKEN` repo secret). -## Dependency on `@focusmcp/core` +## Dependency on `@focus-mcp/core` -`@focusmcp/core` is referenced as a **git dependency** (`github:focus-mcp/core`) because the monorepo that hosts it does not publish to npm at MVP. Local dev can swap the dep for a workspace link (`pnpm link ../core/packages/core`) — the CLI only uses the public API of `createFocusMcp`. +`@focus-mcp/core` is referenced as a **git dependency** (`github:focus-mcp/core`) because the monorepo that hosts it does not publish to npm at MVP. Local dev can swap the dep for a workspace link (`pnpm link ../core/packages/core`) — the CLI only uses the public API of `createFocusMcp`. ## License diff --git a/SECURITY.md b/SECURITY.md index 19ab23f..1c7b503 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT ## Supported versions -`@focusmcp/cli` is pre-MVP (`0.x`). No version is yet considered stable — we reserve the right to ship breaking changes in `0.y` releases. +`@focus-mcp/cli` is pre-MVP (`0.x`). No version is yet considered stable — we reserve the right to ship breaking changes in `0.y` releases. ## Reporting a vulnerability @@ -20,7 +20,7 @@ Send a private report via: Please include if possible: -- Affected version of `@focusmcp/cli` +- Affected version of `@focus-mcp/cli` - Description of the issue - Reproduction steps - Estimated impact @@ -39,7 +39,7 @@ We commit to: The CLI is typically **spawned as a subprocess** of an AI client (Claude Code, Cursor, etc.) and inherits the parent's sandbox. FocusMCP adds three layers on top of the host sandbox: -1. **EventBus guards** (in `@focusmcp/core`) — a brick can only emit / consume events it has declared in its manifest. Mismatches fail fast. +1. **EventBus guards** (in `@focus-mcp/core`) — a brick can only emit / consume events it has declared in its manifest. Mismatches fail fast. 2. **User permissions via `center.json`** — bricks are opt-in. A disabled brick never boots. Per-brick `config` is validated against the brick manifest before being forwarded. 3. **Parent-process sandbox** — Claude Code / Cursor already sandbox stdio MCP servers (limited filesystem + network). The CLI does not try to break out of that sandbox. @@ -49,7 +49,7 @@ Our security priorities: 1. **The `focus start` transport** — the stdio JSON-RPC handshake, request validation, and error shape. 2. **`center.json` / `center.lock` parsers** — untrusted JSON from disk; structural validation is our first line of defence. -3. **Brick resolution** — integrity (SRI hash) and source provenance before a brick is loaded by `@focusmcp/core`. +3. **Brick resolution** — integrity (SRI hash) and source provenance before a brick is loaded by `@focus-mcp/core`. 4. **The CI pipeline** — secret scanning, least-privilege workflow permissions, pinned actions. ## Project security practices diff --git a/package.json b/package.json index 63154bd..891b4cf 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@focusmcp/cli", + "name": "@focus-mcp/cli", "version": "0.0.0", "private": false, "description": "FocusMCP CLI — the primary entry point of FocusMCP. Spawns MCP over stdio and manages bricks (list, info, start, add, remove, update).", @@ -64,7 +64,7 @@ "devDependencies": { "@biomejs/biome": "^2.2.0", "@changesets/cli": "^2.27.0", - "@focusmcp/core": "file:../core/packages/core", + "@focus-mcp/core": "file:../core/packages/core", "@commitlint/cli": "^19.6.0", "@commitlint/config-conventional": "^19.6.0", "@commitlint/types": "^19.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c209b34..ab89c71 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,7 +27,7 @@ importers: '@commitlint/types': specifier: ^19.8.1 version: 19.8.1 - '@focusmcp/core': + '@focus-mcp/core': specifier: file:../core/packages/core version: file:../core/packages/core '@types/node': @@ -424,7 +424,7 @@ packages: cpu: [x64] os: [win32] - '@focusmcp/core@file:../core/packages/core': + '@focus-mcp/core@file:../core/packages/core': resolution: {directory: ../core/packages/core, type: directory} '@hono/node-server@1.19.14': @@ -2534,7 +2534,7 @@ snapshots: '@esbuild/win32-x64@0.27.7': optional: true - '@focusmcp/core@file:../core/packages/core': + '@focus-mcp/core@file:../core/packages/core': dependencies: '@opentelemetry/api': 1.9.1 diff --git a/src/adapters/catalog-store-adapter.ts b/src/adapters/catalog-store-adapter.ts index ad9db90..f0ee0e6 100644 --- a/src/adapters/catalog-store-adapter.ts +++ b/src/adapters/catalog-store-adapter.ts @@ -5,14 +5,14 @@ * Filesystem implementation of CatalogStoreIO. * * Reads and writes the catalog source registry at ~/.focus/catalogs.json. - * Conforms to the CatalogStoreIO interface expected by @focusmcp/core + * Conforms to the CatalogStoreIO interface expected by @focus-mcp/core * marketplace/catalog-store pure functions. */ import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { homedir } from 'node:os'; import { join } from 'node:path'; -import type { CatalogStoreData, CatalogStoreIO } from '@focusmcp/core'; +import type { CatalogStoreData, CatalogStoreIO } from '@focus-mcp/core'; export type { CatalogStoreData, CatalogStoreIO }; diff --git a/src/adapters/http-fetch-adapter.ts b/src/adapters/http-fetch-adapter.ts index 0dd2655..e04fb84 100644 --- a/src/adapters/http-fetch-adapter.ts +++ b/src/adapters/http-fetch-adapter.ts @@ -4,7 +4,7 @@ /** * Node.js (≥ 22) implementation of FetchIO using the global fetch API. * - * Conforms to the FetchIO interface expected by @focusmcp/core + * Conforms to the FetchIO interface expected by @focus-mcp/core * marketplace/catalog-fetcher pure functions. */ diff --git a/src/adapters/npm-installer-adapter.test.ts b/src/adapters/npm-installer-adapter.test.ts index 018afe6..f57b817 100644 --- a/src/adapters/npm-installer-adapter.test.ts +++ b/src/adapters/npm-installer-adapter.test.ts @@ -86,7 +86,7 @@ describe('NpmInstallerAdapter', () => { 'official/echo': { version: '1.0.0', catalogUrl: 'https://example.com/catalog.json', - npmPackage: '@focusmcp/brick-echo', + npmPackage: '@focus-mcp/brick-echo', installedAt: '2026-01-01T00:00:00Z', }, }, @@ -134,7 +134,7 @@ describe('NpmInstallerAdapter', () => { 'official/echo': { version: '1.0.0', catalogUrl: 'https://example.com/catalog.json', - npmPackage: '@focusmcp/brick-echo', + npmPackage: '@focus-mcp/brick-echo', installedAt: '2026-01-01T00:00:00Z', }, }, @@ -157,12 +157,12 @@ describe('NpmInstallerAdapter', () => { makeChildProcess(0) as unknown as ReturnType, ); - await adapter.npmInstall('@focusmcp/brick-echo', '1.0.0'); + await adapter.npmInstall('@focus-mcp/brick-echo', '1.0.0'); expect(mkdir).toHaveBeenCalledWith(BRICKS_DIR, { recursive: true }); expect(spawn).toHaveBeenCalledWith( 'npm', - ['install', '--prefix', BRICKS_DIR, '@focusmcp/brick-echo@1.0.0'], + ['install', '--prefix', BRICKS_DIR, '@focus-mcp/brick-echo@1.0.0'], expect.objectContaining({ stdio: 'inherit', shell: false }), ); }); @@ -173,7 +173,7 @@ describe('NpmInstallerAdapter', () => { makeChildProcess(0) as unknown as ReturnType, ); - await adapter.npmInstall('@focusmcp/brick-echo', '1.0.0', { + await adapter.npmInstall('@focus-mcp/brick-echo', '1.0.0', { registry: 'https://registry.example.com', }); @@ -185,7 +185,7 @@ describe('NpmInstallerAdapter', () => { BRICKS_DIR, '--registry', 'https://registry.example.com', - '@focusmcp/brick-echo@1.0.0', + '@focus-mcp/brick-echo@1.0.0', ], expect.objectContaining({ stdio: 'inherit', shell: false }), ); @@ -197,7 +197,7 @@ describe('NpmInstallerAdapter', () => { makeChildProcess(1) as unknown as ReturnType, ); - await expect(adapter.npmInstall('@focusmcp/brick-echo', '1.0.0')).rejects.toThrow( + await expect(adapter.npmInstall('@focus-mcp/brick-echo', '1.0.0')).rejects.toThrow( 'npm install exited with code 1', ); }); @@ -209,11 +209,11 @@ describe('NpmInstallerAdapter', () => { makeChildProcess(0) as unknown as ReturnType, ); - await adapter.npmUninstall('@focusmcp/brick-echo'); + await adapter.npmUninstall('@focus-mcp/brick-echo'); expect(spawn).toHaveBeenCalledWith( 'npm', - ['uninstall', '--prefix', BRICKS_DIR, '@focusmcp/brick-echo'], + ['uninstall', '--prefix', BRICKS_DIR, '@focus-mcp/brick-echo'], expect.objectContaining({ stdio: 'inherit', shell: false }), ); }); @@ -223,7 +223,7 @@ describe('NpmInstallerAdapter', () => { makeChildProcess(0) as unknown as ReturnType, ); - await adapter.npmUninstall('@focusmcp/brick-echo', { + await adapter.npmUninstall('@focus-mcp/brick-echo', { registry: 'https://registry.example.com', }); @@ -235,7 +235,7 @@ describe('NpmInstallerAdapter', () => { BRICKS_DIR, '--registry', 'https://registry.example.com', - '@focusmcp/brick-echo', + '@focus-mcp/brick-echo', ], expect.objectContaining({ stdio: 'inherit', shell: false }), ); @@ -246,7 +246,7 @@ describe('NpmInstallerAdapter', () => { makeChildProcess(2) as unknown as ReturnType, ); - await expect(adapter.npmUninstall('@focusmcp/brick-echo')).rejects.toThrow( + await expect(adapter.npmUninstall('@focus-mcp/brick-echo')).rejects.toThrow( 'npm uninstall exited with code 2', ); }); @@ -262,7 +262,7 @@ describe('NpmInstallerAdapter', () => { vi.mocked(mkdir).mockResolvedValue(undefined); vi.mocked(spawn).mockReturnValue(child as unknown as ReturnType); - await expect(adapter.npmInstall('@focusmcp/brick-echo', '1.0.0')).rejects.toThrow( + await expect(adapter.npmInstall('@focus-mcp/brick-echo', '1.0.0')).rejects.toThrow( 'spawn ENOENT', ); }); diff --git a/src/adapters/npm-installer-adapter.ts b/src/adapters/npm-installer-adapter.ts index fe22371..00a36d9 100644 --- a/src/adapters/npm-installer-adapter.ts +++ b/src/adapters/npm-installer-adapter.ts @@ -5,7 +5,7 @@ * Node.js implementation of InstallerIO using child_process and the * ~/.focus/ filesystem layout. * - * Conforms to the InstallerIO interface expected by @focusmcp/core + * Conforms to the InstallerIO interface expected by @focus-mcp/core * marketplace/installer pure functions. */ diff --git a/src/bin/focus.ts b/src/bin/focus.ts index f74a0d9..a8094d2 100644 --- a/src/bin/focus.ts +++ b/src/bin/focus.ts @@ -169,7 +169,7 @@ async function main(argv: string[]): Promise { if (values['version']) { process.stdout.write( - `@focusmcp/cli ${process.env['CLI_VERSION'] ?? '0.0.0'} (core ${process.env['CORE_VERSION'] ?? '0.0.0'})\n`, + `@focus-mcp/cli ${process.env['CLI_VERSION'] ?? '0.0.0'} (core ${process.env['CORE_VERSION'] ?? '0.0.0'})\n`, ); return 0; } diff --git a/src/center.ts b/src/center.ts index 105c549..c211018 100644 --- a/src/center.ts +++ b/src/center.ts @@ -13,7 +13,7 @@ * * Both files live under `~/.focus/` and are read by every CLI command. * These parsers perform structural validation only — semver validity, - * catalog URLs, and signatures are checked by `@focusmcp/core`. + * catalog URLs, and signatures are checked by `@focus-mcp/core`. */ export interface CenterJsonEntry { diff --git a/src/commands/add.test.ts b/src/commands/add.test.ts index 6fedde3..60d7e5a 100644 --- a/src/commands/add.test.ts +++ b/src/commands/add.test.ts @@ -7,10 +7,10 @@ import type { FetchIO } from '../adapters/http-fetch-adapter.ts'; import type { InstallerIO } from '../adapters/npm-installer-adapter.ts'; // Re-export real implementations by default; individual tests can override parseCenterJson -const realCore = await vi.importActual('@focusmcp/core'); +const realCore = await vi.importActual('@focus-mcp/core'); -vi.mock('@focusmcp/core', async (importOriginal) => { - const real = await importOriginal(); +vi.mock('@focus-mcp/core', async (importOriginal) => { + const real = await importOriginal(); return { ...real }; }); @@ -79,7 +79,7 @@ function validBrick(overrides: Partial> = {}): Record { echo: { version: '1.0.0', catalogUrl: DEFAULT_URL, - npmPackage: '@focusmcp/brick-echo', + npmPackage: '@focus-mcp/brick-echo', installedAt: '2026-01-01T00:00:00Z', }, }, @@ -188,7 +188,7 @@ describe('addCommand', () => { it('shows "unknown" version when installed brick entry has no version (line 84 fallback)', async () => { // Override parseCenterJson to return a brick entry without a version field // so that centerJson.bricks[brickName]?.version is undefined, hitting the ?? 'unknown' branch - const { default: core } = await import('@focusmcp/core').then((m) => ({ default: m })); + const { default: core } = await import('@focus-mcp/core').then((m) => ({ default: m })); vi.spyOn(core, 'parseCenterJson').mockReturnValue({ bricks: { echo: { enabled: true } as unknown as ReturnType< diff --git a/src/commands/add.ts b/src/commands/add.ts index d52937b..d0fc199 100644 --- a/src/commands/add.ts +++ b/src/commands/add.ts @@ -20,7 +20,7 @@ import { parseCenterJson, parseCenterLock, planInstall, -} from '@focusmcp/core'; +} from '@focus-mcp/core'; import type { CatalogStoreIO } from '../adapters/catalog-store-adapter.ts'; import type { FetchIO } from '../adapters/http-fetch-adapter.ts'; import type { InstallerIO } from '../adapters/npm-installer-adapter.ts'; diff --git a/src/commands/catalog.test.ts b/src/commands/catalog.test.ts index b1dff49..a03a49f 100644 --- a/src/commands/catalog.test.ts +++ b/src/commands/catalog.test.ts @@ -8,8 +8,8 @@ import { catalogCommand } from './catalog.ts'; // listSources override — used only for the "empty sources" branch test (lines 100-101) let overrideListSources: (() => readonly unknown[]) | null = null; -vi.mock('@focusmcp/core', async (importOriginal) => { - const original = await importOriginal(); +vi.mock('@focus-mcp/core', async (importOriginal) => { + const original = await importOriginal(); return { ...original, listSources: (...args: Parameters) => { diff --git a/src/commands/catalog.ts b/src/commands/catalog.ts index 423cf5f..8a5319e 100644 --- a/src/commands/catalog.ts +++ b/src/commands/catalog.ts @@ -14,7 +14,7 @@ import { listSources, parseCatalogStore, removeSource, -} from '@focusmcp/core'; +} from '@focus-mcp/core'; import type { CatalogStoreData, CatalogStoreIO } from '../adapters/catalog-store-adapter.ts'; export type CatalogSubcommand = 'add' | 'remove' | 'list'; diff --git a/src/commands/remove.test.ts b/src/commands/remove.test.ts index 2fba5dd..dfd0f30 100644 --- a/src/commands/remove.test.ts +++ b/src/commands/remove.test.ts @@ -26,7 +26,7 @@ function makeInstallerIO(overrides: Partial = {}): InstallerIO { echo: { version: '1.0.0', catalogUrl: DEFAULT_URL, - npmPackage: '@focusmcp/brick-echo', + npmPackage: '@focus-mcp/brick-echo', installedAt: '2026-01-01T00:00:00Z', }, }, @@ -68,7 +68,7 @@ describe('removeCommand', () => { const result = await removeCommand({ brickName: 'echo', io }); - expect(installer.npmUninstall).toHaveBeenCalledWith('@focusmcp/brick-echo'); + expect(installer.npmUninstall).toHaveBeenCalledWith('@focus-mcp/brick-echo'); expect(installer.writeCenterJson).toHaveBeenCalledOnce(); expect(installer.writeCenterLock).toHaveBeenCalledOnce(); expect(result).toMatch(/removed echo/i); diff --git a/src/commands/remove.ts b/src/commands/remove.ts index 7a82b39..e790ecc 100644 --- a/src/commands/remove.ts +++ b/src/commands/remove.ts @@ -9,7 +9,7 @@ * Pure function: all I/O is injected via RemoveIO. */ -import { executeRemove, parseCenterJson, parseCenterLock, planRemove } from '@focusmcp/core'; +import { executeRemove, parseCenterJson, parseCenterLock, planRemove } from '@focus-mcp/core'; import type { InstallerIO } from '../adapters/npm-installer-adapter.ts'; export interface RemoveIO { diff --git a/src/commands/search.test.ts b/src/commands/search.test.ts index 56d509b..0492544 100644 --- a/src/commands/search.test.ts +++ b/src/commands/search.test.ts @@ -42,7 +42,7 @@ function validBrick(overrides: Partial> = {}): Record ({ +vi.mock('@focus-mcp/core', () => ({ createFocusMcp: () => ({ start: mockStart, stop: mockStop, @@ -1629,7 +1629,7 @@ describe('startCommand', () => { describe('focus_remove', () => { it('returns success message on remove', async () => { mockRemoveCommand.mockResolvedValue( - 'Removed my-brick (package: @focusmcp/my-brick)', + 'Removed my-brick (package: @focus-mcp/my-brick)', ); const { startCommand } = await import('./start.ts'); diff --git a/src/commands/start.ts b/src/commands/start.ts index ff60dfb..a746731 100644 --- a/src/commands/start.ts +++ b/src/commands/start.ts @@ -6,8 +6,8 @@ import { createServer } from 'node:http'; import { homedir } from 'node:os'; import { join } from 'node:path'; import { parseArgs } from 'node:util'; -import type { Brick } from '@focusmcp/core'; -import { createFocusMcp, loadBricks } from '@focusmcp/core'; +import type { Brick } from '@focus-mcp/core'; +import { createFocusMcp, loadBricks } from '@focus-mcp/core'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; @@ -100,7 +100,7 @@ export async function startCommand(argv: string[] = []): Promise { await focusMcp.start(); const server = new Server( - { name: '@focusmcp/cli', version: '0.0.0' }, + { name: '@focus-mcp/cli', version: '0.0.0' }, { capabilities: { tools: {} } }, ); diff --git a/src/source/filesystem-source.ts b/src/source/filesystem-source.ts index 9f714db..7187167 100644 --- a/src/source/filesystem-source.ts +++ b/src/source/filesystem-source.ts @@ -3,7 +3,7 @@ import { access, readFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; -import type { BrickSource } from '@focusmcp/core'; +import type { BrickSource } from '@focus-mcp/core'; import type { CenterJson } from '../center.ts'; export interface FilesystemSourceOptions { diff --git a/tsup.config.ts b/tsup.config.ts index ef06cf0..c8bf7c3 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -17,10 +17,10 @@ export default defineConfig({ format: ['esm'], target: 'node22', platform: 'node', - // @focusmcp/core is consumed locally via a file: dep at build time. + // @focus-mcp/core is consumed locally via a file: dep at build time. // We bundle it into dist so the published tarball is self-contained - // and end users don't have to install @focusmcp/core themselves. - noExternal: ['@focusmcp/core'], + // and end users don't have to install @focus-mcp/core themselves. + noExternal: ['@focus-mcp/core'], // Only the programmatic API emits .d.ts; the binary doesn't need types. dts: { entry: { index: 'src/index.ts' }, From 21c0556ddb93c44cfc001406e22cbda3fc8d53b2 Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 23 Apr 2026 11:11:05 +0200 Subject: [PATCH 3/3] ci: retrigger after core scope merge Co-Authored-By: Claude Opus 4.6 (1M context)