@monster-orange/den 0.4.17 → 0.4.19

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 (49) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/README.md +14 -13
  3. package/docs/distributions.md +138 -25
  4. package/docs/reference.md +1 -1
  5. package/package.json +2 -1
  6. package/skills/install-den/SKILL.md +35 -75
  7. package/src/shared/agents/den-claude.ts +40 -6
  8. package/src/shared/agents/guardrails/stop-hook.ts +30 -4
  9. package/src/shared/agents/guardrails.ts +40 -4
  10. package/src/shared/agents/handback.ts +22 -4
  11. package/src/shared/agents/personas.ts +32 -5
  12. package/src/shared/agents/runtime.ts +8 -0
  13. package/src/shared/agents/server-agent.ts +57 -0
  14. package/src/shared/agents/server-pack/server.md +45 -0
  15. package/src/shared/environment-manager/workspaces.ts +4 -0
  16. package/src/ui/cli/agent-ops.ts +84 -6
  17. package/src/ui/cli/create.ts +2 -2
  18. package/src/ui/cli/index.ts +1 -1
  19. package/src/ui/cli/repo-command.ts +8 -1
  20. package/src/ui/cli/repo-detect.ts +58 -0
  21. package/src/ui/cli/server-agent-ops.ts +411 -0
  22. package/src/ui/mcp/server.ts +29 -12
  23. package/src/ui/mcp/tools.ts +4 -2
  24. package/src/ui/server/agent-routes.ts +10 -1
  25. package/src/ui/server/held-actions.ts +35 -7
  26. package/src/ui/server/index.ts +20 -5
  27. package/src/ui/server/public/agents-page.js +33 -1
  28. package/src/ui/server/public/agents.html +13 -0
  29. package/src/ui/server/public/error-page.js +39 -1
  30. package/src/ui/server/public/graph.css +43 -0
  31. package/src/ui/server/public/graph.js +68 -1
  32. package/src/ui/server/public/header.js +36 -7
  33. package/src/ui/server/public/i18n/es.js +72 -0
  34. package/src/ui/server/public/i18n/ja.js +74 -0
  35. package/src/ui/server/public/local-dev.html +33 -3
  36. package/src/ui/server/public/log-source.js +26 -0
  37. package/src/ui/server/public/logs.html +7 -20
  38. package/src/ui/server/public/persona-ui.css +6 -0
  39. package/src/ui/server/public/server-agent-page.js +415 -0
  40. package/src/ui/server/public/server-agent.html +222 -0
  41. package/src/ui/server/public/services.html +18 -3
  42. package/src/ui/server/public/shell.js +274 -31
  43. package/src/ui/server/public/svc-panel.js +685 -0
  44. package/src/ui/server/public/topbar.js +13 -1
  45. package/src/ui/server/route-classes.ts +21 -0
  46. package/src/ui/server/server-agent-routes.ts +176 -0
  47. package/src/ui/server/session-routes.ts +12 -1
  48. package/src/ui/server/ui-assets.ts +6 -0
  49. package/src/ui/server/workspace-routes.ts +3 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,183 @@ All notable changes to Den are documented here. Each release lists the
4
4
  config and manifest changes a distribution must make to move to it under
5
5
  **Migrations**.
6
6
 
