@marver-design/marver 0.9.0 → 0.10.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 +72 -0
- package/README.md +2 -2
- package/dist/{build-D9gimz6K.mjs → build-Dd91jjIg.mjs} +2 -2
- package/dist/cli.mjs +12 -3
- package/dist/{daemon-2Lft_lVV.mjs → daemon-B_8BmmSJ.mjs} +486 -15
- package/dist/{dev-CTtkqVo_.mjs → dev-Dv0GlYQq.mjs} +4 -4
- package/dist/{init-8Giknvy1.mjs → init-D2EQEbV6.mjs} +4 -3
- package/dist/{manifest-DJHU7qfu.mjs → manifest-DIsp3ldB.mjs} +44 -12
- package/dist/{plugin-BrBWk2Qn.mjs → plugin-CgLVYTR-.mjs} +100 -3
- package/dist/shot-BRgPaFCs.mjs +254 -0
- package/dist/shot-DkkwuCZ2.mjs +29 -0
- package/package.json +1 -1
- package/src/client/frame-host/main.tsx +8 -1
- package/src/client/shell/Comments.tsx +1 -1
- package/templates/instructions/jam.md +88 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
Notable changes to `@marver-design/marver`. Format follows [Keep a Changelog](https://keepachangelog.com); versions follow semver.
|
|
4
4
|
|
|
5
|
+
## 0.10.0 - 2026-08-21
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Live Jam speaks five more agent CLIs: Cursor, droid (Factory), opencode, grok, and pi**,
|
|
10
|
+
alongside claude and codex - which also covers the apps built on them (Factory drives
|
|
11
|
+
`droid`, Cursor drives `cursor-agent`, Conductor drives `claude`). Each adapter spawns its
|
|
12
|
+
CLI headless with the same posture claude set: edits yes, shell no (or OS-sandboxed) -
|
|
13
|
+
cursor runs with its sandbox forced on and never gets `--force`, droid loses its shell,
|
|
14
|
+
delegation, and connector tools, opencode runs under a per-spawn default-deny permission
|
|
15
|
+
grant, grok has its shell and subagents removed, pi's tool allowlist simply omits bash. Detection knows their env markers (`CURSOR_AGENT`,
|
|
16
|
+
`OPENCODE`, `PI_CODING_AGENT`; droid and grok set none and are found by PATH), and
|
|
17
|
+
`jam: "droid"` in the config block names one exactly as before. The Live Jam guide carries
|
|
18
|
+
the full spawn-and-jail table.
|
|
19
|
+
|
|
20
|
+
- **The verify loop: agents can now SEE what they built.** Field feedback from 0.9.0: a
|
|
21
|
+
jam agent shipped variants that were blank at render time, because no-shell (deliberate -
|
|
22
|
+
the job packet carries untrusted text) also meant no screenshots. The answer is a jailed
|
|
23
|
+
capability, not a shell: `GET /api/shot?frame=<id>&theme=<t>` on the dev server renders
|
|
24
|
+
the frame with the machine's own headless Chrome (CDP over Node's built-in WebSocket -
|
|
25
|
+
zero new dependencies) and returns a PNG under `design/.local/shots/`. Two transports,
|
|
26
|
+
because the no-shell jail rules out the obvious one: a **file-drop inbox** (the agent
|
|
27
|
+
writes a `<slug>.request.json`, the dev server renders and writes a `<slug>.result.json`
|
|
28
|
+
with the PNG path) works for every agent including Claude Code, whose WebFetch refuses
|
|
29
|
+
localhost; and `npx marver shot <frame>` / `GET /api/shot` for shell-ful agents and
|
|
30
|
+
humans. The inbox watcher pairs `fs.watch` with a 1s sweep, so a request lands even on
|
|
31
|
+
filesystems where watching is flaky (macOS temp, network mounts) - the same belt-and-
|
|
32
|
+
braces the comments daemon uses. Readiness is deterministic (root mounted, fonts ready);
|
|
33
|
+
a failed navigation, an unreachable server, or a frame that threw at render all return an
|
|
34
|
+
honest `{ok:false,error}` carrying the real cause (the frame's own exception, surfaced via
|
|
35
|
+
the frame host) rather than a blank that reads as success - so even an agent whose model
|
|
36
|
+
cannot read images still learns from the JSON whether the frame rendered. The generated
|
|
37
|
+
jam instructions require: shoot, read the result, LOOK at the PNG when you can - and say
|
|
38
|
+
so honestly when you cannot. Verified live: Claude Code screenshotted a tour frame through
|
|
39
|
+
the file-drop path and read back its real headline; Claude, Codex, Cursor, grok, and pi
|
|
40
|
+
all read a rendered PNG correctly in isolation (opencode's configured model has no vision,
|
|
41
|
+
and degrades to the JSON signal).
|
|
42
|
+
- **A troubleshooting drill written for the agent, with an upstream loop**
|
|
43
|
+
(`design/instructions/jam.md`): boot line first, then the raw run log in
|
|
44
|
+
`design/.local/jam-logs/`, then the CLI's own headless auth check - fix what belongs to
|
|
45
|
+
the workspace (a wrong `jam.agent`, a logged-out CLI), and file what belongs to marver
|
|
46
|
+
at github.com/TNEP4/marver/issues with the evidence and, when debugging surfaced one,
|
|
47
|
+
the patch. The give-up reply on the canvas now points at the same drill.
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- **The daemon pins `PWD` to the workspace when spawning an agent.** `spawn(cwd:)` changes
|
|
52
|
+
the directory but not the inherited env var, and some CLIs (opencode, verified) trust
|
|
53
|
+
`PWD` over `getcwd` - a dev server whose own cwd differed from the repo root would have
|
|
54
|
+
had the agent editing the wrong directory.
|
|
55
|
+
- **The early ack no longer leaks plan narration into the thread.** A first message like
|
|
56
|
+
"On it...\n\nNow let me gather context: ..." posted the note-to-self along with the ack;
|
|
57
|
+
a fenceless ack is now trimmed to its first paragraph (a fenced first message stays whole).
|
|
58
|
+
- **`/api/shot` is owner/token gated**, so a cross-origin page can't trigger the browser it
|
|
59
|
+
spawns; the `marver shot` CLI sends the dev-session token, and the file-drop jam path is
|
|
60
|
+
unaffected. It also renders from the dev server's actual listening address, not the
|
|
61
|
+
client-supplied Host header. And a hung headless Chrome can no longer wedge the shot queue -
|
|
62
|
+
a watchdog kills it past a deadline and settles every in-flight CDP call.
|
|
63
|
+
- **The working glow follows the agent to the frames it actually builds.** A comment on one
|
|
64
|
+
frame whose answer is several NEW frames ("one frame per page") left the glow stuck on the
|
|
65
|
+
commented frame. Jam agents have no shell to run `marver work`, so the daemon now moves the
|
|
66
|
+
glow itself: it watches which frames the agent creates or edits during the job, lights those,
|
|
67
|
+
and clears the commented frame once the agent is clearly building elsewhere.
|
|
68
|
+
- **Tighter agent jails, verified live.** grok's shell was actually reachable - its deny-list
|
|
69
|
+
named `run_terminal_cmd` but the real tool is `run_terminal_command`, so the flag missed and
|
|
70
|
+
a prompt-injected comment could run commands. grok now uses a read/edit tool ALLOWLIST (no
|
|
71
|
+
shell, no web, no subagents - a name a deny-list can't miss). opencode runs `--pure` so a
|
|
72
|
+
repo plugin can't execute outside its permission grant. Every other CLI's shell containment
|
|
73
|
+
was re-checked against the real binary (Cursor's OS sandbox blocks network egress; pi and
|
|
74
|
+
droid have no shell tool) rather than assumed. The Live Jam guide now states the trust model
|
|
75
|
+
plainly: your own agent, on your machine, every diff reviewed - not an airtight sandbox.
|
|
76
|
+
|
|
5
77
|
## 0.9.0 - 2026-08-21
|
|
6
78
|
|
|
7
79
|
### Added
|
package/README.md
CHANGED
|
@@ -46,9 +46,9 @@ Frames appear on the canvas the moment the files land. That's the loop.
|
|
|
46
46
|
|
|
47
47
|
## Live Jam
|
|
48
48
|
|
|
49
|
-
Tag `@marver` in a comment and your own coding agent picks it up - reads the thread, edits the real frame source, replies with a receipt - while the frame wears a live working glow. Nothing to start and nothing to wire: it rides along with `marver dev`, on by default, armed with whichever agent CLI you have. The tool running the process wins, then whatever is on PATH, and `init` writes what it found into `design/config.ts` as `jam: { agent: "claude", concurrency: 6 }` - visible, one word to correct, `jam: false` to switch off.
|
|
49
|
+
Tag `@marver` in a comment and your own coding agent picks it up - reads the thread, edits the real frame source, replies with a receipt - while the frame wears a live working glow. Nothing to start and nothing to wire: it rides along with `marver dev`, on by default, armed with whichever agent CLI you have - Claude Code, Codex, Cursor, Factory's droid, opencode, grok, or pi, which also covers the apps built on them. The tool running the process wins, then whatever is on PATH, and `init` writes what it found into `design/config.ts` as `jam: { agent: "claude", concurrency: 6 }` - visible, one word to correct, `jam: false` to switch off.
|
|
50
50
|
|
|
51
|
-
The trust boundary is hard: only comments written on the owner's machine trigger (a device-bound ledger - a drive-by comment on a published canvas cannot start work), the agent runs locked down (
|
|
51
|
+
The trust boundary is hard: only comments written on the owner's machine trigger (a device-bound ledger - a drive-by comment on a published canvas cannot start work), the agent runs locked down (each CLI with its shell removed or OS-sandboxed - the per-agent table is in the guide), and every reply carries provenance: which agent ran it, as which dev user, on which model when the agent names one. Marver ships no AI; the agent that acts is the one you already run. The [Live Jam guide](docs/live-jam.md) has the config block, every agent's jail, and what to check when a mention does nothing.
|
|
52
52
|
|
|
53
53
|
## Working state
|
|
54
54
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as ROUTE, n as NAME } from "./cli.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { n as tailwind3Css, r as tailwind4Plugin, t as marverPlugin } from "./plugin-
|
|
2
|
+
import { l as detectHost, r as scanFrames, s as loadConfig } from "./manifest-DIsp3ldB.mjs";
|
|
3
|
+
import { n as tailwind3Css, r as tailwind4Plugin, t as marverPlugin } from "./plugin-CgLVYTR-.mjs";
|
|
4
4
|
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { basename, dirname, join, sep } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
package/dist/cli.mjs
CHANGED
|
@@ -39,14 +39,14 @@ function version() {
|
|
|
39
39
|
}
|
|
40
40
|
const cli = cac(NAME);
|
|
41
41
|
cli.command("init", "Scaffold design/ in this repo").option("--mode <mode>", "studio | embedded", { default: "studio" }).option("--no-demo", "Skip the demo scene (the demo ships unless this flag is passed)").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
|
|
42
|
-
const { init } = await import("./init-
|
|
42
|
+
const { init } = await import("./init-D2EQEbV6.mjs");
|
|
43
43
|
init(resolve(opts.root), {
|
|
44
44
|
mode: opts.mode === "embedded" ? "embedded" : "studio",
|
|
45
45
|
demo: opts.demo !== false
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
48
|
for (const [name, desc] of [["dev", "Start the local canvas (everything on: hot reload, comments, Live Jam)"], ["canvas", "Start the local canvas - same as dev"]]) cli.command(name, desc).option("--root <dir>", "Host repo root", { default: "." }).option("--port <port>", "Port (default 5199)").action(async (opts) => {
|
|
49
|
-
const { dev } = await import("./dev-
|
|
49
|
+
const { dev } = await import("./dev-Dv0GlYQq.mjs");
|
|
50
50
|
let port;
|
|
51
51
|
if (opts.port !== void 0) {
|
|
52
52
|
const n = Number(opts.port);
|
|
@@ -56,7 +56,7 @@ for (const [name, desc] of [["dev", "Start the local canvas (everything on: hot
|
|
|
56
56
|
await dev(resolve(opts.root), port);
|
|
57
57
|
});
|
|
58
58
|
cli.command("build", "Static export → design/.dist (what ships comes from design/publish.json - publishing is default-closed)").option("--boards <names>", "Publish only these boards (comma-separated); overrides the publish policy").option("--all-boards", "Publish every board - the loud override for the default-closed policy").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
|
|
59
|
-
const { buildSite } = await import("./build-
|
|
59
|
+
const { buildSite } = await import("./build-Dd91jjIg.mjs");
|
|
60
60
|
try {
|
|
61
61
|
const boards = opts.boards === void 0 ? void 0 : typeof opts.boards === "string" ? opts.boards : "";
|
|
62
62
|
await buildSite(resolve(opts.root), boards, opts.allBoards === true);
|
|
@@ -92,6 +92,15 @@ cli.command("work <action> [...frames]", "Working state on the canvas: start <sc
|
|
|
92
92
|
process.exit(1);
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
|
+
cli.command("shot <frame>", "Render one frame headless and print the PNG path (needs `dev` running)").option("--root <dir>", "Host repo root", { default: "." }).option("--theme <name>", "Theme to render (default: light)").action(async (frame, opts) => {
|
|
96
|
+
const { shotCommand } = await import("./shot-DkkwuCZ2.mjs");
|
|
97
|
+
try {
|
|
98
|
+
await shotCommand(resolve(opts.root), frame, opts);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(`[${NAME}] ${err.message}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
95
104
|
cli.help();
|
|
96
105
|
cli.version(version());
|
|
97
106
|
cli.parse();
|