@marver-design/marver 0.8.1 → 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 +143 -0
- package/README.md +5 -4
- package/dist/{build-BBVQRetk.mjs → build-Dd91jjIg.mjs} +2 -2
- package/dist/cli.mjs +12 -3
- package/dist/{daemon-DkyNOwIt.mjs → daemon-B_8BmmSJ.mjs} +517 -31
- package/dist/{dev-BTAhTie-.mjs → dev-Dv0GlYQq.mjs} +5 -5
- package/dist/{init-DWdhjJD5.mjs → init-D2EQEbV6.mjs} +21 -5
- package/dist/ledger-BgA7nQoH.mjs +103 -0
- package/dist/{manifest-B4zcDGBf.mjs → manifest-DIsp3ldB.mjs} +173 -16
- package/dist/{plugin-BdQEeTLg.mjs → plugin-CgLVYTR-.mjs} +101 -4
- package/dist/shot-BRgPaFCs.mjs +254 -0
- package/dist/shot-DkkwuCZ2.mjs +29 -0
- package/package.json +2 -2
- package/src/client/frame-host/inspect.js +1 -1
- package/src/client/frame-host/main.tsx +8 -1
- package/src/client/shell/Comments.tsx +1 -1
- package/src/client/shell/styles.css +4 -4
- package/templates/AGENTS-embedded.md +1 -1
- package/templates/AGENTS-studio.md +1 -1
- package/templates/instructions/configure.md +6 -1
- package/templates/instructions/jam.md +114 -12
- package/templates/instructions/welcome.md +7 -1
- package/dist/ledger-CbzTJrV2.mjs +0 -64
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,149 @@
|
|
|
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
|
+
|
|
77
|
+
## 0.9.0 - 2026-08-21
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- **A Live Jam guide** (`docs/live-jam.md`), now that the feature arrives armed rather than
|
|
82
|
+
opted into: how the agent is chosen and how to correct it, every key in the config block,
|
|
83
|
+
what each of the two CLIs is allowed to do, where the trust boundary sits, and what to
|
|
84
|
+
check when a mention does nothing.
|
|
85
|
+
|
|
86
|
+
### Changed
|
|
87
|
+
|
|
88
|
+
- **Live Jam is on by default, at concurrency 6.** Tagging `@marver` in a comment was the
|
|
89
|
+
headline workflow and a config edit stood in front of it. Now it arms itself: the tool
|
|
90
|
+
RUNNING the process wins (its env markers are evidence, and `init` is usually run by the
|
|
91
|
+
agent), then whatever is on PATH, claude first. That last tie-break is a guess, which is
|
|
92
|
+
why the answer is made visible rather than clever - `init` prints the agent it chose and
|
|
93
|
+
writes it into `design/config.ts` in plain sight as
|
|
94
|
+
`jam: { agent: "claude", concurrency: 6 }`, and the generated instructions have the agent
|
|
95
|
+
confirm that line names the tool it actually is. One word to correct, once per repo.
|
|
96
|
+
Workspaces that predate the block need no re-init; they resolve the same way at every
|
|
97
|
+
dev boot. `jam: false` is the off switch, and `jam: "codex"` is shorthand for naming the
|
|
98
|
+
agent. Six frames at once replaces three - at three, half of a multi-frame ask sat
|
|
99
|
+
waiting on the other half while the human watched. With no agent CLI installed, jam stays
|
|
100
|
+
off and both `init` and `marver dev` say so instead of going quiet.
|
|
101
|
+
- **A named agent is never quietly swapped, nor armed when it cannot run.** `jam.agent`
|
|
102
|
+
naming something marver cannot spawn turns Live Jam off with a printed reason rather than
|
|
103
|
+
detecting some other tool and answering the human's comments with it; the same applies
|
|
104
|
+
when the named CLI is not on PATH, which used to claim every mention and then fail it. A
|
|
105
|
+
`design/config.ts` that fails to parse also leaves jam off - it may have said `jam: false`,
|
|
106
|
+
and arming a process spawn against intent we cannot read is the one wrong-way error worth
|
|
107
|
+
avoiding.
|
|
108
|
+
- **`jam.subagents` does something now, and Codex fans out too.** The setting existed but never
|
|
109
|
+
reached the spawned agent, which reads no config - so the parallel-frame policy is stated in
|
|
110
|
+
the job prompt, and turning it off keeps a job on a single agent. The Codex adapter had also
|
|
111
|
+
been marked as having no subagents; `codex exec` carries `collaboration.spawn_agent`, so a
|
|
112
|
+
multi-frame Codex job now fans out the way a Claude Code one does. The prompt only ever says
|
|
113
|
+
"you MAY", so an older CLI without those tools just works serially instead of failing.
|
|
114
|
+
- **Worth knowing, now that it is on by default:** the two agents are locked down differently,
|
|
115
|
+
because their CLIs differ. Claude Code is spawned with shell access removed entirely
|
|
116
|
+
(`--disallowedTools Bash`); Codex runs in its own `workspace-write` sandbox, which bounds
|
|
117
|
+
what commands can *touch* but still lets the model run them. Both are confined to the
|
|
118
|
+
workspace, and every change is a diff you review.
|
|
119
|
+
|
|
120
|
+
### Fixed
|
|
121
|
+
|
|
122
|
+
- **A one-message agent no longer posts the raw reply fence into the thread.** Live Jam posts
|
|
123
|
+
the agent's first streamed message as an immediate ack. Codex emits a single message at the
|
|
124
|
+
very end, carrying the completion block, and a fast Claude Code run can do the same - so the
|
|
125
|
+
ack was the finished reply, fence and all, followed by a second message with the same words.
|
|
126
|
+
The early path now normalizes exactly like the final one, which also makes the existing
|
|
127
|
+
duplicate check catch it: one clean reply.
|
|
128
|
+
|
|
129
|
+
- **The jam ledger and journal are bound to the machine that wrote them.** Both live in
|
|
130
|
+
`design/.local/`, which is gitignored and never synced - but gitignore is a convention,
|
|
131
|
+
not provenance: a repo can force-add its own `.local/` and hand a clone a pre-authorized
|
|
132
|
+
ledger plus a pre-baselined journal. Each line and file now carries a device stamp, so
|
|
133
|
+
jam state that arrived with a clone is read as absent. The stamp is derived from the
|
|
134
|
+
machine, not stored (marver writes nothing outside `design/`), so it stops one repo
|
|
135
|
+
published to everyone rather than someone who already knows your machine - and the larger
|
|
136
|
+
caution is unchanged either way: `marver dev` imports and executes `design/config.ts`, so
|
|
137
|
+
running a dev server in a repo you do not trust is already running its code.
|
|
138
|
+
One-time upgrade cost: an existing journal predates the stamp, so the first boot after
|
|
139
|
+
upgrading rebaselines - any `@marver` mention left unprocessed while the server was down
|
|
140
|
+
is marked seen instead of run. Re-comment to pick it up.
|
|
141
|
+
|
|
142
|
+
- **Comments wear the brand blue.** Pins, thread cards, the comment-mode pick cursor and
|
|
143
|
+
the anchored-thread chrome move off systemGreen. Interact keeps purple, and green is now
|
|
144
|
+
reserved for the done state alone - in dark mode the comment and done greens had drifted
|
|
145
|
+
to the same value, so a frame carrying threads and a frame that had just landed a change
|
|
146
|
+
looked alike. A pin, a thread card and a selected frame are told apart by shape.
|
|
147
|
+
|
|
5
148
|
## 0.8.1 - 2026-08-19
|
|
6
149
|
|
|
7
150
|
### Added
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**The agent-native design canvas.** A `design/` folder in your repo, one command, and a canvas of live frames built from your app's real components and theme. Your coding agent designs by writing files; the tool ships no AI.
|
|
8
8
|
|
|
9
|
-
[marver.design](https://marver.design) · [Deploying a canvas](docs/publish.md) · [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) · [Issues](https://github.com/TNEP4/marver/issues)
|
|
9
|
+
[marver.design](https://marver.design) · [Live Jam](docs/live-jam.md) · [Deploying a canvas](docs/publish.md) · [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) · [Issues](https://github.com/TNEP4/marver/issues)
|
|
10
10
|
|
|
11
11
|
## Quickstart
|
|
12
12
|
|
|
@@ -27,6 +27,7 @@ Frames appear on the canvas the moment the files land. That's the loop.
|
|
|
27
27
|
- **Frames are real code.** Plain TSX/HTML files rendered from your repo's actual components and theme - zero imports from this package required. An approved design promotes into the app by moving a file, not by re-implementing a picture.
|
|
28
28
|
- **Everything hot-reloads.** The agent writes, you watch it land - live.
|
|
29
29
|
- **True viewports.** Each frame is a real iframe: drag its edge and your actual breakpoints fire.
|
|
30
|
+
- **Your agent answers on the canvas.** Tag `@marver` in a comment and it picks up the job, edits the real source, and replies in the thread - no wiring, on by default. See [Live Jam](#live-jam).
|
|
30
31
|
- **No AI inside.** The designer is the coding agent you already run and pay for. `init` generates the `design/AGENTS.md` contract that teaches it the whole workflow.
|
|
31
32
|
|
|
32
33
|
## The canvas
|
|
@@ -45,9 +46,9 @@ Frames appear on the canvas the moment the files land. That's the loop.
|
|
|
45
46
|
|
|
46
47
|
## Live Jam
|
|
47
48
|
|
|
48
|
-
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.
|
|
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.
|
|
49
50
|
|
|
50
|
-
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.
|
|
51
52
|
|
|
52
53
|
## Working state
|
|
53
54
|
|
|
@@ -58,7 +59,7 @@ The same glow, driven from the terminal. When your agent takes a request, it cre
|
|
|
58
59
|
| Command | What it does |
|
|
59
60
|
|---|---|
|
|
60
61
|
| `npx marver init` | Scaffold `design/` in this repo (safe to re-run; refreshes managed files) |
|
|
61
|
-
| `npx marver dev` / `canvas` | Start the local canvas - hot reload, comments, Live Jam (`--port`, default 5199) |
|
|
62
|
+
| `npx marver dev` / `canvas` | Start the local canvas - hot reload, comments, Live Jam armed (`--port`, default 5199) |
|
|
62
63
|
| `npx marver build` | Static export → `design/.dist`; what ships comes from `design/publish.json` (default-closed) |
|
|
63
64
|
| `npx marver serve` | Serve the export; `MARVER_PASSWORD` gates it, `MARVER_DATA_DIR` persists comments + accounts |
|
|
64
65
|
| `npx marver comments …` | The agent's queue: `connect <url>` · `sync` · `list` · `reply` · `resolve` · `invite <email>` · `revoke <email>` |
|
|
@@ -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();
|