7
+ ## [0.4.19] - 2026-11-08
8
+
9
+ ### Added
10
+
11
+ - **The server agent (ON-6).** Every Den has its own agent, named after the
12
+ distribution ("Acme agent"), for anything about the server itself: set it
13
+ up, add a repo, fix a failing service, change a setting, explain what's
14
+ running. It belongs to no workspace. It is a normal Den agent underneath
15
+ (record, session, Resume, rotation, hooks), with Den's persona `server`
16
+ and the plain-writing rule, in a reserved scope, `den-server`.
17
+ - It acts only through Den's MCP, which serves it the whole Den. Each
18
+ write (`workspace_create`, `repo_add`, `service_try`) is held for the
19
+ person's Allow, so it only reads until they allow one. It starts in an
20
+ empty folder of its own (`<state_dir>/server-agent`).
21
+ - A fresh Den's first page (`/`, while no workspace has a repo) is that
22
+ agent in a terminal framed as the page, with Open in Agents. With an
23
+ installed runtime that carries Den's tools, it starts by itself, with
24
+ "Let's set up <name>. Where are your repos?", with the folder above the
25
+ Den's as the default, in its first turn. With none, the page shows how
26
+ to install one and the manual path for this Den, from its folder:
27
+ `cd <dir>` → `./bin/<cli> repo add <path>` → `./bin/<cli> up`.
28
+ - After setup it is in the rail (`/server-agent`), ⌘K has "Ask <name>",
29
+ and Agents lists it first, under "Server".
30
+ - Its runtime: the page's Runs on picker (`agents.server_runtime` in
31
+ `config/local/user.yml`), else the first installed one with Den's tools.
32
+ - Its model: the page's Model picker beside it (`agents.server_model`),
33
+ with only the runtime's own models, else Sonnet when the runtime has it.
34
+ A new model takes effect at the next start (a fresh conversation).
35
+ - Den's own MCP tools run without Claude Code's own prompt, for this
36
+ agent only (`mcp__<server>` in its settings file's `permissions.allow`).
37
+ Reads just run; each write still waits for the person's Allow in the
38
+ browser, so it asks once. The org's immediate actions (`mcp.actions`)
39
+ still ask in the terminal (`permissions.ask`). Workspace agents are
40
+ unchanged.
41
+ - On a fresh Den, one line above its terminal: "Claude asks whether to
42
+ trust this folder. Choose Yes." Den doesn't answer Claude's folder-trust
43
+ prompt for the person.
44
+ - `GET /api/server-agent`, `POST /api/server-agent/start`,
45
+ `POST /api/server-agent/runtime` and `POST /api/server-agent/model`.
46
+ Only a person starts it or picks its runtime or model: an agent's token
47
+ or claim gets 403.
48
+
49
+ ### Changed
50
+
51
+ - **The install-den skill does three things only (ON-1, slimmed).** It
52
+ installs Den after checking Node and git, helps pick its name and folder
53
+ (default `~/<name>`), then runs `web up` and hands over the one-time link
54
+ from `web claim-link`: "Den's own agent takes it from there." It no
55
+ longer adds repos, starts services or connects itself to Den's MCP.
56
+ - **`npx @monster-orange/den@latest create`.** The skill, the README, the
57
+ docs, `create`'s own `fix` lines and `--help` name `@latest`. A bare name
58
+ could reuse an older Den cached in `~/.npm/_npx`.
59
+ - **workspace_create makes the workspace active.** On the person's Allow,
60
+ the MCP's `workspace_create` creates the workspace and activates it, so
61
+ `service_try` can start its services. `service_try` on a workspace that
62
+ isn't active says so in the browser ("Start <service> (this activates
63
+ <workspace>)") and does both on the one Allow. Before, the server agent
64
+ was refused with "Workspace is not active", and nothing it could call
65
+ activated one. `<cli> workspace create` is unchanged.
66
+ - **The drafted manifest has a health URL when the dev server's port is
67
+ known.** `manifest_draft` and `repo add` draft
68
+ `health: { local: { url: http://localhost:<port>/ } }` when the start
69
+ script names a port (`--port`, `-p`, `PORT=`) or runs a dev server with a
70
+ fixed default (Vite 5173, Next 3000, Angular 4200, and a few
71
+ more). So the service gets a health check and Visit ↗. `--health` still
72
+ wins. With no port, nothing is guessed.
73
+ - **The ON-4 dry run follows the two agents:** install, the setup link, the
74
+ fresh first page, then the server agent's MCP calls, with `repo_add` and
75
+ `service_try` each allowed from the signed-in browser. It now asserts 5
76
+ minutes or less.
77
+ - **An accessibility check runs with the tests.** axe-core (WCAG 2.0 and
78
+ 2.1 A and AA, plus best practice) scans the rail, an open pinned-service
79
+ panel, the Start agent dialog and the server agent's page, in light and
80
+ dark, at 1440×900 and 390×844. Any violation fails it.
81
+
82
+ ### Fixed
83
+
84
+ - **No Stop hook error at the end of setup.** The server agent was given the build agents' hand-back template, so
85
+ after the service came up it wrote a hand-back, and Den's Stop hook sent it back because a decision didn't end in
86
+ "?". The person saw "Stop hook error" and waited a turn. The server agent now has no hand-back template, and its
87
+ Stop hook skips the hand-back check. It still asks it to explain every ID, and session rotation is unchanged.
88
+
89
+ - **The Stop hook no longer flags Den's own name.** A Den whose name looks
90
+ like an ID (`t2` → "T2") had the server agent's first greeting rejected
91
+ ("'T2' is not explained"), and the person saw "Stop hook error". Den now
92
+ tells the hook the ID-shaped words in its own title and the workspace's
93
+ name (`--known`), and it never flags those. Any other bare ID is still
94
+ flagged.
95
+ - **No What's new over a brand-new Den.** On a fresh Den (no repo in any
96
+ workspace yet, the server agent page's `fresh`) the release notes no
97
+ longer open by themselves over the agent and the approvals. That version
98
+ counts as seen. `/api/server-info` has `fresh`.
99
+ - **The "log in here" line shows on every fresh run.** The server agent
100
+ page chose the line from the runtime picker's runtime, which can read
101
+ none (or another one) while the agent runs. It now uses the runtime the
102
+ agent runs on (`runningRuntime`, from its record). And a start that isn't
103
+ running yet when the page reads it back is read again, a second apart, so
104
+ the terminal and its lines come up without a reload.
105
+ - **The Graph's empty View says where a service is.** With the View on a
106
+ workspace with no services (right after onboarding), Open in Graph for
107
+ a service in another workspace showed "No services in workspace" only.
108
+ It now also says "<service> is in <workspace>, outside this View." with
109
+ Show <workspace>, the same line as over a drawn graph.
110
+ - **Open Terminal on Windows.** On the signed-out page it did nothing on Windows. Windows has no `ssh://` app by default, so
111
+ there the link is gone and the ssh command is the step: "Open Windows Terminal or PowerShell, paste this, and press
112
+ Enter." Elsewhere, if the page still has focus 2 seconds after the click, it says "Nothing opened? Copy the command
113
+ below and paste it into your terminal app." The command and its copy button always show.
114
+
115
+ - **No "down" flash after Start.** Starting a dev server from the
116
+ pinned-service panel showed "starting…", then "down: fetch failed" for
117
+ a second or two, then up. The server's ready event ended "starting…",
118
+ and the header's next health paint still held the service's down result
119
+ from before Start. Now, while a Start or Restart is in flight, a down
120
+ reads "starting…" until the first up or the 120 s timeout. The ready
121
+ event ends it only when health already says up.
122
+ - **Open in Graph says when a service is outside the View.** With the View
123
+ on one workspace, Open in Graph for a service in another landed on a
124
+ Graph without its card. Now the Graph says "<service> is in
125
+ <workspace>, outside this View." with a Show <workspace> button. The
126
+ button switches the View the way the top bar does, then focuses the
127
+ card. The View never switches by itself.
128
+ - **The phone drawer keeps the rail a nav.** Under 720 px, ☰ made the
129
+ rail's `<nav>` itself a dialog, which a nav may not be. The dialog is
130
+ now a box around the rail ("Pages"); focus, Tab, Esc and the scrim work
131
+ as before.
132
+ - **The chosen persona's role and tag are readable.** On the chosen row's
133
+ tint, in light, they were 4.49:1, under 4.5:1. They read in the muted
134
+ colour there now.
135
+
136
+ ### Migrations
137
+
138
+ - No workspace may be named `den-server`: creating one is refused. Rename a
139
+ workspace with that name before moving to 0.4.19.
140
+
141
+ ## [0.4.18] - 2026-11-08
142
+
143
+ ### Added
144
+
145
+ - **A pinned service opens a quick panel, not a page jump.** A click on a
146
+ pinned service's name in the rail (or Enter on its row, or its dot in
147
+ the collapsed rail) opens a panel beside the row, without leaving the
148
+ page. It has the service's workspace, state and URL; Visit ↗, Start or
149
+ Stop, Restart and Logs, which call what the Services page calls; the
150
+ repo's last test run with Run tests; the agents working in the repo,
151
+ each with Open, and Start agent here; and Open in Services, Open in
152
+ Graph and Unpin. It stays current while open. Esc or a click outside
153
+ closes it and focus goes back to the row. Under 640 px it is a bottom
154
+ sheet. ⌘-click or a middle click still opens Services in a new tab. The
155
+ Services card's name and the Graph card's new ⋯ open the same panel.
156
+ - **Visit ↗ on every pinned row.** Always shown, it opens the service's
157
+ URL in a new tab. It is greyed out ("Not running") while the service is
158
+ down, and absent when the service has no URL. The hover × is gone:
159
+ Unpin is in the panel, and Delete on the row still unpins.
160
+ - **Start agent here.** The Start dialog has a Folder field (optional):
161
+ the agent runs in that folder of the workspace's, or in a repo's
162
+ folder. The route takes it as `folder`, and refuses a folder outside
163
+ the workspace (403). The panel's Start agent here fills the workspace
164
+ and the repo's folder.
165
+ - **Open in Graph focuses the service.** `/graph#focus=<repo>` or
166
+ `#focus=<repo>/<service>` opens the Graph on that card.
167
+
168
+ ### Fixed
169
+
170
+ - **The panel's Logs reads the service's log.** It asks where the Logs
171
+ page asks (taillog for a local service), so a service with no `logs:`
172
+ block no longer says "Connection closed". The Services page's Logs
173
+ uses the same rule.
174
+ - **"starting…" follows health.** After Start or Restart, the panel
175
+ leaves "starting…" once health says up, once it says down after a
176
+ moment, or after two minutes. Restart works again then, even when the
177
+ service's `up` never exits (a dev server).
178
+ - **A pinned row's Visit ↗ greys out with the panel.** It reads the
179
+ panel's live state, so it greys out on the same health update, also
180
+ for a service outside the top bar's View.
181
+ - **Open in Graph keeps its target.** The Graph page keeps the URL's
182
+ `#focus=` when it picks a workspace, so the card is focused and in view.
183
+
7
184
  ## [0.4.17] - 2026-11-08
