@prismer/runtime 1.9.1 → 1.9.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +363 -229
  3. package/dist/cli.cjs +10269 -0
  4. package/dist/cli.cjs.map +1 -0
  5. package/dist/cli.js +10257 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.cjs +10603 -0
  8. package/dist/index.cjs.map +1 -0
  9. package/dist/index.d.cts +1643 -0
  10. package/dist/index.d.ts +1496 -1916
  11. package/dist/index.js +9702 -9177
  12. package/dist/index.js.map +1 -1
  13. package/package.json +31 -33
  14. package/dist/adapter-registry-EMZFKFYK.mjs +0 -8
  15. package/dist/adapter-registry-EMZFKFYK.mjs.map +0 -1
  16. package/dist/artifacts-uploader-N2HNBSTW.mjs +0 -159
  17. package/dist/artifacts-uploader-N2HNBSTW.mjs.map +0 -1
  18. package/dist/auto-register-M4YSPJS6.mjs +0 -204
  19. package/dist/auto-register-M4YSPJS6.mjs.map +0 -1
  20. package/dist/bin/prismer.js +0 -14988
  21. package/dist/chunk-BJTO5JO5.mjs +0 -11
  22. package/dist/chunk-BJTO5JO5.mjs.map +0 -1
  23. package/dist/chunk-JIEDFDVI.mjs +0 -148
  24. package/dist/chunk-JIEDFDVI.mjs.map +0 -1
  25. package/dist/chunk-NDNX2G6O.mjs +0 -68
  26. package/dist/chunk-NDNX2G6O.mjs.map +0 -1
  27. package/dist/chunk-POWV475F.mjs +0 -45
  28. package/dist/chunk-POWV475F.mjs.map +0 -1
  29. package/dist/chunk-VTFKZAUY.mjs +0 -68
  30. package/dist/chunk-VTFKZAUY.mjs.map +0 -1
  31. package/dist/dispatch-mux-MW4HHICS.mjs +0 -8
  32. package/dist/dispatch-mux-MW4HHICS.mjs.map +0 -1
  33. package/dist/dispatch-rpc-J7H6KC2V.mjs +0 -78
  34. package/dist/dispatch-rpc-J7H6KC2V.mjs.map +0 -1
  35. package/dist/fs-rpc-OSHJZYK6.mjs +0 -58
  36. package/dist/fs-rpc-OSHJZYK6.mjs.map +0 -1
  37. package/dist/heartbeat-loop-H2LAI3V5.mjs +0 -95
  38. package/dist/heartbeat-loop-H2LAI3V5.mjs.map +0 -1
  39. package/dist/index.d.mts +0 -2063
  40. package/dist/index.mjs +0 -8807
  41. package/dist/index.mjs.map +0 -1
  42. package/dist/mode-b-DXJ7FJAL.mjs +0 -152
  43. package/dist/mode-b-DXJ7FJAL.mjs.map +0 -1
  44. package/dist/registry-ZYU2HDFL.mjs +0 -12
  45. package/dist/registry-ZYU2HDFL.mjs.map +0 -1
  46. /package/{dist → assets}/icon +0 -0
  47. /package/{dist → assets}/smallicon +0 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,178 @@
