@kigo-dev/sindri 0.1.4 → 0.1.6
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 +25 -1
- package/dist/index.js +698 -179
- package/manifest.json +18 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,6 +28,10 @@ names, parameters and this document are English. The contract lives in
|
|
|
28
28
|
| `share` | `app` | The Slack line. |
|
|
29
29
|
| `help` | – | No network. `{ summary, space_url, logged_in, apps_dir }`: the Spanish introduction Claude gives on first contact (what Sindri is, what to ask for, limits, the Mi espacio link https://sindri.kigo.dev), whether credentials are stored on this computer (keychain or file, no API call) and where the apps live. |
|
|
30
30
|
| `design_guide` | `app`, `topic?` | No network. Reads the `kigo-sindri-design` skill the template ships at `apps/<owner>/<app>/.claude/skills/kigo-sindri-design/`: without `topic`, `SKILL.md` plus `topics` (the file names under `references/` without `.md`); with `topic`, that reference file. `{ ok, summary, topic, topics, content }`, `content` verbatim markdown for Claude to follow (never pasted to the PM). `ok:false, code:"no_design_guide"` when the app predates the skill (Claude runs `update_template` once and retries); `code:"unknown_topic"` lists the valid topics. Also exposed as MCP resources `sindri://design-guide/<app>` and `sindri://design-guide/<app>/<topic>`. |
|
|
31
|
+
| `set_secret` | `app`, `name`, `hint?` | Asks the PM for a credential without it ever passing through the conversation. Validates the name (`^[A-Z][A-Z0-9_]{1,63}$`, platform keys `KIGO_ENV`, `KIGO_APP_NAME`, `DATABASE_URL`, `PGLITE_DATA_DIR`, `SINDRI_TASK_TOKEN` refused with `code:"reserved_key"`), checks the app and the session (`GET /v1/apps/<app>`), then listens on `http://127.0.0.1:<random>/s/<nonce>` and opens the browser (`SINDRI_OPENER`) on a self-contained Spanish page («Guardar secreto para «<app>»», the key, the optional `hint`, a password input with «mostrar», «Guardar»). On POST: nonce single-use, `Origin` must be the loopback, value ≤ 8 KB with one trailing newline trimmed; the value is upserted as `NAME=value` in the app's `.env.local` (quoted for dotenv and `node --env-file`), sent with `PUT /v1/apps/<app>/secrets/<NAME>`, the browser gets «Listo, ya puedes volver a Claude» and the server closes. A running preview is restarted so the env applies. Waits up to 5 minutes (`code:"expired"`); `code:"no_browser"` when the opener fails. Returns `{ ok, summary, name, restarted, preview_restarted, local }`; the value is never in the result, in logs or on stderr. |
|
|
32
|
+
| `list_secrets` | `app` | `GET /v1/apps/<app>/secrets` → `names`, plus `local_names` from the app's `.env.local` (platform keys hidden) and the two differences `missing_local` / `missing_in_sindri`. Names only, never values. |
|
|
33
|
+
| `delete_secret` | `app`, `name` | `DELETE /v1/apps/<app>/secrets/<NAME>` (a 404 counts as "not in Sindri") and removes the line from `.env.local`; restarts a running preview. `{ removed_from_sindri, removed_locally, preview_restarted }`. |
|
|
34
|
+
| `run_task` | `app`, `task`, `where?` | `where` defaults to `local` when a preview is running, else `sindri`. Local: reads the `schedules:` line of the local `kigo-app.yaml` (`code:"task_not_declared"` with the declared names when absent), makes sure `SINDRI_TASK_TOKEN` exists in `.env.local` (restarting the preview if it had to be created) and does `POST http://127.0.0.1:<port><path>` with `X-Sindri-Task: <task>` and `Authorization: Bearer <token>`, 5-minute cap. Sindri: `POST /v1/apps/<app>/tasks/<task>/run`. Both return `{ ok, summary, where, status: "ok"|"error"|"timeout", http_status, duration_ms, output_tail }`. |
|
|
31
35
|
|
|
32
36
|
Every result is `{ ok, summary, ...data }`. `needs_login: true` / `needs_setup: true` tell Claude
|
|
33
37
|
which tool to run first. `list_apps` also returns `space_url`. The server also ships
|
|
@@ -43,7 +47,7 @@ name, typed confirmation before `delete_app`).
|
|
|
43
47
|
**Claude Code:**
|
|
44
48
|
|
|
45
49
|
```
|
|
46
|
-
claude mcp add sindri -- npx -y @kigo-dev/sindri@0.1.
|
|
50
|
+
claude mcp add sindri -- npx -y @kigo-dev/sindri@0.1.6
|
|
47
51
|
```
|
|
48
52
|
|
|
49
53
|
**Manual check without an MCP client:**
|
|
@@ -112,6 +116,26 @@ after a rename; `test/tools.test.ts` builds the builder's post-rename tree (old
|
|
|
112
116
|
`name:` edited) and asserts both hashes are equal. Deleted apps are never removed from disk: they
|
|
113
117
|
go to `~/Sindri/.papelera/`, which no tool scans (`.papelera` is not a valid app name).
|
|
114
118
|
|
|
119
|
+
## Secrets and tasks
|
|
120
|
+
|
|
121
|
+
`.env.local` in the app dir is owned by the connector but edited by line (`src/envfile.ts`):
|
|
122
|
+
`create_app` writes it once with `KIGO_ENV=local`, `KIGO_APP_NAME=<app>` and a fresh
|
|
123
|
+
`SINDRI_TASK_TOKEN` (32 random bytes, hex); `rollback`, `update_template` and `rename_app` only
|
|
124
|
+
make sure those keys exist (`rename_app` rewrites `KIGO_APP_NAME`) and never overwrite the file,
|
|
125
|
+
so the PM's secrets and the token survive every tree swap. The file is excluded from the tree
|
|
126
|
+
hash and from the `publish` tarball (`test/tools.test.ts` gunzips the uploaded archive and
|
|
127
|
+
asserts the value is not in it). Values are quoted with whichever quote character they do not
|
|
128
|
+
contain (double quotes carry `\n`; single quotes when the value has `$`, which Next would
|
|
129
|
+
otherwise expand), because Next's dotenv and Node's `--env-file` disagree on escaped quotes.
|
|
130
|
+
|
|
131
|
+
Scheduled tasks are one line in `kigo-app.yaml`,
|
|
132
|
+
`schedules: [{"name":"sync-linear","path":"/api/tareas/sync-linear","every":"30m"}]`
|
|
133
|
+
(`src/schedules.ts` validates: name `^[a-z][a-z0-9-]{1,31}$` and unique, path under `/api/`
|
|
134
|
+
without query, `every` ∈ 5m 10m 15m 30m 1h 2h 6h 12h 1d, at most 5). In Sindri the workspace
|
|
135
|
+
router calls the path in business hours with `X-Sindri-Task` and the app's own
|
|
136
|
+
`SINDRI_TASK_TOKEN`; the template's `taskHandler` checks both. `run_task` reproduces that call
|
|
137
|
+
against the local preview with the local token, which is how a task is tested before publishing.
|
|
138
|
+
|
|
115
139
|
## Local database
|
|
116
140
|
|
|
117
141
|
The template runs on PGlite when `KIGO_ENV=local` and no `DATABASE_URL` is set; data lives in
|