@skill-map/spec 0.11.0 → 0.12.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/CHANGELOG.md +73 -3
- package/cli-contract.md +49 -1
- package/index.json +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
# Spec changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 68c5e28: Step 14.1 — `sm serve` + Hono BFF skeleton
|
|
8
|
+
|
|
9
|
+
Adds `src/server/` Hono workspace with single-port wiring (`/api/health` real,
|
|
10
|
+
`/api/*` 404 stubs, `/ws` no-op upgrade, `serveStatic` + SPA fallback). Real
|
|
11
|
+
`ServeCommand` extracted from stub at `cli/commands/stubs.ts` to dedicated
|
|
12
|
+
`cli/commands/serve.ts` extending `SmCommand`. Loopback-only through v0.6.0
|
|
13
|
+
(Decision #119). Boot resilient to missing DB — `/api/health` reports
|
|
14
|
+
`db: 'missing'`. Spec `cli-contract.md` `sm serve` row updated to full flag
|
|
15
|
+
set; new `### Server` subsection (skeleton — endpoints fill at 14.2).
|
|
16
|
+
|
|
17
|
+
**Files added (server)**
|
|
18
|
+
|
|
19
|
+
- `src/server/index.ts` — `createServer(opts)` factory returning `ServerHandle` (`{ address, close }`); resolves spec version, builds the Hono app, instantiates a `WebSocketServer({ noServer: true })`, hands both to `@hono/node-server`'s `serve({ websocket: { server: wss } })`. Closing the http server tears down the WSS automatically (node-server registers the `'close'` hook internally); `close()` calls `wss.close()` defensively for forward-compatibility.
|
|
20
|
+
- `src/server/app.ts` — Hono app construction. Routes registered in single-port order: `GET /api/health` → real, `ALL /api/*` → structured 404, `GET /ws` via the injected `attachWs` registrar, static handler + SPA fallback. Global `app.onError` formats every uncaught throw into the error envelope.
|
|
21
|
+
- `src/server/options.ts` — `IServerOptions` + `validateServerOptions(input)`. Loopback-only check for `--dev-cors`; port range check `[0, 65535]`; scope validation.
|
|
22
|
+
- `src/server/paths.ts` — `resolveDefaultUiDist(ctx)` walks upwards from cwd looking for `ui/dist/browser/index.html`; `resolveExplicitUiDist(ctx, raw)` honours absolute paths for `--ui-dist`.
|
|
23
|
+
- `src/server/static.ts` — wraps `@hono/node-server`'s `serveStatic` middleware with the SPA-fallback layer (`serveStatic` does not do SPA fallback — it `next()`s on miss, which is exactly the seam we hook into). Absolute `root` paths work on POSIX in node-server@2.0.1 (verified runtime probe — implementation is `path.join(root, filename)`); the `.d.ts` "Absolute paths are not supported" string is stale (upstream issue honojs/node-server#187 still open). When the bundle is missing (`uiDist === null`), a tiny placeholder middleware serves the boot-without-bundle hint at `/`.
|
|
24
|
+
- `src/server/ws.ts` — `noopWebSocketRoute(app)` registers `GET /ws` via the official `upgradeWebSocket` re-exported from `@hono/node-server@2.x`. The 14.1 handler closes the connection in `onOpen` with code 1000 + reason `'no broadcaster yet'`. 14.4 swaps this registrar for the chokidar-fed broadcaster — one-line change in `index.ts`, `app.ts` untouched.
|
|
25
|
+
- `src/server/health.ts` — `buildHealth(deps)` synchronous; `resolveSpecVersion()` async, called once at boot.
|
|
26
|
+
- `src/server/i18n/server.texts.ts` — `SERVER_TEXTS` catalog.
|
|
27
|
+
|
|
28
|
+
**Files added (CLI)**
|
|
29
|
+
|
|
30
|
+
- `src/cli/commands/serve.ts` — `ServeCommand extends SmCommand`. Parses flags, validates, calls `createServer`, registers SIGINT/SIGTERM handlers, awaits shutdown. `protected emitElapsed = false` (long-running daemon).
|
|
31
|
+
- `src/cli/i18n/serve.texts.ts` — `SERVE_TEXTS` catalog.
|
|
32
|
+
|
|
33
|
+
**Tests added (15)**
|
|
34
|
+
|
|
35
|
+
- `src/test/server-boot.test.ts` (7) — boot/listen/health JSON, custom port, db state present/missing, structured 404, /ws upgrade closes with code 1000 + reason 'no broadcaster yet' (uses real `WebSocket` client from `ws`), shutdown < 1s + idempotent close, inline placeholder when uiDist null.
|
|
36
|
+
- `src/test/server-flags.test.ts` (6) — host non-loopback + dev-cors rejection, port out-of-range, port non-numeric, scope invalid, ui-dist missing, ui-dist with valid bundle.
|
|
37
|
+
- `src/test/server-db-missing.test.ts` (2) — `--db <missing>` exits 5, default boots cleanly with db:missing.
|
|
38
|
+
|
|
39
|
+
**Files edited**
|
|
40
|
+
|
|
41
|
+
- `src/cli/commands/stubs.ts` — `ServeCommand` removed; replaced with a comment pointer.
|
|
42
|
+
- `src/cli/entry.ts` — registers the new `ServeCommand`.
|
|
43
|
+
- `src/package.json` — adds `hono@4.12.16`, `@hono/node-server@2.0.1`, `ws@8.20.0` (deps); `@types/ws@8.18.1` (dev). All exact-pinned per AGENTS.md.
|
|
44
|
+
- `spec/cli-contract.md` — `sm serve` row replaced with the full 14.1 flag set; new `#### Server` subsection (stability: experimental).
|
|
45
|
+
- `spec/CHANGELOG.md` — `[Unreleased]` `### Minor` entry for the spec change.
|
|
46
|
+
- `spec/index.json` — regenerated (40 files hashed; previous head was 215 lines).
|
|
47
|
+
|
|
48
|
+
**Decisions during implementation (flag for orchestrator)**
|
|
49
|
+
|
|
50
|
+
- WebSocket support uses `@hono/node-server@2.x`'s built-in `upgradeWebSocket` plus the canonical `ws@8.20.0` Node WebSocket library, per the official README pattern. The previously-published `@hono/node-ws` adapter was deprecated when node-server@2.0 absorbed WebSocket support natively (PR honojs/node-server#328). The 14.4 broadcaster will replace `noopWebSocketRoute` with its own one-line registrar — no API churn between 14.1 and 14.4.
|
|
51
|
+
- The `/api/*` catch-all is wired with `app.all('/api/*', ...)` BEFORE the `/ws` registrar and the static handler so neither a `serveStatic` filesystem hit nor the SPA fallback can shadow API endpoints. `/ws` is registered BEFORE the static handler so a literal `/ws` path on disk inside `uiDist` cannot accidentally shadow the upgrade route.
|
|
52
|
+
- `serveStatic` from `@hono/node-server/serve-static` accepts absolute root paths at runtime on POSIX (its implementation is `path.join(root, filename)`); the `.d.ts` string saying otherwise is documentation drift, not a runtime contract. Verified with a runtime probe and cross-referenced against the open upstream issue (honojs/node-server#187). Documented in `src/server/static.ts` so future contributors don't re-investigate.
|
|
53
|
+
|
|
3
54
|
## 0.11.0
|
|
4
55
|
|
|
5
56
|
### Minor Changes
|
|
@@ -172,6 +223,25 @@ list`, `sm plugins doctor`, `sm db prune` plugin filter, runtime
|
|
|
172
223
|
|
|
173
224
|
## [Unreleased]
|
|
174
225
|
|
|
226
|
+
### Minor
|
|
227
|
+
|
|
228
|
+
- **`sm serve` row + `### Server` subsection** in `cli-contract.md` —
|
|
229
|
+
Step 14.1 promotes `sm serve` from an implementation-defined stub to a
|
|
230
|
+
documented surface. The verb row at `§Verb catalog` › `### Server`
|
|
231
|
+
expands the flag set to the full 14.1 contract: `--port` (default
|
|
232
|
+
`4242`), `--host` (default `127.0.0.1`, loopback-only through v0.6.0),
|
|
233
|
+
`--scope project|global`, `--db <path>`, `--no-built-ins`,
|
|
234
|
+
`--no-plugins`, `--open` / `--no-open`, `--dev-cors`, `--ui-dist
|
|
235
|
+
<path>` (hidden). New `#### Server` subsection documents the
|
|
236
|
+
single-port mandate, the boot-with-missing-DB resilience contract
|
|
237
|
+
(`/api/health` returns `db: 'missing'`), the v14.1 endpoint surface
|
|
238
|
+
(`GET /api/health` real, `ALL /api/*` 404 stubs, `GET /ws` upgrade-only,
|
|
239
|
+
static + SPA fallback), the structured error envelope shape, and the
|
|
240
|
+
flag table. Marked `*(Stability: experimental — locks at v0.6.0.)*` —
|
|
241
|
+
endpoints fill at v14.2, broadcaster at v14.4. Additive minor per
|
|
242
|
+
`versioning.md` § Pre-1.0 (no breaking change to the existing row's
|
|
243
|
+
semantics; the old wording was strictly less specific).
|
|
244
|
+
|
|
175
245
|
### Minor (breaking, pre-1.0)
|
|
176
246
|
|
|
177
247
|
- **`Node.kind` opens to any non-empty string (was the closed enum
|
|
@@ -1159,9 +1229,9 @@ kind, normalizedTrigger)` and prints one row per group with the
|
|
|
1159
1229
|
(`Links out (12, 9 unique)`). When N > 1 detector emits the same
|
|
1160
1230
|
logical link, the row also gets a `(×N)` suffix.
|
|
1161
1231
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1232
|
+
`--json` output is byte-identical to before — raw rows, no merge.
|
|
1233
|
+
Storage is byte-identical to before. The grouping is purely a
|
|
1234
|
+
read-time presentation choice for human eyes.
|
|
1165
1235
|
|
|
1166
1236
|
**Spec changes (patch)**:
|
|
1167
1237
|
|
package/cli-contract.md
CHANGED
|
@@ -316,7 +316,55 @@ Destructive verbs (`reset --state`, `reset --hard`, `restore`) require interacti
|
|
|
316
316
|
|
|
317
317
|
| Command | Purpose |
|
|
318
318
|
|---|---|
|
|
319
|
-
| `sm serve [--port N] [--host ...] [--no-open]` | Start Hono + WebSocket for the Web UI.
|
|
319
|
+
| `sm serve [--port N] [--host ...] [--scope project\|global] [--db <path>] [--no-built-ins] [--no-plugins] [--open\|--no-open] [--dev-cors] [--ui-dist <path>]` | Start Hono + WebSocket for the Web UI. Single-port mandate: SPA + REST + WS under one listener. Default port 4242, default host 127.0.0.1 (loopback-only through v0.6.0; multi-host deferred — see §Server). |
|
|
320
|
+
|
|
321
|
+
#### Server
|
|
322
|
+
|
|
323
|
+
*(Stability: experimental — locks at v0.6.0.)*
|
|
324
|
+
|
|
325
|
+
The reference implementation ships a Hono BFF rooted at `src/server/`. One Node process serves the Angular SPA, the REST API under `/api/*`, and the WebSocket at `/ws` — single-port mandate, no proxy. Loopback-only assumption through v0.6.0: no per-connection auth on `/ws`; combining `--dev-cors` with a non-loopback `--host` is rejected (exit 2).
|
|
326
|
+
|
|
327
|
+
**Boot resilience**: `sm serve` boots even when the project DB is missing. `/api/health` reports `db: 'missing'` so the SPA can render an empty-state CTA instead of failing the connection. Explicit `--db <path>` that doesn't exist is the exception — that exits 5 (NotFound) per `§Exit codes`.
|
|
328
|
+
|
|
329
|
+
**Endpoints (v14.1 surface)**:
|
|
330
|
+
|
|
331
|
+
| Path | Status | Shape |
|
|
332
|
+
|---|---|---|
|
|
333
|
+
| `GET /api/health` | implemented | `{ ok: true, schemaVersion, specVersion, implVersion, scope: 'project'\|'global', db: 'present'\|'missing' }` |
|
|
334
|
+
| `ALL /api/*` (other) | reserved | structured 404 envelope (see below); real endpoints land at v14.2 |
|
|
335
|
+
| `GET /ws` | upgrade-only | accepts WebSocket upgrade and immediately closes; broadcaster lands at v14.4 |
|
|
336
|
+
| `GET *` | implemented | static asset from the resolved UI bundle, falling back to `index.html` for SPA deep links |
|
|
337
|
+
|
|
338
|
+
**Error envelope** (mirrors `§Machine-readable output rules`):
|
|
339
|
+
|
|
340
|
+
```json
|
|
341
|
+
{
|
|
342
|
+
"ok": false,
|
|
343
|
+
"error": {
|
|
344
|
+
"code": "not-found" | "bad-query" | "db-missing" | "internal",
|
|
345
|
+
"message": "<human-readable>",
|
|
346
|
+
"details": { ... } | null
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
HTTP status mapping: `400` → `bad-query`, `404` → `not-found`, `500` → `internal` / `db-missing`.
|
|
352
|
+
|
|
353
|
+
**Flag surface**:
|
|
354
|
+
|
|
355
|
+
| Flag | Default | Purpose |
|
|
356
|
+
|---|---|---|
|
|
357
|
+
| `--port N` | `4242` | Listening port. `0` = OS-assigned (handle reports the bound port). |
|
|
358
|
+
| `--host <ip>` | `127.0.0.1` | Listening host. Implementations MUST NOT bind `0.0.0.0` by default. |
|
|
359
|
+
| `--scope project\|global` | `project` | Effective scope for `/api/*` reads. Alias for `-g/--global`. |
|
|
360
|
+
| `--db <path>` | resolved per spec § Global flags | Override the DB file location. Missing explicit `--db` exits 5. |
|
|
361
|
+
| `--no-built-ins` | off | Skip built-in plugin registration (parity with `sm scan --no-built-ins`). |
|
|
362
|
+
| `--no-plugins` | off | Skip drop-in plugin discovery. |
|
|
363
|
+
| `--open` / `--no-open` | `--open` | Auto-open the SPA in the user's default browser after listen. |
|
|
364
|
+
| `--dev-cors` | off | Enable permissive CORS for the Angular dev-server proxy workflow. Loopback-only when set. |
|
|
365
|
+
| `--ui-dist <path>` | auto | Override the UI bundle directory. Hidden flag — used by the demo build pipeline + tests; everyday users never need it. |
|
|
366
|
+
|
|
367
|
+
**Graceful shutdown**: SIGINT / SIGTERM trigger a graceful close; the verb returns exit 0 on clean shutdown. Bind failure (port in use, EACCES) returns exit 2.
|
|
320
368
|
|
|
321
369
|
---
|
|
322
370
|
|
package/index.json
CHANGED
|
@@ -166,14 +166,14 @@
|
|
|
166
166
|
}
|
|
167
167
|
]
|
|
168
168
|
},
|
|
169
|
-
"specPackageVersion": "0.
|
|
169
|
+
"specPackageVersion": "0.12.0",
|
|
170
170
|
"integrity": {
|
|
171
171
|
"algorithm": "sha256",
|
|
172
172
|
"files": {
|
|
173
|
-
"CHANGELOG.md": "
|
|
173
|
+
"CHANGELOG.md": "c85703fa37d3c084e2251c0b77626c94fa5c6897289c1534432ae45ac168762b",
|
|
174
174
|
"README.md": "bd30780525e75379eaeb5f8a903bdc601daf3862f3ec69dffc96c437e8d476fc",
|
|
175
175
|
"architecture.md": "9a6d96d150af60ed8d476af572d07dcce605f116fde720bebb2662b11250bf4b",
|
|
176
|
-
"cli-contract.md": "
|
|
176
|
+
"cli-contract.md": "89dcd366624821c1ab77d1014229b4c209953f337d0c62d16b24472c64c3bad4",
|
|
177
177
|
"conformance/README.md": "838b1247e1ffb402d96bd8a0fe9c1c0f4a99ed0fbc4bf8156f7a58330cac27f5",
|
|
178
178
|
"conformance/cases/kernel-empty-boot.json": "ad4bbe9d637537625025c8bdb61285b1433568a2544b1ce0248f304ccff8c350",
|
|
179
179
|
"conformance/coverage.md": "4df23b78ec44887dc355e0622b9008bb2514f3b8e9c302db18eb51532fda5275",
|