modelroom 0.0.5 → 0.1.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 +15 -0
- package/README.md +40 -8
- package/dist/bin/modelroom.js +241 -75
- package/dist/bin/modelroom.js.map +1 -1
- package/dist/lib/agents/index.d.ts +6 -0
- package/dist/lib/agents/index.d.ts.map +1 -1
- package/dist/lib/agents/index.js +22 -4
- package/dist/lib/agents/index.js.map +1 -1
- package/dist/lib/artifact.d.ts +1 -1
- package/dist/lib/artifact.d.ts.map +1 -1
- package/dist/lib/artifact.js +9 -5
- package/dist/lib/artifact.js.map +1 -1
- package/dist/lib/config.d.ts +17 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +40 -4
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/frontmatter.d.ts +2 -0
- package/dist/lib/frontmatter.d.ts.map +1 -1
- package/dist/lib/frontmatter.js +11 -2
- package/dist/lib/frontmatter.js.map +1 -1
- package/dist/lib/i18n.d.ts +315 -0
- package/dist/lib/i18n.d.ts.map +1 -0
- package/dist/lib/i18n.js +651 -0
- package/dist/lib/i18n.js.map +1 -0
- package/dist/lib/lang.d.ts +4 -0
- package/dist/lib/lang.d.ts.map +1 -0
- package/dist/lib/lang.js +5 -0
- package/dist/lib/lang.js.map +1 -0
- package/dist/lib/lint.d.ts +3 -0
- package/dist/lib/lint.d.ts.map +1 -1
- package/dist/lib/lint.js +22 -12
- package/dist/lib/lint.js.map +1 -1
- package/dist/lib/locale.d.ts +9 -0
- package/dist/lib/locale.d.ts.map +1 -0
- package/dist/lib/locale.js +32 -0
- package/dist/lib/locale.js.map +1 -0
- package/dist/lib/opencode.d.ts +31 -1
- package/dist/lib/opencode.d.ts.map +1 -1
- package/dist/lib/opencode.js +83 -1
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/server.d.ts +3 -0
- package/dist/lib/server.d.ts.map +1 -1
- package/dist/lib/server.js +79 -36
- package/dist/lib/server.js.map +1 -1
- package/dist/lib/templates.d.ts +7 -0
- package/dist/lib/templates.d.ts.map +1 -0
- package/dist/lib/templates.js +30 -0
- package/dist/lib/templates.js.map +1 -0
- package/docs/02-convention.md +10 -5
- package/docs/03-cli.md +59 -14
- package/docs/04-agents.md +27 -3
- package/package.json +9 -19
- package/templates/{AGENTS.md → en/AGENTS.md} +8 -3
- package/templates/ja/AGENTS.md +38 -0
- package/templates/ja/room/BEHAVIOUR.md +18 -0
- package/templates/ja/room/BRIEF.md +16 -0
- package/templates/ja/room/SPEC.md +9 -0
- package/templates/ja/room/index.html +53 -0
- package/templates/modelroom.json +3 -1
- package/ui/assets/app.js +120 -47
- package/ui/dashboard.html +11 -7
- package/ui/kit.html +13 -9
- package/ui/modelroom.css +1 -2
- package/ui/room.html +11 -7
- package/ui/settings.html +11 -7
- /package/templates/{room → en/room}/BEHAVIOUR.md +0 -0
- /package/templates/{room → en/room}/BRIEF.md +0 -0
- /package/templates/{room → en/room}/SPEC.md +0 -0
- /package/templates/{room → en/room}/index.html +0 -0
package/docs/04-agents.md
CHANGED
|
@@ -38,11 +38,26 @@ Two things are worth knowing, both learned the hard way:
|
|
|
38
38
|
environment, which is what makes provider keys visible to it. If your shared service already
|
|
39
39
|
has keys, either setting works.
|
|
40
40
|
|
|
41
|
+
### What the chat shows
|
|
42
|
+
|
|
43
|
+
modelroom runs the agent, but it does not read the *turn* out of the CLI's prose. While the
|
|
44
|
+
process is alive, opencode's session already describes that turn — the text, the reasoning, one
|
|
45
|
+
entry per tool call, and the patch an edit wrote — and modelroom follows that instead. So a tool
|
|
46
|
+
call is a row you can open, an edit shows its diff, reasoning folds away, and the CLI's own
|
|
47
|
+
output stays in the run log. It is the same session the panel reads, asked about once a second.
|
|
48
|
+
|
|
49
|
+
If the session cannot be reached, or the adapter has no such place to look, the chat is exactly
|
|
50
|
+
what the process printed. That is the `command` adapter, and it is why `structured` exists.
|
|
51
|
+
|
|
52
|
+
The agent runs with its working directory set to `cfg.rootDir` — for a new
|
|
53
|
+
install, `modelroom/`. That is where it reads `AGENTS.md`, and it is the whole
|
|
54
|
+
tree modelroom will serve under `/files/...`.
|
|
55
|
+
|
|
41
56
|
Agents that need to *write* only the room's files should be scoped on their side, for example
|
|
42
57
|
with OpenCode `permissions`:
|
|
43
58
|
|
|
44
59
|
```yaml
|
|
45
|
-
#
|
|
60
|
+
# modelroom/.opencode/agents/design.md
|
|
46
61
|
permissions:
|
|
47
62
|
- { action: "*", resource: "*", effect: deny }
|
|
48
63
|
- { action: read, resource: "rooms/*", effect: allow }
|
|
@@ -63,7 +78,11 @@ For anything else — Claude Code, Codex, a local model, a shell script:
|
|
|
63
78
|
```
|
|
64
79
|
|
|
65
80
|
`{session}` is substituted with the room's session id. Sessions are stored per room in
|
|
66
|
-
`.modelroom/state.json
|
|
81
|
+
`.modelroom/state.json` at the project root; **new session** in the room UI starts a fresh one.
|
|
82
|
+
|
|
83
|
+
The generated `AGENTS.md` tells the agent which language to write the room's prose in, and
|
|
84
|
+
that frontmatter keys and promise ids stay in English. Change `lang` in `modelroom.json`
|
|
85
|
+
to change that language for new rooms and for the UI; existing documents are not rewritten.
|
|
67
86
|
|
|
68
87
|
## Writing an adapter
|
|
69
88
|
|
|
@@ -72,6 +91,7 @@ An adapter is one object:
|
|
|
72
91
|
```js
|
|
73
92
|
export const mine = {
|
|
74
93
|
name: 'mine',
|
|
94
|
+
structured: false, // true only if the turn can be read while it still runs
|
|
75
95
|
newSessionId: () => `ses_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`,
|
|
76
96
|
run({ cfg, cwd, prompt, sessionId, onChunk, onExit }) {
|
|
77
97
|
// spawn your CLI; stream output with onChunk('stdout'|'stderr', text)
|
|
@@ -80,9 +100,13 @@ export const mine = {
|
|
|
80
100
|
};
|
|
81
101
|
```
|
|
82
102
|
|
|
83
|
-
Add it to `lib/agents/index.
|
|
103
|
+
Add it to `lib/agents/index.ts`. Three rules keep adapters honest:
|
|
84
104
|
|
|
85
105
|
1. **Close stdin** (`stdio: ['ignore', 'pipe', 'pipe']`). A CLI that reads stdin will hang
|
|
86
106
|
forever if the pipe stays open.
|
|
87
107
|
2. **Do not parse the output into meaning.** modelroom shows the agent's words as they are.
|
|
88
108
|
Interpretation belongs to the person reading the room.
|
|
109
|
+
3. **`structured: true` is a claim that the turn can be read while the run is in progress** —
|
|
110
|
+
that the agent keeps it somewhere modelroom can ask for it. Only one adapter makes that
|
|
111
|
+
claim today, and the reading lives in `lib/opencode.ts` (`sessionParts`). If the claim is
|
|
112
|
+
wrong, the agent's *prose* lands in the chat and nothing else breaks.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modelroom",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A local workspace to design UI screens with any coding agent — one room per screen: BRIEF, SPEC, BEHAVIOUR and the artifact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-agnostic",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"build": "npm run build:server && npm run build:web && npm run build:css",
|
|
54
54
|
"build:server": "tsc -p tsconfig.build.json",
|
|
55
55
|
"build:web": "node scripts/build-web.mjs",
|
|
56
|
-
"build:css": "
|
|
56
|
+
"build:css": "esbuild src/modelroom.css --bundle --minify --outfile=ui/modelroom.css --target=es2022",
|
|
57
57
|
"dev:web": "node scripts/build-web.mjs --dev --watch",
|
|
58
|
-
"dev:css": "
|
|
58
|
+
"dev:css": "esbuild src/modelroom.css --bundle --outfile=ui/modelroom.css --watch --target=es2022",
|
|
59
59
|
"lint": "oxlint",
|
|
60
60
|
"lint:types": "oxlint --type-aware",
|
|
61
61
|
"format": "oxfmt",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"test": "vitest run --coverage",
|
|
65
65
|
"test:watch": "vitest",
|
|
66
66
|
"verify": "npm run lint && npm run lint:types && npm run format:check && npm run typecheck && npm test && npm run build",
|
|
67
|
+
"verify:ui": "node scripts/verify-ui.mjs",
|
|
67
68
|
"prepublishOnly": "npm run build"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
@@ -75,19 +76,14 @@
|
|
|
75
76
|
"@codemirror/state": "^6.7.6",
|
|
76
77
|
"@codemirror/view": "^6.43.14",
|
|
77
78
|
"@lezer/highlight": "^1.2.5",
|
|
78
|
-
"@
|
|
79
|
-
"@
|
|
80
|
-
"@
|
|
81
|
-
"@radix-ui/react-tabs": "^1.2.1",
|
|
82
|
-
"@radix-ui/react-toggle-group": "^1.2.1",
|
|
83
|
-
"@tailwindcss/cli": "^4.3.3",
|
|
84
|
-
"@tailwindcss/typography": "^0.5.20",
|
|
79
|
+
"@mantine/core": "^9.7.3",
|
|
80
|
+
"@mantine/hooks": "^9.7.3",
|
|
81
|
+
"@tanstack/react-virtual": "^3.14.21",
|
|
85
82
|
"@types/node": "^26.6.5",
|
|
86
83
|
"@types/react": "^19.3.0",
|
|
87
84
|
"@types/react-dom": "^19.3.0",
|
|
88
85
|
"@vitest/coverage-v8": "^5.0.5",
|
|
89
|
-
"
|
|
90
|
-
"clsx": "^2.1.1",
|
|
86
|
+
"axe-core": "^4.14.0",
|
|
91
87
|
"esbuild": "^0.28.2",
|
|
92
88
|
"highlight.js": "^11.12.0",
|
|
93
89
|
"lefthook": "^2.2.2",
|
|
@@ -101,16 +97,10 @@
|
|
|
101
97
|
"react": "^19.3.1",
|
|
102
98
|
"react-dom": "^19.3.1",
|
|
103
99
|
"react-resizable-panels": "^3.0.6",
|
|
104
|
-
"tailwind-merge": "^3.7.0",
|
|
105
|
-
"tailwindcss": "^4.3.3",
|
|
106
100
|
"typescript": "^7.0.2",
|
|
107
101
|
"vitest": "^5.0.5"
|
|
108
102
|
},
|
|
109
|
-
"overrides": {
|
|
110
|
-
"postcss-selector-parser": "^7.1.6"
|
|
111
|
-
},
|
|
112
103
|
"engines": {
|
|
113
104
|
"node": ">=22.18"
|
|
114
|
-
}
|
|
115
|
-
"//": "postcss-selector-parser is overridden to 7.x: @tailwindcss/typography pins ^6, where GHSA-rj75-hqrm-r3gf lives with no 6.x fix. It is a build-time parser, and `npm run build:css` checks the result."
|
|
105
|
+
}
|
|
116
106
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
This repository uses [modelroom](https://github.com/modelroom/modelroom): one room per screen,
|
|
4
4
|
with the reason, the invisible spec, the promises and the artifact kept apart.
|
|
5
5
|
|
|
6
|
+
You are working inside the design layer (`modelroom/`). Write the room's prose in English.
|
|
7
|
+
|
|
6
8
|
## Where you may write
|
|
7
9
|
|
|
8
10
|
- `rooms/<room>/BRIEF.md` — why this room exists
|
|
@@ -10,7 +12,8 @@ with the reason, the invisible spec, the promises and the artifact kept apart.
|
|
|
10
12
|
- `rooms/<room>/BEHAVIOUR.md` — what it promises (operations and results)
|
|
11
13
|
- `rooms/<room>/index.html` — the artifact itself
|
|
12
14
|
|
|
13
|
-
Nothing else. Do not
|
|
15
|
+
Nothing else. Do not reach outside this directory; the design layer never reads the
|
|
16
|
+
application code. The application is handed this layer, not the other way round.
|
|
14
17
|
|
|
15
18
|
## How to work
|
|
16
19
|
|
|
@@ -25,7 +28,9 @@ Nothing else. Do not touch the application code from here; the design layer neve
|
|
|
25
28
|
|
|
26
29
|
## Conventions
|
|
27
30
|
|
|
28
|
-
-
|
|
29
|
-
|
|
31
|
+
- Frontmatter keys (`title`, `status`, `summary`, `tags`) and promise ids (`@verb-1`) stay
|
|
32
|
+
in English, whatever language the prose uses.
|
|
33
|
+
- Add `status: draft|review|adopted` to `BRIEF.md` when you want the dashboard to show a
|
|
34
|
+
state. Changing it to `adopted` is a human decision, not yours.
|
|
30
35
|
|
|
31
36
|
See `docs/02-convention.md` in the modelroom package for the reasoning.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# AGENTS.md — デザインレイヤー
|
|
2
|
+
|
|
3
|
+
このリポジトリは [modelroom](https://github.com/modelroom/modelroom) を使っています。
|
|
4
|
+
1画面につき1つの room を作り、理由・見えない仕様・約束・artifact を分けて保ちます。
|
|
5
|
+
|
|
6
|
+
あなたはデザインレイヤー(`modelroom/`)の中で作業しています。room の文章は日本語で書いてください。
|
|
7
|
+
|
|
8
|
+
## 書き込んでよい場所
|
|
9
|
+
|
|
10
|
+
- `rooms/<room>/BRIEF.md` — この room が存在する理由
|
|
11
|
+
- `rooms/<room>/SPEC.md` — artifact では見えないこと(デバイス、状態、制約、使ってよいもの)
|
|
12
|
+
- `rooms/<room>/BEHAVIOUR.md` — 何を約束するか(操作と結果)
|
|
13
|
+
- `rooms/<room>/index.html` — artifact そのもの
|
|
14
|
+
|
|
15
|
+
それ以外は書き込まないでください。このディレクトリの外には出ないでください。
|
|
16
|
+
デザインレイヤーはアプリケーションのコードを読みません。アプリケーションに渡すのは
|
|
17
|
+
このレイヤーであり、その逆ではありません。
|
|
18
|
+
|
|
19
|
+
## 進め方
|
|
20
|
+
|
|
21
|
+
1. まず room の `BRIEF.md` を読み、次に `SPEC.md` と `BEHAVIOUR.md` を読みます。
|
|
22
|
+
2. それらに合うように artifact を変えます。仕様が間違っているなら、黙って書き換えず、
|
|
23
|
+
間違っていると伝えてください。
|
|
24
|
+
3. artifact は自己完結にします。CDN、Webフォント、フレームワーク、ビルド手順は使いません。
|
|
25
|
+
実装に渡すものなので、単体で成立する必要があります。
|
|
26
|
+
4. `SPEC.md` に、artifact を見れば分かることを書き直さないでください。同じ約束を2つの
|
|
27
|
+
ファイルにコピーせず、id(`@verb-1`)で参照します。
|
|
28
|
+
5. 実際のシステムが必要とする約束(レコード、タイムスタンプ、権限)は、このレイヤーには
|
|
29
|
+
置きません。
|
|
30
|
+
|
|
31
|
+
## 決まりごと
|
|
32
|
+
|
|
33
|
+
- frontmatter のキー(`title`、`status`、`summary`、`tags`)と約束の id(`@verb-1`)は、
|
|
34
|
+
文章がどの言語でも英語のままにします。
|
|
35
|
+
- ダッシュボードに状態を出したいときは、`BRIEF.md` に `status: draft|review|adopted` を
|
|
36
|
+
足します。`adopted` に変えるのは人間の判断で、あなたの判断ではありません。
|
|
37
|
+
|
|
38
|
+
理由は modelroom パッケージの `docs/02-convention.md` にあります。
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# {{room}} — 振る舞い
|
|
2
|
+
|
|
3
|
+
この room が約束すること: 操作と結果。コードではなく、仕事の言葉で書きます。
|
|
4
|
+
|
|
5
|
+
```gherkin
|
|
6
|
+
機能: {{room}}
|
|
7
|
+
|
|
8
|
+
@first-1
|
|
9
|
+
シナリオ: 最初の約束
|
|
10
|
+
前提 何かの開始点
|
|
11
|
+
もし 人が何かをする
|
|
12
|
+
ならば 観測できることが起きる
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
メモ
|
|
16
|
+
- 約束ごとに1つの id(`@<verb>-<n>`)を付け、1つのシナリオに1つの約束を書きます。
|
|
17
|
+
- 実際のシステムが必要とする約束(レコード、タイムスタンプ、権限)は、このファイルではなく
|
|
18
|
+
アプリケーションに属します。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: {{room}}
|
|
3
|
+
status: draft
|
|
4
|
+
version: 1
|
|
5
|
+
summary: 次に読む人が判断できる一言。
|
|
6
|
+
tags: []
|
|
7
|
+
---
|
|
8
|
+
# {{room}}
|
|
9
|
+
|
|
10
|
+
この room はなぜ存在するのか。誰のためで、何が成り立っていれば作る価値があるのか。
|
|
11
|
+
優先順位と、あえてやらないことを書いてください。
|
|
12
|
+
|
|
13
|
+
- **誰のため:**
|
|
14
|
+
- **なぜ:**
|
|
15
|
+
- **いちばん大事なこと:**
|
|
16
|
+
- **やらないこと:**
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!-- {{room}} — artifact(実装に渡すもの)
|
|
3
|
+
意図的に自己完結: CDN なし、フレームワークなし、ビルドなし。 -->
|
|
4
|
+
<html lang="ja">
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="utf-8">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
+
<title>{{room}}</title>
|
|
9
|
+
<style>
|
|
10
|
+
:root {
|
|
11
|
+
--bg: #faf9f7;
|
|
12
|
+
--surface: #ffffff;
|
|
13
|
+
--text: #1c1917;
|
|
14
|
+
--muted: #78716c;
|
|
15
|
+
--line: #e7e5e4;
|
|
16
|
+
--primary: #1c1917;
|
|
17
|
+
--primary-text: #fafaf9;
|
|
18
|
+
--radius: 16px;
|
|
19
|
+
--space: 24px;
|
|
20
|
+
}
|
|
21
|
+
* { box-sizing: border-box; }
|
|
22
|
+
html, body { height: 100%; }
|
|
23
|
+
body {
|
|
24
|
+
margin: 0; display: grid; place-items: center; padding: 40px 20px; background: var(--bg); color: var(--text);
|
|
25
|
+
font-family: "Hiragino Kaku Gothic ProN", "Hiragino Sans", "Noto Sans JP", system-ui, sans-serif;
|
|
26
|
+
line-height: 1.7;
|
|
27
|
+
}
|
|
28
|
+
.card {
|
|
29
|
+
width: min(520px, 100%); background: var(--surface); border: 1px solid var(--line);
|
|
30
|
+
border-radius: var(--radius); padding: var(--space); display: flex; flex-direction: column; gap: var(--space);
|
|
31
|
+
}
|
|
32
|
+
h1 { font-size: 22px; margin: 0; letter-spacing: .01em; }
|
|
33
|
+
p { margin: 0; color: var(--muted); font-size: 15px; }
|
|
34
|
+
.actions { display: flex; gap: 12px; flex-wrap: wrap; }
|
|
35
|
+
button {
|
|
36
|
+
font: inherit; padding: 14px 22px; border-radius: var(--radius); border: 1px solid var(--line);
|
|
37
|
+
background: var(--surface); color: var(--text); cursor: pointer;
|
|
38
|
+
}
|
|
39
|
+
button.primary { background: var(--primary); color: var(--primary-text); border-color: var(--primary); }
|
|
40
|
+
</style>
|
|
41
|
+
</head>
|
|
42
|
+
<body>
|
|
43
|
+
<main class="card">
|
|
44
|
+
<h1>{{room}}</h1>
|
|
45
|
+
<p>これは room の artifact です。チャットから置き換えるか、手で書いてください。
|
|
46
|
+
仕様と約束は隣の SPEC.md と BEHAVIOUR.md にあります。</p>
|
|
47
|
+
<div class="actions">
|
|
48
|
+
<button class="primary">主なアクション</button>
|
|
49
|
+
<button>副次的なアクション</button>
|
|
50
|
+
</div>
|
|
51
|
+
</main>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|