1
+ # Changelog — @prismer/runtime
2
+
3
+ ## Unreleased — Origin Adapter framework + memory-curation skill
4
+
5
+ Doc 26 §4 Phase 2 + doc 27 rev 5 §3. Daemon-side asset producers behind a
6
+ uniform OriginAdapter SPI; agent-driven memory curation guidance loaded into
7
+ the four host adapters.
8
+
9
+ ### Added — **Origin Adapter framework** (`daemon/asset/origin/`)
10
+ - **SPI** (`spi.ts`): `OriginAdapter` interface with `kind: 'upload' | 'drop-folder' | 'agent-gen'`, `observe / identifySource / fetch` decomposition. Identification stays separate from byte fetch so the outbox can dedupe before paying read cost.
11
+ - **Outbox** (`outbox.ts`): SQLite-backed pending-upload queue mirroring `daemon/memory/outbox.ts` shape — Zod validation → dead-letter, `idempotencyKey = sha256(originKind|wid|sourceRef|observedAt)` UNIQUE, `claimNext()` transactional, `recordFailure(maxAttempts)` auto-spills to dead-letter. Restart-resume-friendly (rows persist across daemon process death).
12
+ - **Drop-folder adapter** (`drop-folder.ts`): polls `~/.prismer/workspaces/<wid>/drop/` (1s tick, recursive), enqueues observations, on success moves files to `uploaded/`, on persistent failure to `upload-failed/`. Mime detected by extension.
13
+ - **Agent-gen adapter** (`agent-gen.ts`): synchronous handler `handleAssetWrite(body, { cloud })` for the new `POST /local/asset/write` RPC. Daemon writes under owner identity; `sourceAgentImUserId` is a passenger metadata field (decoupled from auth — no dependency on Line B B1 POST permission alignment).
14
+ - **Web-upload adapter** (`web-upload.ts`): cloud-side marker class for SPI symmetry. Throws if invoked daemon-side; the actual upload is the cloud `POST /api/im/assets` handler.
15
+ - **Upload runner** (`upload-runner.ts`): generic worker draining the outbox, dispatching to adapters by `originKind`. Hooks `onUploadSuccess` / `onUploadFailure` on the adapter (drop-folder uses these for the uploaded/upload-failed file moves).
16
+ - **`POST /local/asset/write` route** (`local-server.ts`): wires `onAssetWrite` sink alongside `onDispatch` / `attachMemory`. Returns `{ assetId, contentHash, prismerUri: 'prismer://workspace/<wid>/asset/<contentHash>' }`. 400/502/501 error contract.
17
+
18
+ ### Added — **memory-curation skill** (doc 27 rev 5 §3)
19
+ - **Codex adapter** (`adapters/codex/index.ts`): `buildCodexPrompt()` extracted as pure function; injects `MEMORY_CURATION_SKILL_TEXT` as system-prompt preamble (Codex has no native skill framework).
20
+ - **Embedded skill module** (`src/skills/memory-curation.ts`): regenerated from canonical `sdk/prismer-cloud/skill/memory-curation.md` via `scripts/regenerate-memory-curation-skill.cjs` (also handles the openclaw / Python / CC plugin copies).
21
+
22
+ ### Tests
23
+ - 44 new vitest assertions across 8 new test files: `origin-spi`, `origin-outbox`, `origin-drop-folder`, `origin-agent-gen`, `local-server-asset-write`, `origin-web-upload`, `skill-memory-curation-sync`, `codex-adapter-skill-injection`.
24
+ - Acceptance criteria covered: doc 26 §5 L2-T1 (100-burst, dead-letter=0), L2-T2 (restart resume), L2-T3 (RPC sync return).
25
+ - Total runtime suite: 192 → 234 passing, 0 failures.
26
+
27
+ ### Cookbook
28
+ - `docs/cookbook/m-asset-origin-drop-folder.md`
29
+ - `docs/cookbook/m-asset-origin-agent-gen.md`
30
+
31
+ ### Phase staging — what this PR does NOT yet wire
32
+ - **Daemon `runner.ts` does not yet construct `OriginOutbox` / `DropFolderAdapter` / `UploadRunner`.** The SPI + handlers ship here; the runner-level wiring + a concrete `CloudUploadClient` (FormData wrapper around the existing `CloudClient`) land in a follow-up PR alongside the rest of doc 26 §4 Phase 2 production-enable work.
33
+ - `POST /local/asset/write` returns **501 `asset_write_unavailable`** in production until that PR wires the `onAssetWrite` sink on `LocalServer`.
34
+ - Acceptance criteria (L2-T1, L2-T2, L2-T3) are validated against `fakeCloud` in unit tests; an end-to-end cookbook run against the live `POST /api/im/assets` handler is part of the follow-up.
35
+
36
+ ---
37
+
38
+ ## Unreleased — CLI hardening pass
39
+
40
+ User-reported "大量空洞" — full audit of the 16-verb CLI surface. No new daemon
41
+ behavior; existing commands now fail closed and emit consistent JSON when
42
+ `--json` is set.
43
+
44
+ ### Fixed
45
+
46
+ - **`--json` was dead code on every subcommand.** `applyCommonFlags` stripped
47
+ `--json` from argv before commander parsed per-command options, so
48
+ `if (opts.json) printJson(...)` branches in setup/status/workspace/sandbox/
49
+ asset/cookbook/chat never fired. UI mode was set, but the pretty branches
50
+ silently no-op'd in JSON mode and stdout came out empty (e.g.
51
+ `prismer status --json` exit 0 with no body). Now we keep `--json` in argv
52
+ and declare it on every subcommand that prints — empty-output paths are gone.
53
+ - **`prismer setup --cloud 0.0.0.0:3000` accepted bare host:port and exploded
54
+ with raw Zod JSON six stack frames later.** `normalizeCloudUrl()` now
55
+ auto-prefixes `http://` for bare host shapes and rejects everything else
56
+ with a single-line error. The same helper is wired into `pair`, `setup`,
57
+ and `config set cloud_api_base`.
58
+ - **`exitWithError` is JSON-aware.** When the UI is in JSON mode it emits
59
+ `{ok:false, error:{code, message}}` to stdout (with stable codes like
60
+ `invalid_cloud_url`, `config_missing`, `task_create_failed`) instead of
61
+ the pretty `Error: …` line. Every action handler now goes through a
62
+ `runAction(fn, { code })` wrapper that catches throws — including the
63
+ `loadConfig()` "Config not found" throw that previously bubbled to
64
+ commander's default handler with a `prismer:` prefix.
65
+ - **Daemon ignored application-level `AUTH_FAILED`.** Cloud sends an
66
+ application error frame (not WS close 4001) when the post-handshake API
67
+ key lookup fails; the runner only logged it and stayed alive forever with
68
+ a stale pid file. Now the runner detects `AUTH_FAILED` / `AUTH_REQUIRED`
69
+ / `auth_invalid` payload codes, emits `auth-failed`, and `daemon run`'s
70
+ handler stops the runner, clears the pid file, and exits 2.
71
+ - **`memory stats` returned exit 0 when the gateway was unavailable** even
72
+ though `delete` and `sync` both exit 1 in the same condition. All five
73
+ memory subcommands now consistently set `process.exitCode = 1` when the
74
+ gateway is missing.
75
+ - **`task create` printed `(0): fetch failed`.** Network errors now render
76
+ as `(network error): …` so the `0` HTTP status doesn't leak.
77
+ - **`daemon restart` dropped `--port` / `--foreground` / `--no-local-server`
78
+ on the floor.** Restart now forwards the flags through to `start`.
79
+ - **`daemon logs --tail` read the entire log file into memory.** Now seeks
80
+ from the end in 64 KiB chunks until enough newlines are collected — works
81
+ on the multi-MB logs that long-lived hosts accumulate.
82
+ - **`--no-start` was a redundant declaration** of commander's automatic
83
+ `--no-X` negation; removed.
84
+
85
+ ### Added
86
+
87
+ - **`prismer config (path|show|set)`** — inspect or edit
88
+ `~/.prismer/config.toml` without hand-editing TOML. `show` redacts the
89
+ api_key by default; `--reveal` prints clear text. `set cloud_api_base
90
+ <url>` runs through `normalizeCloudUrl`, `set api_key sk-…` validates
91
+ the key format.
92
+ - **`prismer setup --check`** — dry-run mode. Validates `--cloud`, prints
93
+ the would-be config target and api-key source, and returns without
94
+ touching disk. JSON-friendly: `{ok:true, check:true, mode, cloud, …}`.
95
+ - **Default `--cloud` URL is `https://prismer.cloud`** (was
96
+ `https://cloud.prismer.dev`). The default is now visible in
97
+ `setup --help` / `pair --help`.
98
+ - **Stable error codes** on every CLI exit path so JSON consumers can
99
+ branch on `error.code` rather than parsing `error.message`.
100
+
101
+ ### Internal
102
+
103
+ - New `src/cli/util.ts` helpers: `DEFAULT_CLOUD_BASE_URL`,
104
+ `normalizeCloudUrl(input)`, `runAction(fn, { code, sanitize })`, and the
105
+ JSON-aware `exitWithError(message, { code, exitCode, details })`.
106
+ - `applyCommonFlags` now keeps `--json` in argv (only `--quiet`,
107
+ `--no-color`, `--color` are still stripped). Every subcommand that
108
+ prints JSON now declares `.option('--json', …)` so commander parses it
109
+ consistently; pure-text commands (`daemon stop`, `pair`, `banner`,
110
+ `adapter install / remove`) declare `--json` as a passthrough so
111
+ `prismer --json daemon stop` doesn't error.
112
+
113
+ ## v1.9.3 — 2026-05-07 — Hosted agents + Hermes long-running + 16-verb CLI
114
+
115
+ First published cut of `@prismer/runtime`. The runtime is the TS-only daemon that hosts Prismer agents on a user's Mac (under `launchd`) or inside a sandbox pod (as PID 1). One binary, one WebSocket to cloud, four in-process adapters, local SQLite mirror.
116
+
117
+ ### Added
118
+
119
+ - **CLI: 8 new verbs** — `setup`, `banner`, `chat`, `cookbook`, `asset`, `sandbox`, `memory`, `events` (+ `events:stats`). Plus `workspace` (already shipped). Total surface is now **16 verbs**.
120
+ - `setup` — three onboarding paths (direct API key, `--token <jwt>` mints a daemon-scoped key via `POST /api/keys`, `--pair` delegates to QR/local-only). `--force` archives `local.db` → `local.db.<iso>.bak` when key/cloud/daemon_id changed.
121
+ - `chat` — `me` / `direct` / `messages` / `group (create|send|messages|remove-member)`. Sanitizes `sk-prismer-*` from error messages.
122
+ - `cookbook run` — 54release MVP regression suites (`status` / `im` / `task` / `group` / `asset` / `sandbox`); `--strict` treats skips as failure.
123
+ - `asset` — `list` / `upload` (multipart) / `download` / `get` / `by-hash`.
124
+ - `sandbox` — full `/api/sandboxes` CRUD + `runCmd` + log streaming.
125
+ - `memory` — daemon Memory Gateway first; falls back to read-only view of `~/.prismer/local.db` cache tables when gateway is absent (returns `error.code='memory_gateway_unavailable'` with a fix hint).
126
+ - `events` / `events:stats` — read `~/.prismer/para/events.jsonl` with `--limit / --agent-id / --session-id / --family / --type` filters; stats aggregates `byFamily / byType / byAgentId / bySessionId`.
127
+ - **Hermes long-running adapter** — autostart from `~/.hermes/profiles/<name>/config.yaml`, `/v1/runs` SSE consumer, full `tool.started` / `tool.completed` / `reasoning.available` event handling, Kanban + Goal mirror writeback onto `IMTask.metadata.bridge.hermes`. New runtime dep: `yaml@^2.8.2`. Hermes runs in the user's own Python venv; the runtime stays TS-only.
128
+ - **Hosted-agent pipeline** — `agent.host.declare` payload now stamps `daemonId` onto `IMAgentCard.metadata` so the workspace runtime view groups daemon-declared agents under the right device (instead of `__unbound__`). New `POST /v1/agents/install` LocalServer endpoint + `POST /:id/installAgent` sandbox-controller proxy enable cloud→daemon agent install RPC.
129
+ - **Static binding** — `PRISMER_HOSTED_AGENT_FILE` / `PRISMER_HOSTED_AGENT_JSON` / `PRISMER_STATIC_BINDING_REQUIRED` env vars consumed by `Runner.installStaticHostedAgentFromEnv`. K8s deployments seed one `agents` + `agent_profiles` row before the first `host.declare`.
130
+ - **Daemon-local shell route** — `runtimeRoute='shell'` (or `metadata.execution.kind === 'shell'`) routes through `shell-executor.ts`. Output capping (default 256 KiB, hard max 5 MiB), timeout enforcement (default 60s, hard max 30 min), `allowedWorkspaces` allow-list, `bash|zsh|sh` selector, structured error codes (`shell_disabled`, `shell_workspace_not_allowed`, `shell_command_required`, `shell_cwd_missing`, `shell_spawn_failed`, `shell_timeout`, `task_cancelled`, `shell_exit_nonzero`).
131
+ - **Stuck-task reaper** (60s) + **per-`taskId` dedupe** in `Runner.runningTasks` — closes the failure mode where cloud's `redispatchPending` fires the same task five times during a long LLM call and an upstream gateway half-closes a connection. Reaper aborts past `max(timeoutMs, 5min)` and emits `task.dispatch.reply {ok:false, error.code:'daemon_task_timeout'}`.
132
+ - **30s heartbeat re-declare** — re-sends `agent.host.declare` so cloud's 90s `sweepTimedOut()` doesn't flip status back offline.
133
+ - **Bridge + observability writeback** — dispatch PATCH-merges `result.metadata.hermes` onto `IMTask.metadata.bridge.hermes` (with `lastSyncedAt`) and writes `metadata.observability` with `{identity, memory, goals, lastSyncedAt}`.
134
+ - **8 new tests** under `test/` (Vitest):
135
+ - `asset.test.ts` (240 LOC) — CLI asset CRUD + envelope normalization.
136
+ - `chat-cli.test.ts` (135 LOC) — chat envelope + `sk-prismer` redaction.
137
+ - `cookbook.test.ts` (148 LOC) — suite parsing, summary, strict-skip.
138
+ - `dispatch.test.ts` (265 LOC) — `composePrompt` / `appendGoalContext` / `appendMemoryContext` + full `handleDispatch` path with mocked resolver/cache/ws/service-pool, plus error paths.
139
+ - `hermes-validate.test.ts` (88 LOC) — `hermesAdapter.validate` accepts/rejects port, apiKey, env-var key regex, provider URL.
140
+ - `sandbox.test.ts` (189 LOC) — sandbox CRUD + `runCmd` + logs streaming.
141
+ - `shell-executor.test.ts` (66 LOC) — `resolveShellConfig` defaults + clamping, `isShellDispatch` routing, `executeShellDispatch` enabled/disabled/timeout.
142
+ - `workspace-cli.test.ts` (89 LOC) — `prismer workspace (list|create|get|runtime|files)` envelope unwrapping.
143
+ - **2 opt-in Playwright e2e specs** under `e2e-playwright/specs/`:
144
+ - `workspace-hermes-daemon-runtime.spec.ts` — `WAVE7_HERMES_E2E=1 HERMES_API_KEY=...`. Drives full `pair → register Hermes agent → AgentProfile → host.declare → POST /api/im/tasks → Hermes reply` chain via product APIs only.
145
+ - `workspace-hermes-ui-flow.spec.ts` — `WAVE7_HERMES_UI_E2E=1`. Workspace UI: New Agent dialog → Hermes long-running role → direct session → IM message → reply persisted. Requires a real local daemon on `127.0.0.1:3210`.
146
+
147
+ ### Evolved
148
+
149
+ - **5 existing CLI verbs reworked**: `adapter` (richer install/uninstall + per-adapter register, new `doctor` + `hooks`), `agent` (host register/list/unregister + 6-check `doctor`), `daemon` (`--foreground` for LaunchAgent + log tail-N + follow), `status` (consolidated banner + composite `/healthz` + `/api/im/me` + `local.db` row counts), `task` (tolerant envelope parsing for both `{task:{...}}` and flat shapes; reads `output` from `task.output` or `task.result.output`).
150
+ - **`Runner` + `dispatch` + `LocalServer`** gain hosted-agent paths (~940 lines added across the three files).
151
+
152
+ ### Breaking
153
+
154
+ - **`package.json` `module` + `exports.import` now point at `dist/index.js`** (was `dist/index.mjs`, which `tsup` never actually emitted — bug fix that may affect bundlers respecting the old field).
155
+ - **`yaml@^2.8.2` is a new runtime dependency.** Used by the Hermes adapter to read/write `~/.hermes/profiles/<name>/config.yaml`.
156
+ - **`public/install.sh` strict-pins `@prismer/runtime@1.9.3`** (no caret). Stale 1.8.x installs will not auto-upgrade via curl re-run; users must explicitly re-run the installer.
157
+ - **LaunchAgent plist `ProgramArguments` now include `--foreground`.** Existing 1.8.x installs that loaded the plist without it would respawn-loop unless the user re-runs the installer (which does `bootout` + `bootstrap`).
158
+ - **`agent.host.declare` payload now requires `daemonId`** to be honored by cloud — without it the agent renders under `__unbound__` in the workspace runtime view.
159
+ - **`runtimeRoute` extended** with `'shell'` as a valid value of `TaskDispatchRequestPayload.runtimeRoute`. Cloud-side dispatchers that previously hard-coded `'agent'|'sandbox'` need a passthrough for `'shell'`.
160
+ - **`adapter list` JSON output now includes `installed: { package_manager, package_name, binary, version, installed_at } | null`** field. Strict-shape consumers need an update.
161
+ - **New CLI verbs may shadow user aliases**: `setup`, `banner`, `chat`, `cookbook`, `asset`, `sandbox`, `memory`, `events`, `events:stats`, `workspace`. None overlap with the prior 7-verb shape, but wrapper scripts that did `prismer <unknown>` and got a friendly error will now get command-not-found.
162
+ - **claude-code adapter closes child stdin** (`stdio: ['ignore', 'pipe', 'pipe']`). Operators relying on stdin-mode interactive use of `claude` via the daemon (which was never supported) see no behavior change; this only removes the 3s "no stdin" warning that made daemon dispatches appear hung on `claude` ≥ 2.1.128.
163
+
164
+ ### Fixed
165
+
166
+ - **LaunchAgent KeepAlive respawn loop on macOS** — `install.sh` now passes `--foreground` to `prismer daemon start` in the plist `ProgramArguments`. Without it, `daemon start` spawned a child and exited, `launchd` saw exit-zero, KeepAlive=true respawned immediately. With `--foreground` the binary blocks in the polling loop until `config.toml` appears.
167
+
168
+ ### Internal
169
+
170
+ - `module` / `exports.import` field correctness (`dist/index.js`).
171
+ - `qrcode@^1.5.4` runtime dep added (used by the QR pair flow).
172
+ - `eslint-plugin-react-hooks` added to dev tooling.
173
+
174
+ ---
175
+
176
+ ## v1.8.x — Pre-publish scaffolding
177
+
178
+ The runtime tree was scaffolded across the `feat/refactoring` branch. There were no published cuts before v1.9.3; the package landed at v1.9.3 directly when its public API surface stabilized.