8
185
 
9
186
  ### Fixed
package/README.md CHANGED
@@ -10,8 +10,8 @@
10
10
  </p>
11
11
 
12
12
  <picture>
13
- <source media="(prefers-color-scheme: dark)" srcset="docs/images/0.4.17/hero-dark.png">
14
- <img src="docs/images/0.4.17/hero-light.png" width="100%" alt="Den's Graph page: the demo workspace's services grouped by application, all healthy, with the status chip and the left rail">
13
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/0.4.19/hero-dark.png">
14
+ <img src="docs/images/0.4.19/hero-light.png" width="100%" alt="Den's Graph page: the demo workspace's services grouped by application, all healthy, with the status chip and the left rail">
15
15
  </picture>
16
16
 
17
17
  ## Set up by your agent
@@ -22,11 +22,12 @@ Paste this line into your coding agent (Claude Code, Codex, Gemini, Grok, …):
22
22
  Set up Den for me by following https://raw.githubusercontent.com/Monster-Orange/den/main/skills/install-den/SKILL.md
23
23
  ```
24
24
 
25
- The agent follows the [install-den skill](skills/install-den/SKILL.md). It asks you at most three questions,
26
- creates your Den, adds one of your repos without changing it, starts it, checks it, and connects itself to Den's
27
- MCP server. Then it tells you what's running and the URL to open. It never asks for a password in chat, never
28
- edits your repos and sends nothing off your machine. Every step it runs answers in JSON and is safe to re-run:
29
- see [Set up by your agent](docs/distributions.md#set-up-by-your-agent).
25
+ The agent follows the [install-den skill](skills/install-den/SKILL.md). It checks Node and git, installs Den,
26
+ asks you its name and folder, starts it, and hands you a one-time link. Open it: your Den's own agent takes it
27
+ from there. That agent finds your repos, adds them without changing them and starts one, and each change waits
28
+ for you to allow it in the browser. Neither agent asks for a password in chat, edits your repos or sends anything
29
+ off your machine. Every step answers in JSON and is safe to re-run: see
30
+ [Set up by your agent](docs/distributions.md#set-up-by-your-agent) and [The server agent](docs/distributions.md#the-server-agent).
30
31
 
31
32
  ## What Den is
32
33
 
@@ -38,7 +39,7 @@ It doesn't replace your tools. Your repos, Docker, your test runners, your secre
38
39
  yours. Den connects them and turns on good practice from the start.
39
40
 
40
41
  <p align="center">
41
- <img src="docs/images/0.4.17/up.gif" width="100%" alt="make up in the Graph page: every stack down, then demo-api, demo-web and demo-notes come up in dependency order until the status chip reads All 3 healthy">
42
+ <img src="docs/images/0.4.19/up.gif" width="100%" alt="make up in the Graph page: every stack down, then demo-api, demo-web and demo-notes come up in dependency order until the status chip reads All 3 healthy">
42
43
  </p>
43
44
 
44
45
  ## How it helps
@@ -68,10 +69,10 @@ yours. Den connects them and turns on good practice from the start.
68
69
  lives in your own repo.
69
70
 
70
71
  <p align="center">
71
- <img src="docs/images/0.4.17/agents.png" width="49%" alt="The Agents tab: the demo workspace's sessions on the left, and one open in a terminal pane on the right, running demo-api's test and then the service">
72
- <img src="docs/images/0.4.17/workspaces.png" width="49%" alt="The Workspaces page: the demo workspace's repos with their health, mode and Start, Stop, Restart and Logs actions">
73
- <img src="docs/images/0.4.17/status-drawer.png" width="49%" alt="The status drawer: nothing needs attention, and every service in the demo workspace, by application, with its latency">
74
- <img src="docs/images/0.4.17/edge.png" width="49%" alt="The Edge page: the edge container up, its ports and TLS, and every route it serves, Den's own and each stack's, with its upstream">
72
+ <img src="docs/images/0.4.19/agents.png" width="49%" alt="The Agents tab: the demo workspace's sessions on the left, and one open in a terminal pane on the right, running demo-api's test and then the service">
73
+ <img src="docs/images/0.4.19/workspaces.png" width="49%" alt="The Workspaces page: the demo workspace's repos with their health, mode and Start, Stop, Restart and Logs actions">
74
+ <img src="docs/images/0.4.19/status-drawer.png" width="49%" alt="The status drawer: nothing needs attention, and every service in the demo workspace, by application, with its latency">
75
+ <img src="docs/images/0.4.19/edge.png" width="49%" alt="The Edge page: the edge container up, its ports and TLS, and every route it serves, Den's own and each stack's, with its upstream">
75
76
  </p>
76
77
 
77
78
  ## Get started
@@ -79,7 +80,7 @@ yours. Den connects them and turns on good practice from the start.
79
80
  You need Node 22.13 or later, and Docker for anything that runs in containers. mkcert is only needed if you want Den to issue local HTTPS certificates.
80
81
 
81
82
  ```sh
