@flumecode/runner 0.23.1 → 0.25.0-preview.39
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/README.md +19 -7
- package/dist/cli.js +1148 -586
- package/dist/mcp-stdio.js +18 -1
- package/package.json +1 -1
- package/skills-plugin/rules/coding-guideline.md +1 -0
- package/skills-plugin/skills/preview-ui/SKILL.md +67 -108
- package/skills-plugin/skills/request-to-plan/SKILL.md +7 -0
- package/skills-plugin/skills/setup-preview/SKILL.md +166 -0
package/dist/mcp-stdio.js
CHANGED
|
@@ -66,6 +66,9 @@ var requirementSchema = z.object({
|
|
|
66
66
|
)
|
|
67
67
|
});
|
|
68
68
|
var planInputSchema = {
|
|
69
|
+
dependsOn: z.array(z.number().int().positive()).optional().describe(
|
|
70
|
+
"1-based positions of EARLIER plans in this same submission that must be merged or closed before this one. Use ONLY when the work must be strictly serial; omit for independent plans."
|
|
71
|
+
),
|
|
69
72
|
title: z.string().min(1).max(120).describe(
|
|
70
73
|
"A concise, descriptive name for THIS plan. Must be distinct from the request title and from any sibling plans on the same request. Keep it under 120 characters."
|
|
71
74
|
),
|
|
@@ -187,6 +190,20 @@ function renderPlan(plan) {
|
|
|
187
190
|
lines.push(PLAN_MARKER);
|
|
188
191
|
return lines.join("\n");
|
|
189
192
|
}
|
|
193
|
+
function validateDependsOnReferences(arr, ctx) {
|
|
194
|
+
for (let i = 0; i < arr.length; i++) {
|
|
195
|
+
const deps = arr[i]?.dependsOn ?? [];
|
|
196
|
+
for (const dep of deps) {
|
|
197
|
+
if (dep > i || dep < 1) {
|
|
198
|
+
ctx.addIssue({
|
|
199
|
+
code: z.ZodIssueCode.custom,
|
|
200
|
+
path: [i, "dependsOn"],
|
|
201
|
+
message: "dependsOn must reference an earlier plan (1-based) in this submission."
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
190
207
|
var submitPlanInputSchema = {
|
|
191
208
|
plans: z.array(requireAtLeastTwoCriteria(requireRootCauseForFix(z.object(planInputSchema)))).min(1).refine(
|
|
192
209
|
(arr) => {
|
|
@@ -194,7 +211,7 @@ var submitPlanInputSchema = {
|
|
|
194
211
|
return new Set(titles).size === titles.length;
|
|
195
212
|
},
|
|
196
213
|
{ message: "Each plan must have a distinct non-empty title" }
|
|
197
|
-
)
|
|
214
|
+
).superRefine(validateDependsOnReferences)
|
|
198
215
|
};
|
|
199
216
|
var submitPlanSchema = z.object(submitPlanInputSchema);
|
|
200
217
|
|
package/package.json
CHANGED
|
@@ -47,3 +47,4 @@ description: >-
|
|
|
47
47
|
## Documentation
|
|
48
48
|
|
|
49
49
|
- When behavior or conventions change, update the matching project docs (`CLAUDE.md` or rule files) in the same PR.
|
|
50
|
+
- FlumeCode plugin recipes (`.flumecode/plugins/*.json`) record how to install, build, run, or preview the app. If your change invalidates one — you altered the install/build/run/dev-server command, how the port or env is supplied, where the app lives (`appDir`), or which files count as the relevant change — update the matching recipe in the same PR so it doesn't go stale. They are not regenerated automatically; a stale recipe silently breaks the capability (e.g. the UI Preview pass) until someone re-installs.
|
|
@@ -1,127 +1,86 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: preview-ui
|
|
3
3
|
description: >-
|
|
4
|
-
Author an ephemeral
|
|
5
|
-
runner can screenshot
|
|
6
|
-
implementation, when the runner provides a
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
Author an ephemeral showcase that renders the recently-changed UI with realistic
|
|
5
|
+
fake data, so the runner can screenshot it in a headless browser. Use after a
|
|
6
|
+
UI-touching implementation, when the runner provides a preview recipe (from the
|
|
7
|
+
repo's ui-preview plugin manifest) and a sentinel-file path. Follows the recipe to
|
|
8
|
+
mount a temporary showcase — including registering a temporary route for
|
|
9
|
+
server-rendered stacks — and records the showcase URL in the sentinel file. The
|
|
10
|
+
showcase is ephemeral: the runner reverts the working tree afterward, so it never
|
|
11
|
+
reaches the pull request.
|
|
9
12
|
---
|
|
10
13
|
|
|
11
14
|
# preview-ui
|
|
12
15
|
|
|
13
|
-
You author a **temporary showcase
|
|
14
|
-
|
|
15
|
-
repo's dev server and take headless screenshots.
|
|
16
|
+
You author a **temporary showcase** that renders the recently-changed UI filled with
|
|
17
|
+
realistic fake data, so the runner can start the app and take headless screenshots.
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
The showcase is **ephemeral**. The runner runs this pass _after_ the implementation is
|
|
20
|
+
already committed, and **reverts the working tree** (tracked and untracked changes) once
|
|
21
|
+
it has captured the screenshots. So you may edit whatever the recipe requires — including
|
|
22
|
+
registering a temporary route in tracked files — and **nothing you write reaches the pull
|
|
23
|
+
request**. Never commit or push.
|
|
19
24
|
|
|
20
25
|
## What you receive
|
|
21
26
|
|
|
22
27
|
The runner injects these into your prompt:
|
|
23
28
|
|
|
24
|
-
-
|
|
25
|
-
(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Choose a URL path unlikely to collide with real routes: `/__flumecode_preview`.
|
|
54
|
-
Write that string (exactly, no trailing newline) to `<tmpRoute>/.showcase-path`.
|
|
55
|
-
|
|
56
|
-
## Step 3 — Author the showcase entry file
|
|
57
|
-
|
|
58
|
-
Create a single route/page file at the correct location under `<tmpRoute>` for
|
|
59
|
-
the detected framework:
|
|
60
|
-
|
|
61
|
-
| Framework | File to create |
|
|
62
|
-
| ---------------------- | ----------------------------------------------------- |
|
|
63
|
-
| Next.js (App Router) | `<tmpRoute>/page.tsx` (if the project uses `app/`) |
|
|
64
|
-
| Next.js (Pages Router) | `<tmpRoute>/index.tsx` (if the project uses `pages/`) |
|
|
65
|
-
| Vite + React | `<tmpRoute>/App.tsx` (or `.jsx`) |
|
|
66
|
-
| Vite + Vue | `<tmpRoute>/App.vue` |
|
|
67
|
-
| Vite + Svelte | `<tmpRoute>/App.svelte` |
|
|
68
|
-
| SvelteKit | `<tmpRoute>/+page.svelte` |
|
|
69
|
-
| Nuxt | `<tmpRoute>/index.vue` |
|
|
70
|
-
| Astro | `<tmpRoute>/index.astro` |
|
|
71
|
-
| CRA | `<tmpRoute>/index.tsx` |
|
|
72
|
-
| Remix | `<tmpRoute>/route.tsx` |
|
|
73
|
-
|
|
74
|
-
**Next.js App Router note:** The runner mounts the showcase at
|
|
75
|
-
`app/__flumecode_preview/page.tsx` by symlinking or copying `<tmpRoute>` to
|
|
76
|
-
`app/__flumecode_preview/`. You only need to produce `<tmpRoute>/page.tsx` — the
|
|
77
|
-
runner handles the mount.
|
|
29
|
+
- **The preview recipe** — from the repo's `.flumecode/plugins/ui-preview.json` manifest
|
|
30
|
+
(written when a repo member initialized the UI Preview plugin). It tells you the app
|
|
31
|
+
directory, the showcase strategy for this stack, and step-by-step instructions for
|
|
32
|
+
where to put the showcase and which URL path it serves at. **Follow it** — it is the
|
|
33
|
+
source of truth for how previews work in this repo. Do not re-detect the framework.
|
|
34
|
+
- **A sentinel file path** — an absolute path. Write the showcase's URL path there.
|
|
35
|
+
- **Changed UI files** — the list of files the implementation changed, so you know what
|
|
36
|
+
to showcase.
|
|
37
|
+
|
|
38
|
+
## Step 1 — Record the URL path first
|
|
39
|
+
|
|
40
|
+
Decide the showcase URL path the recipe specifies (e.g. `/__flumecode_preview`). Write
|
|
41
|
+
that string **exactly** (no trailing newline) to the sentinel file the runner gave you,
|
|
42
|
+
**before** authoring anything else — the runner reads it even if a later step fails.
|
|
43
|
+
|
|
44
|
+
## Step 2 — Author the showcase by following the recipe
|
|
45
|
+
|
|
46
|
+
Do exactly what the recipe's instructions say for this repo's stack. The shape differs by
|
|
47
|
+
stack, but the intent is always the same: a single page/route that renders the changed UI
|
|
48
|
+
with hard-coded fake data, reachable at the URL path from Step 1.
|
|
49
|
+
|
|
50
|
+
- **Drop-in file stacks** (e.g. a Next.js/Vite/Svelte route file): create the showcase
|
|
51
|
+
entry file at the location the recipe names, importing the changed components by their
|
|
52
|
+
real relative paths and filling every prop with realistic fake data.
|
|
53
|
+
- **Server-rendered stacks** (e.g. Django, Rails): also register a **temporary route** so
|
|
54
|
+
the page is reachable — add the URL/route mapping the recipe describes (e.g. a Django
|
|
55
|
+
`urls.py` entry pointing at a throwaway view + template, a Rails route + controller
|
|
56
|
+
action + view). Editing these tracked files is expected and safe; the runner reverts
|
|
57
|
+
them after capture.
|
|
78
58
|
|
|
79
59
|
### Content rules
|
|
80
60
|
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
- If a component
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
showcase.
|
|
101
|
-
- Do not import from test utilities, MSW, Storybook, or Cypress.
|
|
102
|
-
- Do not add new npm dependencies.
|
|
103
|
-
- Do not edit any file outside `<tmpRoute>`.
|
|
104
|
-
- Do not commit or push.
|
|
105
|
-
|
|
106
|
-
## Step 4 — Verify your output
|
|
107
|
-
|
|
108
|
-
Before finishing, confirm:
|
|
109
|
-
|
|
110
|
-
1. `<tmpRoute>/.showcase-path` exists and contains the URL path string.
|
|
111
|
-
2. The showcase entry file exists at the expected path under `<tmpRoute>`.
|
|
112
|
-
3. The file imports only modules that already exist in the repo (no invented
|
|
113
|
-
paths).
|
|
114
|
-
|
|
115
|
-
If you cannot produce a valid showcase (e.g. the components have complex
|
|
116
|
-
dependencies you cannot stub), write only `<tmpRoute>/.showcase-path` with the
|
|
117
|
-
URL string and leave the entry file absent — the runner will detect the missing
|
|
118
|
-
file and skip the screenshot step gracefully.
|
|
61
|
+
- Fill every prop / template variable with **realistic fake data** — hard-coded literals,
|
|
62
|
+
never live calls to a database, API, or external service.
|
|
63
|
+
- If a component needs a provider/context/store, wrap it with a minimal in-file stub — do
|
|
64
|
+
not import the real app store or data layer.
|
|
65
|
+
- If a component or view calls a fetch/route/query, stub it locally with a mock returning
|
|
66
|
+
realistic hard-coded data. Do NOT pull in MSW, Storybook, Cypress, or any test library.
|
|
67
|
+
- Do not add new dependencies — the manifest already declares everything previews need.
|
|
68
|
+
- Keep it short: render all the changed UI in one simple page with a little padding.
|
|
69
|
+
|
|
70
|
+
## Step 3 — Verify before finishing
|
|
71
|
+
|
|
72
|
+
1. The sentinel file contains the showcase URL path.
|
|
73
|
+
2. The showcase entry (and any temporary route registration the stack needs) exists and
|
|
74
|
+
references only modules/paths that already exist in the repo — no invented imports.
|
|
75
|
+
|
|
76
|
+
If you cannot produce a valid showcase (e.g. the changed UI has dependencies you cannot
|
|
77
|
+
reasonably stub), leave only the sentinel file with the URL path and stop — the runner
|
|
78
|
+
detects the missing showcase and reports the preview as needing manual setup rather than
|
|
79
|
+
crashing.
|
|
119
80
|
|
|
120
81
|
## Always
|
|
121
82
|
|
|
122
|
-
- Write the URL path to
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
- Your final reply should be one short sentence confirming what you created (e.g.
|
|
127
|
-
"Wrote `<tmpRoute>/page.tsx` showcasing `Button` and `Card` with fake data.").
|
|
83
|
+
- Write the URL path to the sentinel file **first**, before anything else.
|
|
84
|
+
- The showcase is ephemeral and reverted by the runner. **Never commit or push.**
|
|
85
|
+
- Final reply: one short sentence naming what you created and its URL path (e.g.
|
|
86
|
+
"Showcased `Button` and `Card` at `/__flumecode_preview` via a temporary route.").
|
|
@@ -89,6 +89,7 @@ Field-by-field guidance:
|
|
|
89
89
|
- **`description`** — an array of bullet points that help the reviewer understand the upcoming `pseudoCode` and decide whether the plan and design are correct. Each item is a distinct, self-contained point about what is changing and why — not a single paragraph, and not a line-by-line restatement of the pseudo code. Use concrete file references (`path/to/file.ts`) and name the functions/symbols involved. Apply inline-code formatting to all identifiers.
|
|
90
90
|
- **`pseudoCode`** — an array of `{ file, pseudoCode }` entries. Provide an entry for every file the step touches **except** documentation files (SKILL.md, README.md, wiki pages, etc.). `pseudoCode` is optional in the schema but expected for all non-documentation files. Each entry names the file path and contains pseudo code that precisely describes the changes to make in that file.
|
|
91
91
|
|
|
92
|
+
- **`dependsOn`** — optional. A list of 1-based positions of EARLIER plans in the same `plans[]` call that must be merged or closed before this one can start. Use ONLY when the plans must be worked strictly serially (e.g. a shared refactor that must merge before dependent features can be built on top of it). Omit for independent plans — most plans are independent.
|
|
92
93
|
- **`risks`** — anything that could change the approach or surface a problem.
|
|
93
94
|
- **`outOfScope`** — what you are deliberately not doing.
|
|
94
95
|
|
|
@@ -110,6 +111,12 @@ own independently-acceptable "Accept as plan" draft. After a plan is accepted th
|
|
|
110
111
|
keep commenting to refine it; treat a later turn as a fresh **Plan** phase and call
|
|
111
112
|
`submit_plan` again with a `plans[]` array containing the revised fields.
|
|
112
113
|
|
|
114
|
+
When plans must be worked in a strict order (e.g. plan 1 is a shared refactor that plan 2
|
|
115
|
+
builds on), express this with `dependsOn`: plan 2 sets `dependsOn: [1]`. Accepting the plans
|
|
116
|
+
auto-creates the blocking links between their coding sessions — the order of acceptance does
|
|
117
|
+
not matter. Do **not** use `dependsOn` for plans that can safely run in parallel; rely on
|
|
118
|
+
array order only for documentation, not for enforcement.
|
|
119
|
+
|
|
113
120
|
Before adding an entry to `plans[]`, apply this right-sizing checklist — if a plan fails any criterion, split it into separate entries:
|
|
114
121
|
|
|
115
122
|
- **Single, clear outcome** — one bug fixed, one feature increment, one refactor. If the `title` needs "and", consider splitting.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup-preview
|
|
3
|
+
description: >-
|
|
4
|
+
Set up the FlumeCode UI Preview plugin for a repository. Analyse the app, then
|
|
5
|
+
record how to install it, run its dev server, and mount a temporary showcase page
|
|
6
|
+
into a machine-readable manifest at .flumecode/plugins/ui-preview.json plus a
|
|
7
|
+
human-readable wiki page — and install any packages future previews need. Use when a
|
|
8
|
+
request asks to install/re-initialize the UI Preview plugin. Works for any stack
|
|
9
|
+
(Node, Django, Rails, …): everything
|
|
10
|
+
stack-specific is captured as data in the manifest, so later previews need no
|
|
11
|
+
per-stack code. If previews can't be fully automated, record the manual steps.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# setup-preview
|
|
15
|
+
|
|
16
|
+
You set up the **UI Preview plugin** for this repository: a one-time (re-runnable)
|
|
17
|
+
analysis that records _how to run and preview this app_ so that every later coding
|
|
18
|
+
session can screenshot its UI automatically — for **any** stack, with no per-stack code.
|
|
19
|
+
|
|
20
|
+
You produce two artifacts and commit them (the runner opens the PR):
|
|
21
|
+
|
|
22
|
+
1. **`.flumecode/plugins/ui-preview.json`** — the machine-readable recipe the per-session
|
|
23
|
+
preview pass executes. Its existence is what marks the plugin "initialized".
|
|
24
|
+
2. **A wiki record** — a human-readable `.flumecode/wiki/components/ui-preview.md` page,
|
|
25
|
+
linked from the wiki nav map, documenting the detected stack and how previews work,
|
|
26
|
+
with a sync marker.
|
|
27
|
+
|
|
28
|
+
You may also install/scaffold packages the previews genuinely need (these persist in the
|
|
29
|
+
PR). Do **not** otherwise modify application code.
|
|
30
|
+
|
|
31
|
+
## Step 1 — Understand the app
|
|
32
|
+
|
|
33
|
+
Read the FlumeCode wiki first if it exists (`.flumecode/wiki/README.md`), then confirm
|
|
34
|
+
against the code. Determine:
|
|
35
|
+
|
|
36
|
+
- **The app directory** — the repo root, or a subdirectory / workspace member that holds
|
|
37
|
+
the previewable front-end (e.g. `apps/web`).
|
|
38
|
+
- **The stack** — framework + language (Next.js, Vite, SvelteKit, Django, Rails, …).
|
|
39
|
+
- **Install** — the command(s) that make the app runnable (`pnpm install`,
|
|
40
|
+
`pip install -r requirements.txt`, `bundle install`, …).
|
|
41
|
+
- **Dev server** — the command that serves the app on a port, and how the port is passed.
|
|
42
|
+
- **Hermetic boot** — any env vars needed so the dev server starts without real
|
|
43
|
+
infrastructure (e.g. a throwaway SQLite `DATABASE_URL`, a dummy secret). Previews must
|
|
44
|
+
not depend on production services.
|
|
45
|
+
- **Showcase mounting** — how to add a _temporary_ page that renders arbitrary components
|
|
46
|
+
with fake data, reachable at a URL. For drop-in-file frameworks that's a route file; for
|
|
47
|
+
server-rendered stacks (Django, Rails) it's a temporary route + view + template.
|
|
48
|
+
|
|
49
|
+
## Step 2 — Write `.flumecode/plugins/ui-preview.json`
|
|
50
|
+
|
|
51
|
+
Write the manifest with these fields (the runner fills sane defaults for omitted optionals,
|
|
52
|
+
but be explicit):
|
|
53
|
+
|
|
54
|
+
| Field | Type | Meaning |
|
|
55
|
+
| ------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| `version` | number | Manifest version. Use `1`. |
|
|
57
|
+
| `appDir` | string | App dir relative to repo root (`.` for root). |
|
|
58
|
+
| `install` | string[] | Commands run (in order) before the dev server. Keep idempotent. |
|
|
59
|
+
| `devServer` | string | Dev-server command. Use the token `{PORT}` where the port goes. |
|
|
60
|
+
| `readyPath` | string | Path polled for HTTP readiness once up (usually `/`). |
|
|
61
|
+
| `env` | object (optional) | Extra env for the dev server (hermetic boot). |
|
|
62
|
+
| `uiGlobs` | string[] | Globs that count as a UI change (gates whether a session previews). |
|
|
63
|
+
| `showcase` | object | `{ "kind": "...", "instructions": "..." }` — the recipe the `preview-ui` skill follows each session to author the ephemeral showcase. |
|
|
64
|
+
| `manualSteps` | string (optional) | Set ONLY when you cannot fully automate previews — markdown telling a human what to do. Omit/empty otherwise. |
|
|
65
|
+
|
|
66
|
+
The `showcase.instructions` is the most important field: write **clear, stack-specific,
|
|
67
|
+
step-by-step** instructions a future agent can follow blindly — where to create the
|
|
68
|
+
showcase file(s), which route to register, the exact URL path to serve at, and how to
|
|
69
|
+
import/stub the changed UI. Choose an unlikely URL path such as `/__flumecode_preview`.
|
|
70
|
+
|
|
71
|
+
### Examples
|
|
72
|
+
|
|
73
|
+
**Next.js (App Router) in a monorepo member:**
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"version": 1,
|
|
78
|
+
"appDir": "apps/web",
|
|
79
|
+
"install": ["pnpm install"],
|
|
80
|
+
"devServer": "pnpm next dev -p {PORT}",
|
|
81
|
+
"readyPath": "/",
|
|
82
|
+
"uiGlobs": ["apps/web/**/*.tsx", "apps/web/**/*.css"],
|
|
83
|
+
"showcase": {
|
|
84
|
+
"kind": "next-app-route",
|
|
85
|
+
"instructions": "Create apps/web/app/__flumecode_preview/page.tsx as a client component. Import the changed components by relative path, render them in a column with fake props, and stub any data hooks inline. Serve at /__flumecode_preview."
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Django:**
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"version": 1,
|
|
95
|
+
"appDir": ".",
|
|
96
|
+
"install": ["pip install -r requirements.txt"],
|
|
97
|
+
"devServer": "python manage.py runserver 127.0.0.1:{PORT}",
|
|
98
|
+
"readyPath": "/",
|
|
99
|
+
"env": { "DJANGO_SETTINGS_MODULE": "myproject.settings", "DATABASE_URL": "sqlite:///preview.db" },
|
|
100
|
+
"uiGlobs": ["**/templates/**/*.html", "**/static/**/*.css"],
|
|
101
|
+
"showcase": {
|
|
102
|
+
"kind": "django-urlconf",
|
|
103
|
+
"instructions": "Add a temporary view that renders the changed template(s) with a hard-coded context, register it at path '__flumecode_preview/' in the project urls.py, and ensure ALLOWED_HOSTS permits localhost. Serve at /__flumecode_preview/."
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Ruby on Rails:**
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"version": 1,
|
|
113
|
+
"appDir": ".",
|
|
114
|
+
"install": ["bundle install"],
|
|
115
|
+
"devServer": "bin/rails server -p {PORT} -b 127.0.0.1",
|
|
116
|
+
"readyPath": "/",
|
|
117
|
+
"env": { "RAILS_ENV": "development" },
|
|
118
|
+
"uiGlobs": ["app/views/**/*.erb", "app/assets/**/*.css"],
|
|
119
|
+
"showcase": {
|
|
120
|
+
"kind": "rails-route",
|
|
121
|
+
"instructions": "Add a temporary controller action that assigns hard-coded instance variables and renders the changed view(s), wire it to get '/__flumecode_preview' in config/routes.rb. Serve at /__flumecode_preview."
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Step 3 — Write the wiki record
|
|
127
|
+
|
|
128
|
+
Create or update `.flumecode/wiki/components/ui-preview.md` (and add a row for it in the
|
|
129
|
+
wiki nav map in `README.md`). It documents — for humans — the detected stack, the
|
|
130
|
+
install/run/preview commands, and any manual steps. Begin it with a sync marker so a future
|
|
131
|
+
re-init knows what it last synced to:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
<!-- preview-plugin-synced-to: <current HEAD SHA> -->
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Get the SHA with `git rev-parse HEAD`. Keep the page short and accurate; point at the
|
|
138
|
+
manifest rather than duplicating it.
|
|
139
|
+
|
|
140
|
+
## Step 4 — Install / scaffold what previews need
|
|
141
|
+
|
|
142
|
+
If the app needs a package or config to be previewable (e.g. a dev dependency, a sample
|
|
143
|
+
env file, a static-build config), add it now — these changes persist in the PR so future
|
|
144
|
+
previews don't re-do them. Do not add anything the app doesn't actually need.
|
|
145
|
+
|
|
146
|
+
## Step 5 — Best-effort self-verify
|
|
147
|
+
|
|
148
|
+
If you can, verify the recipe end-to-end without real infrastructure: run `install`, start
|
|
149
|
+
the `devServer` on a free port with `env`, author a trivial showcase per your own
|
|
150
|
+
`showcase.instructions`, and confirm the page renders. Then **revert any throwaway showcase
|
|
151
|
+
edits** — only the manifest, wiki record, and genuinely-needed packaging should remain.
|
|
152
|
+
|
|
153
|
+
## When you cannot fully automate
|
|
154
|
+
|
|
155
|
+
If the app cannot boot for previews without external services (a real database, third-party
|
|
156
|
+
auth, secrets you don't have), do not guess. Set `devServer` to `""` (or still record your
|
|
157
|
+
best attempt) and fill `manualSteps` with concise markdown telling a human exactly what to
|
|
158
|
+
provide. Still write the wiki record. The per-session pass will then report previews as
|
|
159
|
+
needing setup, surfacing your steps, instead of failing opaquely.
|
|
160
|
+
|
|
161
|
+
## Always
|
|
162
|
+
|
|
163
|
+
- Only create/edit files under `.flumecode/` plus the minimal packaging the previews need.
|
|
164
|
+
Never change application logic.
|
|
165
|
+
- Do not commit or push — the runner does. Reply with a one- or two-line summary: the
|
|
166
|
+
detected stack, the commands you recorded, and any manual steps left for a human.
|