@kigo-dev/sindri 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/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # @kigo-dev/sindri — the Sindri connector
2
+
3
+ An MCP server (stdio) that turns a product manager's Claude into a builder of Kigo internal
4
+ apps. Claude edits the app files on the PM's computer with the PM's own plan; this connector
5
+ does everything around that: installs the toolchain, runs the app locally with an embedded
6
+ database, publishes it at `https://<name>.sindri.kigo.dev` and keeps versions.
7
+
8
+ Everything the PM reads (the `summary` of every tool result, error messages) is Spanish; tool
9
+ names, parameters and this document are English. The contract lives in
10
+ `docs/conector-v4-contratos.md`, section D.
11
+
12
+ ## Tools
13
+
14
+ | Tool | Arguments | What it does |
15
+ |---|---|---|
16
+ | `setup` | – | Installs Node LTS and pnpm under the user's home with [fnm](https://github.com/Schniz/fnm) (no sudo), creates `~/Sindri`. Reuses an existing Node ≥ 20 + pnpm. Idempotent. |
17
+ | `login` | – | OAuth 2.0 authorization code + PKCE (S256) with a loopback redirect, Vercel-CLI style: listens on `http://127.0.0.1:<random>/callback`, opens Identity's `authorization_endpoint` (client `sindri-connector`, public, `audience=sindri-api`), validates `state`, exchanges the code with the verifier, shows "Listo, ya entraste a Sindri" and closes. Waits up to 5 minutes. Device flow only as a fallback when no browser can be opened and discovery advertises the device grant. Tokens go to the macOS keychain (service `sindri`) or `~/.sindri/credentials.json` (0600). Refreshes silently. |
18
+ | `create_app` | `name`, `description` | `POST /v1/apps`, downloads the personalised template into `~/Sindri/<name>`, `pnpm install`, migrates and seeds the local database. |
19
+ | `preview` | `app` | `pnpm db:migrate` (and seed on first run), then `pnpm dev --port <free>` detached with `KIGO_ENV=local` (PGlite), waits for `/healthz`, opens the browser. Reuses a healthy preview. |
20
+ | `publish` | `app`, `message` | `tsc --noEmit`, checks the running preview, tars the tree (without `node_modules`, `.next`, `.sindri`, `.env*`, `dist`, `.turbo`), `POST /v1/apps/<app>/publish`. On failure the published version does not change. |
21
+ | `status` | `app` | Address and last version from the API, plus whether the local folder exists and has unpublished edits (tree hash vs `.sindri/last-published.json`). |
22
+ | `list_apps` | – | The PM's apps, with local folder state. |
23
+ | `versions` | `app` | Published versions, most recent first. |
24
+ | `rollback` | `app`, `version` | `POST rollback`, then downloads that version's archive and replaces the local tree (keeps `node_modules`, `.sindri`, `.env.local`). Stops the preview first: PGlite allows one process per data dir. |
25
+ | `share` | `app` | The Slack line. |
26
+
27
+ Every result is `{ ok, summary, ...data }`. `needs_login: true` / `needs_setup: true` tell Claude
28
+ which tool to run first. The server also ships `instructions` describing how to talk to the PM.
29
+
30
+ ## Install
31
+
32
+ **Claude Desktop (recommended for PMs):** double-click the `sindri.mcpb` extension (built from
33
+ `manifest.json` with `npx @anthropic-ai/mcpb pack`), accept, done. The first conversation runs
34
+ `setup` and `login`.
35
+
36
+ **Claude Code:**
37
+
38
+ ```
39
+ claude mcp add sindri -- npx -y @kigo-dev/sindri
40
+ ```
41
+
42
+ **Manual check without an MCP client:**
43
+
44
+ ```
45
+ npx @kigo-dev/sindri status '{"app":"visitas"}'
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ | Variable | Default | Meaning |
51
+ |---|---|---|
52
+ | `SINDRI_API_URL` | `https://api.sindri.kigo.dev` | Sindri API |
53
+ | `SINDRI_ISSUER` | `https://id.kigo.dev` | Identity issuer (OpenID discovery) |
54
+ | `SINDRI_CLIENT_ID` | `sindri-connector` | Public OAuth client |
55
+ | `SINDRI_AUDIENCE` | `sindri-api` | Audience requested for the access token |
56
+ | `SINDRI_HOME` | `~/Sindri` | Where app folders live |
57
+ | `SINDRI_STATE_DIR` | `~/.sindri` | Credentials fallback, preview registry |
58
+ | `SINDRI_CREDENTIAL_STORE` | keychain on macOS, file elsewhere | `file` forces the JSON file |
59
+ | `SINDRI_FNM_DIR` | `~/.local/share/fnm` | Where `setup` installs Node |
60
+ | `SINDRI_OPENER` | `open` / `xdg-open` | Browser opener; empty disables |
61
+
62
+ ## Development
63
+
64
+ ```
65
+ pnpm install --ignore-workspace
66
+ pnpm typecheck && pnpm test && pnpm build
67
+ ```
68
+
69
+ Tests run against a fake Identity issuer (`/authorize` redirecting to the loopback, `/token`
70
+ checking the PKCE verifier, plus the device endpoints for the fallback), a fake Sindri API and
71
+ stub `node`/`pnpm` binaries under a temporary HOME; nothing is installed on the developer's machine.
72
+
73
+ Identity must register `sindri-connector` as a PUBLIC client with `redirect_uri_globs`
74
+ `http://127.0.0.1:*/callback` (loopback ports are random, RFC 8252 §7.3), PKCE required, grant
75
+ types `authorization_code` and `refresh_token`.
76
+
77
+ ## Local layout
78
+
79
+ `~/Sindri/<name>/` is the sparse root of the kigo-sindri-apps monorepo exactly as Sindri's
80
+ archive ships it (`package.json`, `pnpm-workspace.yaml`, `pnpm-lock.yaml`, `tsconfig.base.json`,
81
+ `packages/`, `apps/<owner>/<name>`), because the app uses `catalog:` and `workspace:` specifiers
82
+ and cannot install standalone. `pnpm install` runs at that root; `preview`, `db:migrate`,
83
+ `db:seed`, `tsc`, the tree hash, `.env.local`, `.sindri/last-published.json` and the `publish`
84
+ tarball (paths relative to the app) all live at `apps/<owner>/<name>`. `replaceTree` swaps the
85
+ whole root on `create_app`/`rollback` but keeps every `node_modules` and the app's `.sindri/`
86
+ and `.env*`. The owner is the single folder under `apps/`, else the `owner` from `GET /v1/me`
87
+ (cached in `~/.sindri/me.json`).
88
+
89
+ ## Local database
90
+
91
+ The template runs on PGlite when `KIGO_ENV=local` and no `DATABASE_URL` is set; data lives in
92
+ `<app>/.sindri/pglite/`. PGlite is single-process: the connector never runs migrations while a
93
+ preview is up, and stops the preview before a rollback replaces the tree.