82
- npx @monster-orange/den create acme # your own Den, named after your product
83
+ npx @monster-orange/den@latest create acme # your own Den, named after your product
83
84
  cd acme && npm install
84
85
  ./bin/acme register ../shop-api # add a repo (repeat for each one)
85
86
  ./bin/acme up # start everything, in order
@@ -19,8 +19,8 @@ Den's own checkout is itself a distribution, named `den`.
19
19
  ## Create one
20
20
 
21
21
  ```sh
22
- npx @monster-orange/den create acme # writes ./acme
23
- npx @monster-orange/den create acme ~/src/acme-dev --title "Acme Dev"
22
+ npx @monster-orange/den@latest create acme # writes ./acme
23
+ npx @monster-orange/den@latest create acme ~/src/acme-dev --title "Acme Dev"
24
24
  ```
25
25
 
26
26
  From a Den checkout, `./bin/den create acme ../acme` does the same.
@@ -72,26 +72,33 @@ Set up Den for me by following https://raw.githubusercontent.com/Monster-Orange/
72
72
 
73
73
  That file is the install-den skill, also in the package at
74
74
  `skills/install-den/SKILL.md`: plain Markdown any agent can follow, with
75
- Claude skill front matter. `den --help` prints the line. The skill runs the
76
- commands below. Each one takes `--json`, never prompts, and is safe to
75
+ Claude skill front matter. `den --help` prints the line. The skill does three
76
+ things only: it installs Den (after checking Node and git), helps the person
77
+ pick its name and folder (default `~/<name>`), then runs `web up` and hands
78
+ over the one-time link from `web claim-link`: "Den's own agent takes it from
79
+ there." It adds no repo and creates no workspace: that is
80
+ [the server agent](#the-server-agent)'s job. Every command below also stays a
81
+ person's own: `npm i -g @monster-orange/den` → `den create <name>` →
82
+ `<cli> repo add` → `<cli> up` skips both agents. The skill runs the first
83
+ of the commands below, and the server agent the rest through MCP. Each one takes `--json`, never prompts, and is safe to
77
84
  re-run. With `--json`, stdout carries exactly one JSON object and the
78
85
  command's log goes to stderr. When `ok` is false the object says why
79
86
  (`error`) and carries either a command the agent can run (`fix`) or a
80
87
  question for the person (`ask`, sometimes with `choices`).
81
88
 
82
- | Step | Answers |
83
- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- |
84
- | `npx @monster-orange/den create <name> [dir] --yes --json` | `{ ok, dir, cli, existed, files, port, portPicked?, next }` |
85
- | `<cli> repo add <path\|git-url> --json` | `{ ok, existed, repo, workspace, mode, path, manifest, services, next }` |
86
- | `<cli> repo detect <folder> --json` | `{ ok, path, repos, workspaces, truncated, skipped, rule, next }` |
87
- | `<cli> repo add <path> --dry-run --json` | `{ ok, dryRun, repo, workspace, path, manifest, draft, validation, next }` |
88
- | `<cli> onboard status --json` | `{ ok, checks: [{ id, status, detail, fix?, ask? }], next }` |
89
- | `<cli> up <repo> --json` | `{ ok, workspace, services: [{ address, result, health, detail? }], next }` |
90
- | `<cli> web up --no-open --json` | `{ ok, url, port, version? }` |
91
- | `<cli> doctor --json` | `{ ok, checks: [{ id, status, detail, url?, port?, fix?, ask? }] }` |
92
- | `<cli> mcp connect --runtime <runtime> --json` | `{ ok, server, clients: [{ id, ok, said, file?, changed? }], restart, web }` |
93
- | `<cli> down <repo> --json` | `{ ok, workspace, services, all? }` |
94
- | `<cli> web down --json` | `{ ok, url, port, running, stopped }` |
89
+ | Step | Answers |
90
+ | ----------------------------------------------------------------- | ---------------------------------------------------------------------------- |
91
+ | `npx @monster-orange/den@latest create <name> [dir] --yes --json` | `{ ok, dir, cli, existed, files, port, portPicked?, next }` |
92
+ | `<cli> repo add <path\|git-url> --json` | `{ ok, existed, repo, workspace, mode, path, manifest, services, next }` |
93
+ | `<cli> repo detect <folder> --json` | `{ ok, path, repos, workspaces, truncated, skipped, rule, next }` |
94
+ | `<cli> repo add <path> --dry-run --json` | `{ ok, dryRun, repo, workspace, path, manifest, draft, validation, next }` |
95
+ | `<cli> onboard status --json` | `{ ok, checks: [{ id, status, detail, fix?, ask? }], next }` |
96
+ | `<cli> up <repo> --json` | `{ ok, workspace, services: [{ address, result, health, detail? }], next }` |
97
+ | `<cli> web up --no-open --json` | `{ ok, url, port, version? }` |
98
+ | `<cli> doctor --json` | `{ ok, checks: [{ id, status, detail, url?, port?, fix?, ask? }] }` |
99
+ | `<cli> mcp connect --runtime <runtime> --json` | `{ ok, server, clients: [{ id, ok, said, file?, changed? }], restart, web }` |
100
+ | `<cli> down <repo> --json` | `{ ok, workspace, services, all? }` |
101
+ | `<cli> web down --json` | `{ ok, url, port, running, stopped }` |
95
102
 
96
103
  ### repo add
97
104
 
@@ -119,7 +126,12 @@ question for the person (`ask`, sometimes with `choices`).
119
126
  the answer has `ask` and `choices`, nothing is written, and a re-run names
120
127
  the command with `--run "<cmd>"`. A Makefile `test` target or a
121
128
  `package.json` `test` script becomes the repo's `tests.unit`.
122
- `--health <url>` adds an HTTP health check.
129
+ `--health <url>` adds an HTTP health check. Without it, when the start
130
+ script names a port (`--port`, `-p`, `PORT=`) or runs a dev server with a
131
+ fixed default port (Vite 5173, Next 3000, Angular 4200,
132
+ Gatsby 8000, webpack-dev-server 8080), the side-car gets
133
+ `http://localhost:<port>/` as its health URL, so the service has Visit ↗.
134
+ No port: no health URL is guessed.
123
135
  - The workspace is `-w <workspace>` (made and activated if it doesn't exist),
124
136
  else the focused one, else a new `default` workspace.
125
137
  - The same repo again answers `ok` with `existed: true`. A different repo
@@ -184,11 +196,11 @@ token (an MCP server outside an agent's session, or anything else on this
184
196
  machine) reads "Something on this machine (no agent identity) wants to:",
185
197
  with "If you didn't ask an agent to do this, Deny." under it.
186
198
 
187
- | MCP tool | What Allow runs |
188
- | ------------------ | ------------------------------------------------------- |
189
- | `workspace_create` | The Workspaces page's create: an empty workspace |
190
- | `repo_add` | `repo add <path> --json`, a local folder inside home |
191
- | `service_try` | `up` for one service, as the Services page's Start does |
199
+ | MCP tool | What Allow runs |
200
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
201
+ | `workspace_create` | The Workspaces page's create: an empty workspace, made active |
202
+ | `repo_add` | `repo add <path> --json`, a local folder inside home |
203
+ | `service_try` | `up` for one service, as the Services page's Start does; an inactive workspace is activated first ("Start <service> (this activates <workspace>)") |
192
204
 
193
205
  - **Den writes the dialog.** Its line and its Review come from the action
194
206
  and its arguments, never from the agent. `repo_add`'s Review is its dry
@@ -368,6 +380,39 @@ The ☆ star on Workspaces rows, Services and Graph cards marks a
368
380
  favourite. It is one list, saved in `shell.pins`, so a star set on one
369
381
  page shows on all of them.
370
382
 
383
+ ### The service panel
384
+
385
+ A pinned service in the rail has **↗** at the end of its row, always
386
+ shown: it opens the service's URL in a new tab ("Visit <service> (opens a
387
+ new tab)", the URL as its tooltip). It is greyed out, saying "Not
388
+ running", while the service is down, and absent when the service has no
389
+ URL.
390
+
391
+ A click on the service's name (or Enter on its row, or its dot when the
392
+ rail is collapsed) opens its **panel** beside the row, without leaving
393
+ the page. ⌘-click, Ctrl-click or a middle click still opens Services in a
394
+ new tab. Esc or a click outside closes it, and focus goes back to the
395
+ row. Under 640 px wide it is a sheet at the bottom of the screen. The
396
+ Services card's name and the Graph card's **⋯** open the same panel.
397
+
398
+ Top to bottom, it has:
399
+
400
+ - the name, workspace, health dot, state ("up 2h", "down: HTTP 502",
401
+ "starting…") and URL;
402
+ - **Visit ↗**, then **Start** or **Stop**, **Restart** and **Logs**. These
403
+ call what the Services page calls (`/api/service/exec` with `up`,
404
+ `down` or `restart`, and `/api/service/logs`), each in a tab of the runs
405
+ dock. Logs opens the dock on that service;
406
+ - **Last test run** (the server's run history, `GET /api/runs/last`) and
407
+ **Run tests**, which runs the repo's suites (`/api/run?pillar=suites`);
408
+ - **Agents**: the agents working in the repo, each with **Open**, and
409
+ **+ Start agent here**, which opens the Start dialog with the workspace
410
+ and the repo's folder filled in;
411
+ - **Open in Services**, **Open in Graph** and **Unpin** (or **Pin**).
412
+
413
+ It stays current while it is open, from the same feeds the pages use. Delete
414
+ on a pinned row still unpins it.
415
+
371
416
  ## Health checks
372
417
 
373
418
  A service declares its health per environment under `health`, in one of
@@ -1576,7 +1621,12 @@ user, and the CLI does that for you:
1576
1621
  the 10 minutes, and an expired code is a click away from a new one.
1577
1622
  From a computer with SSH access to it, the page gives the one-liner
1578
1623
  (`ssh <host> '<cli> web approve <code>'`) and, when the host is a name,
1579
- an Open Terminal (`ssh://`) link;
1624
+ an Open Terminal (`ssh://`) link. On Windows, which has no `ssh://`
1625
+ app by default, there is no link: the one-liner is the step, with
1626
+ "Open Windows Terminal or PowerShell, paste this, and press Enter."
1627
+ Elsewhere, if the page still has focus 2 seconds after a click on Open
1628
+ Terminal (no app took the link), it says "Nothing opened? Copy the
1629
+ command below and paste it into your terminal app.";
1580
1630
  - **Other ways**, collapsed: the one-time link with
1581
1631
  `web login --origin`.
1582
1632
 
@@ -2228,6 +2278,64 @@ start` and `<cli> doctor` say why den-pty is unavailable.
2228
2278
  limit) is refused with that reason; point `<PREFIX>_HOME` somewhere
2229
2279
  shorter.
2230
2280
 
2281
+ ## The server agent
2282
+
2283
+ Every Den has its own agent, named after the distribution ("Acme agent"),
2284
+ for anything about the server itself: set it up, add a repo, fix a failing
2285
+ service, change a setting, explain what's running. It belongs to no
2286
+ workspace. It is a normal Den agent underneath (its record, its session,
2287
+ Resume after a restart, rotation and Den's hooks), with Den's persona
2288
+ `server` and the plain-writing rule, in a reserved scope, `den-server`: no
2289
+ workspace may take that name.
2290
+
2291
+ - **It acts only through Den's MCP.** Its MCP server
2292
+ (`<cli> mcp --workspace den-server --actor agent:server`) serves the whole
2293
+ Den, not one workspace, so it may use the onboarding tools a workspace's
2294
+ agent is refused. Every write (`workspace_create`, `repo_add`,
2295
+ `service_try`) is [held for the person](#onboarding-writes-held-for-the-person):
2296
+ until they allow one in the browser, it only reads. It starts in an empty
2297
+ folder of its own (`<state_dir>/server-agent`), with no checkout to edit,
2298
+ and its runtime asks before every command (`permission_mode: ask`).
2299
+ Den's own MCP tools are the exception, for this agent only: its settings
2300
+ file allows `mcp__<server>` (the `--mcp-config` server), so reads just
2301
+ run and each write asks once, in the browser. The org's immediate actions
2302
+ (`mcp.actions`) stay in `permissions.ask`. On a fresh Den the page says
2303
+ above its terminal: "Claude asks whether to trust this folder. Choose
2304
+ Yes." Den doesn't answer that prompt for the person.
2305
+ - **Where it lives.** On a fresh Den (no repo in any workspace yet), the
2306
+ first page, `/`, is that agent in a terminal framed as the page, with
2307
+ Open in Agents as the way out. After setup it is one click away in the
2308
+ rail ("Acme agent", `/server-agent`), and ⌘K has "Ask Acme". Agents lists
2309
+ it first, under "Server", not under a workspace.
2310
+ - **Its onboarding:** `onboard_status`, then "Let's set up Acme. Where are
2311
+ your repos? I'll look in <the folder above the Den's> unless you name
2312
+ another folder." in its first turn, `repos_detect` and suggested workspaces, `workspace_create`,
2313
+ `manifest_draft` and `repo_add` for each repo, `service_try` (and
2314
+ `doctor` when it fails), then "Here's what's running, and three things to
2315
+ try next."
2316
+ - **What runs it.** A catalog runtime that is installed and carries Den's
2317
+ tools: the person's choice (`agents.server_runtime` in
2318
+ `config/local/user.yml`, set from the page's Runs on picker), else the
2319
+ first one found. Den can tell a runtime is installed, not that it is
2320
+ logged in: one that isn't asks in its own terminal, on the page. On a
2321
+ fresh Den with such a runtime it starts by itself, once per page load;
2322
+ after setup it starts only from its Start button. With no runtime, the
2323
+ page shows how to install one and the manual path for this Den, from its
2324
+ folder: `cd <dir>`, `./bin/<cli> repo add <path>`, `./bin/<cli> up`.
2325
+ - **Its model.** The page's Model picker, beside Runs on, offers the
2326
+ runtime's own models (`agents.server_model`). With none saved, Sonnet
2327
+ when the runtime has it, else the runtime's default. A new model starts
2328
+ a fresh conversation at the next start.
2329
+ - **Only a person starts it or picks its runtime or model.** An agent's token, or a
2330
+ request claiming to be an agent, is refused (403).
2331
+
2332
+ | Route | What it does |
2333
+ | -------------------------------- | --------------------------------------------------------------------------- |
2334
+ | `GET /api/server-agent` | Its name, runtime (or none), state, session, fresh, manual |
2335
+ | `POST /api/server-agent/start` | `{ runtime? }`: start it, or resume or relaunch it |
2336
+ | `POST /api/server-agent/runtime` | `{ runtime: id \| null }`: the person's choice of runtime |
2337
+ | `POST /api/server-agent/model` | `{ model: id \| null }`: the person's choice of model, one of the runtime's |
2338
+
2231
2339
  ## Agents
2232
2340
 
2233
2341
  An agent is a **persona** (who) in a **workspace** (where), run by a
@@ -2398,6 +2506,11 @@ started. The workspace header counts them ("2 agents").
2398
2506
  `agents.runtimes.<id>.bin` to its path in <your user.yml>, or run
2399
2507
  `<cli> agents doctor`" (see [Runtimes](#runtimes)). Nothing fails only
2400
2508
  after Start.
2509
+ - **Folder** (optional) is where the agent runs: a folder inside the
2510
+ workspace's own, or a repo's folder of the workspace (relative to the
2511
+ workspace's folder, or absolute). Empty, it runs in the workspace's
2512
+ folder. A folder outside the workspace is refused (403). The service
2513
+ panel's **Start agent here** fills it with the repo's folder.
2401
2514
  - The page and the CLI call the same operations and read the same agent
2402
2515
  records, so an agent started in one is listed in the other. A workspace
2403
2516
  lists its own agents only.
@@ -2412,7 +2525,7 @@ started. The workspace header counts them ("2 agents").
2412
2525
 
2413
2526
  The routes: `GET /api/workspaces/<ws>/agents`, `POST
2414
2527
  /api/workspaces/<ws>/agents` (`{ persona, runtime?, model?, version?,
2415
- permission?, allow?, instruction?, id? }`, see
2528
+ permission?, allow?, instruction?, id?, folder? }`, see
2416
2529
  [The Start dialog](#the-start-dialog)), `POST
2417
2530
  /api/workspaces/<ws>/agents/<id>/stop` and `…/resume`, `POST
2418
2531
  /api/workspaces/<ws>/sessions` (a plain session), `GET /api/personas`
package/docs/reference.md CHANGED
@@ -7,7 +7,7 @@ The technical reference that used to be the README. It will be split into separa
7
7
  1. **Create** a distribution named after your product:
8
8
 
9
9
  ```sh
10
- npx @monster-orange/den create acme # → ./acme
10
+ npx @monster-orange/den@latest create acme # → ./acme
11
11
  cd acme && npm install
12
12
  ```
13
13
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monster-orange/den",
3
- "version": "0.4.17",
3
+ "version": "0.4.19",
4
4
  "description": "Den: a local multi-repo dev orchestrator, HTTPS edge and E2E harness",
5
5
  "type": "module",
6
6
  "bin": {
@@ -90,6 +90,7 @@
90
90
  "@types/semver": "7.7.1",
91
91
  "@typescript-eslint/eslint-plugin": "^7.18.0",
92
92
  "@typescript-eslint/parser": "^7.18.0",
93
+ "axe-core": "4.10.3",
93
94
  "eslint": "^8.56.0",
94
95
  "husky": "^8.0.3",
95
96
  "jest": "^29.7.0",