@rubytech/create-maxy-code 0.1.108 → 0.1.110
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/dist/index.js +11 -125
- package/dist/snap-chromium.js +1 -2
- package/dist/uninstall.js +10 -9
- package/package.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/upgrade/SKILL.md +34 -0
- package/payload/platform/plugins/cloudflare/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/cloudflare/PLUGIN.md +9 -16
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +7 -12
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +3 -3
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +16 -51
- package/payload/platform/plugins/cloudflare/references/reset-guide.md +24 -25
- package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +29 -144
- package/payload/platform/plugins/docs/references/admin-session.md +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/cloudflare.md +20 -29
- package/payload/platform/plugins/docs/references/platform.md +4 -22
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +4 -316
- package/payload/platform/plugins/venture-studio/PLUGIN.md +35 -4
- package/payload/platform/plugins/venture-studio/bin/scaffold.sh +104 -0
- package/payload/platform/plugins/venture-studio/skills/investor-data-room/SKILL.md +3 -1
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js +78 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js.map +1 -0
- package/payload/platform/scripts/check-no-task-id-leaks.mjs +1 -1
- package/payload/platform/scripts/vnc.sh +4 -3
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
- package/payload/premium-plugins/venture-studio/PLUGIN.md +35 -4
- package/payload/premium-plugins/venture-studio/bin/scaffold.sh +104 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/SKILL.md +3 -1
- package/payload/server/{chunk-AGFS3TVN.js → chunk-FSPPVVWM.js} +1303 -496
- package/payload/server/maxy-edge.js +21 -259
- package/payload/server/public/assets/{ChatInput-DJsqm_Gf.js → ChatInput-CsnIedhS.js} +1 -5
- package/payload/server/public/assets/{Checkbox-DGZG9BKc.js → Checkbox-CWugFyFT.js} +1 -1
- package/payload/server/public/assets/admin-D3gZuyUn.js +217 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Dw16BhiX.js → architectureDiagram-Q4EWVU46-CeTRKWDb.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DIOpmf5Y.js → blockDiagram-DXYQGD6D-DeeIX5U3.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Tdb_HZeX.js → c4Diagram-AHTNJAMY-CFsqZuil.js} +1 -1
- package/payload/server/public/assets/channel-CrSx5mnG.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-CebpwDDe.js → chunk-336JU56O-DpIXuFM0.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-BtRCmfDU.js → chunk-426QAEUC-Qk8qqrvA.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BZ3GEWs3.js → chunk-4TB4RGXK-DtM8-CUn.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-iDI6Xu0U.js → chunk-5FUZZQ4R-CrSQ4ySU.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-SQD_EpYa.js → chunk-5PVQY5BW-Bn2nQwdj.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CtCcA7_e.js → chunk-EDXVE4YY-CzCPnR0P.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-pXVGVCbb.js → chunk-ENJZ2VHE-CgZj9RoG.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-Dkzg9o2N.js → chunk-ICPOFSXX-wy-eNjwW.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-1ZZWzf9F.js → chunk-OYMX7WX6-CMmJtL8S.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-CpQ3kzO0.js → chunk-U2HBQHQK-CFCW7OaT.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-C2LkxroC.js → chunk-X2U36JSP-Bgh-CJSN.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Bl5jBOt5.js → chunk-YZCP3GAM-BXKwZ4vN.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-CHtnptPS.js → chunk-ZZ45TVLE-BiOuK5NP.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-C3IDJsqN.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BOIrJ5Zb.js +1 -0
- package/payload/server/public/assets/clone-P8Fkz7JD.js +1 -0
- package/payload/server/public/assets/{dagre-BziN0Nkh.js → dagre-DyCxa9Q2.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-B7OG1g1Y.js → dagre-KV5264BT-Cffo_hmf.js} +1 -1
- package/payload/server/public/assets/data-DRfwJPja.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-Bf31nIDs.js → diagram-5BDNPKRD-Bt93Du3V.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DQu85hhH.js → diagram-G4DWMVQ6-v4r-tBsC.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-5tstbs4y.js → diagram-MMDJMWI5-DKrVPOP-.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635--MOV1U4o.js → diagram-TYMM5635-B1PzWQb9.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BtAnOJmd.js → erDiagram-SMLLAGMA-ClQzsQAs.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CybiCIih.js → flowDiagram-DWJPFMVM-h3IbpN_7.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-B44jN7Cy.js → ganttDiagram-T4ZO3ILL-ClaxOJi8.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CT7iYcwg.js → gitGraphDiagram-UUTBAWPF-pM-U4ClD.js} +1 -1
- package/payload/server/public/assets/graph-B4FFYwus.js +1 -0
- package/payload/server/public/assets/graph-labels-Cpk9Ktt0.js +1 -0
- package/payload/server/public/assets/{graphlib-DP4o0pYL.js → graphlib-CwimOv_M.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-CvxFpFHN.js → infoDiagram-42DDH7IO-DcO3Giwe.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CUwWLPeR.js → ishikawaDiagram-UXIWVN3A-BcdSL5VS.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-y-OnGgLi.js → journeyDiagram-VCZTEJTY-CYahHYzf.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BhrSe8R4.js → kanban-definition-6JOO6SKY-Cl5KhoS4.js} +1 -1
- package/payload/server/public/assets/lib--yuBd0Xi.js +33 -0
- package/payload/server/public/assets/{line-C9uS7z4J.js → line-d_2oTxLp.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-Cg4ZdKp-.js → mermaid-parser.core-CMMDGv3x.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-BHdKOsex.js → mermaid.core-DK9ENGbr.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-NBYiXHo7.js → mindmap-definition-QFDTVHPH-mA3x3MFG.js} +1 -1
- package/payload/server/public/assets/page-CgDmg_fX.js +1 -0
- package/payload/server/public/assets/{page-D9YpwhIu.js → page-D9lluVl7.js} +2 -2
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CbojC64C.js → pieDiagram-DEJITSTG-CW1nGFlY.js} +1 -1
- package/payload/server/public/assets/public-DdLMkNdS.js +7 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CnnoZXcL.js → quadrantDiagram-34T5L4WZ-DI5igJhR.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DFRFRtyJ.js → requirementDiagram-MS252O5E-DyVeI4e_.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DU5gcpzO.js → sankeyDiagram-XADWPNL6-CCTTBYKY.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BN7HZ6Hq.js → sequenceDiagram-FGHM5R23-hVVf35ly.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DG6cCjvg.js → stateDiagram-FHFEXIEX-CSLuQDUX.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C5JejhQU.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-qmV-8SEV.js → timeline-definition-GMOUNBTQ-sxC3W8Q4.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BMXQ1s3n.js → vennDiagram-DHZGUBPP-Ro-ton6Z.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CoAdP1Gw.js → wardleyDiagram-NUSXRM2D-T-dKD0Zx.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CZlfGTEn.js → xychartDiagram-5P7HB3ND-CfProPts.js} +1 -1
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +5 -5
- package/payload/server/public/index.html +7 -7
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +299 -1392
- package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +0 -241
- package/payload/platform/plugins/cloudflare/scripts/_stream-log.sh +0 -154
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.sh +0 -98
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +0 -749
- package/payload/platform/plugins/cloudflare/scripts/reset-tunnel.sh +0 -107
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +0 -854
- package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +0 -291
- package/payload/server/chunk-BDFOTLPW.js +0 -759
- package/payload/server/chunk-JRBCOVA4.js +0 -1305
- package/payload/server/cloudflare-task-tracker-M5ONAGUT.js +0 -22
- package/payload/server/public/assets/admin-BvzMvMGo.js +0 -217
- package/payload/server/public/assets/channel-DThrH4QF.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BC6oGTNX.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-COwC5Umh.js +0 -1
- package/payload/server/public/assets/clone-Chp7hvnA.js +0 -1
- package/payload/server/public/assets/data-BAgaPs4j.js +0 -1
- package/payload/server/public/assets/graph-Cma7EArf.js +0 -1
- package/payload/server/public/assets/graph-labels-DyKk6Sxf.js +0 -1
- package/payload/server/public/assets/lib-CpkYtEDz.js +0 -29
- package/payload/server/public/assets/page-B4IWl3aZ.js +0 -1
- package/payload/server/public/assets/public-BtOXjy3A.js +0 -8
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CvVd1Q_q.js +0 -1
|
@@ -216,7 +216,7 @@ Two endpoints, two surfaces, two restart-survival roles:
|
|
|
216
216
|
liveness. `processStartedAt` resets on every brand-service restart;
|
|
217
217
|
Neo4j probe is bounded to 1 s and reports
|
|
218
218
|
`conversationDb: 'ok' | 'error'`. Use this to confirm the brand
|
|
219
|
-
process came back after
|
|
219
|
+
process came back after a Cloudflare-setup armed restart.
|
|
220
220
|
- `GET /api/admin/version` (maxy-edge) — installer / brand version
|
|
221
221
|
string. Hosted on `maxy-edge.service` so the Software Update modal
|
|
222
222
|
can read it while the brand service is mid-restart.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Cloudflare Tunnel — the dashboard is the source of truth
|
|
2
2
|
|
|
3
|
-
Each installation has its own Cloudflare account. Sign-in is OAuth: the
|
|
3
|
+
Each installation has its own Cloudflare account. Sign-in is OAuth: the agent invokes `cloudflared tunnel login` via Bash; the Cloudflare Authorize URL streams into the admin chat PTY and the native terminal renders it as a clickable link. Click it, authorise in your own browser, and `cloudflared` writes `cert.pem` to the brand's config directory. The agent never reads or mutates Cloudflare account state directly — whatever you see in your logged-in dashboard is the single source of truth. When something needs doing on the account side (adding a domain, deleting a stray entry, switching accounts), the agent relays the click-paths; you run them in your browser.
|
|
4
4
|
|
|
5
5
|
## Identity model
|
|
6
6
|
|
|
@@ -8,34 +8,25 @@ Each installation has its own Cloudflare account. Sign-in is OAuth: the setup sc
|
|
|
8
8
|
|------|--------|
|
|
9
9
|
| **Product identity** (Maxy vs Real Agent) | `brand.json` (`productName`, `configDir`) — known at install. |
|
|
10
10
|
| **Cloudflare account identity** | `cert.pem` from OAuth. One account per brand per device. |
|
|
11
|
-
| **Domain scope** (which zones the operator can route) | Live Cloudflare dashboard
|
|
12
|
-
| **
|
|
13
|
-
| **Local tunnel state** | `~/{configDir}/cloudflared/` — `cert.pem`, `<UUID>.json`, `config.yml`, `tunnel.state`, `alias-domains.json`. |
|
|
11
|
+
| **Domain scope** (which zones the operator can route) | Live Cloudflare dashboard — the operator picks the zone in the dashboard during OAuth or names it in chat. The agent does not enumerate zones programmatically. |
|
|
12
|
+
| **Local tunnel state** | `~/{configDir}/cloudflared/` — `cert.pem`, `<UUID>.json`, `config.yml`, `alias-domains.json`. |
|
|
14
13
|
|
|
15
|
-
There is no token-based auth for the operator-owned path (Mode A). To switch Cloudflare accounts,
|
|
14
|
+
There is no token-based auth for the operator-owned path (Mode A). To switch Cloudflare accounts, the agent runs the reset flow from `plugins/cloudflare/references/reset-guide.md` (deletes the cert and every tunnel on the current account), then the manual-setup flow again — `cloudflared tunnel login` picks a fresh account when you sign in.
|
|
16
15
|
|
|
17
16
|
## Setup flow
|
|
18
17
|
|
|
19
|
-
Ask the agent to set up Cloudflare. The agent confirms the domain is already on your Cloudflare account (if not, it quotes the dashboard click-path — see below) and
|
|
18
|
+
Ask the agent to set up Cloudflare. The agent confirms the domain is already on your Cloudflare account (if not, it quotes the dashboard click-path — see below) and collects the inputs in plain chat:
|
|
20
19
|
|
|
21
20
|
- **Admin address** — the hostname that will serve the admin chat (e.g. `admin.yourdomain.com`).
|
|
22
21
|
- **Public address** — optional hostname for the public agent (e.g. `public.yourdomain.com` or `chat.yourdomain.com`).
|
|
23
22
|
- **Proxy apex** — optional bare-domain hostname (e.g. `yourdomain.com`) that should also serve the public agent.
|
|
24
23
|
- **Admin password** — the password used to gate remote access to the admin surface.
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
The agent then sets the admin password via `curl -X POST http://127.0.0.1:${PORT}/api/remote-auth/set-password` (same endpoint the local onboarding form uses), and works through `plugins/cloudflare/references/manual-setup.md` Steps 1–7 directly via the Bash tool. `cloudflared`'s stdout streams into the PTY verbatim. The OAuth URL is linkified by the terminal; click it in your own browser to authorise. After the tunnel is up, the agent appends each non-`public.*` public or apex hostname to `~/{configDir}/alias-domains.json` so `isPublicHost()` classifies it as public, and starts the brand's cloudflared user service.
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
If any step's `cloudflared` invocation exits non-zero, the agent names the literal exit code, surfaces the stderr verbatim, and cites `reset-guide.md` for the next action — no retry under a different flag, no Playwright-driven dashboard inspection.
|
|
29
28
|
|
|
30
|
-
-
|
|
31
|
-
- Tunnel resolution from operator-supplied identity (operator-selected-tunnel fix). The script requires EXACTLY ONE of `TUNNEL_ID` or `TUNNEL_NAME` in env and exits 1 with a literal error on either-both-set or neither-set. Pre-fix the script derived `${BRAND}-$(hostname -s)` locally; that broke the operator-state-is-authoritative doctrine and silently created orphan tunnels whenever the device hostname changed. Stream log emits `step=tunnel-resolve source=operator-selected|operator-created tunnel_id=… tunnel_name=…` once the UUID is known.
|
|
32
|
-
- **Zone pre-flight** — for every non-apex hostname the script queries `1.1.1.1` for the registrable parent's NS records and refuses the whole run if they don't point at Cloudflare. Stream log: `step=zone-preflight result=ok|error zones_on_account=… missing_parent_for=…`. Catches "domain not on Cloudflare"; does not catch "domain on a different Cloudflare account than `cert.pem` is bound to" — that case surfaces later via `tunnel-status`.
|
|
33
|
-
- `cloudflared tunnel route dns` for each subdomain hostname. Apex hostnames cannot be routed this way — the script prints an **ACTION REQUIRED** block naming the exact dashboard record to add or edit. Stream log emits `step=route-dns hostname=… tunnel_id=…` before the call and `step=route-dns hostname=… result=ok|apex-skip|error` after; on error the bounded cloudflared stderr (≤400 chars) rides in the same phase line. **The script does not parse cloudflared's stdout** — exit code is the sole decision signal, so all three legitimate cloudflared output shapes (new record, overwrite, idempotent "already configured") are treated as success.
|
|
34
|
-
- `config.yml` and `tunnel.state` written under `${CFG_DIR}`.
|
|
35
|
-
- `systemctl --user restart ${BRAND}.service` — restarts the platform service so the new tunnel spawns via the service's `ExecStartPre=resume-tunnel.sh`. The restart fires a few seconds after the script exits so the script does not kill its own cgroup when invoked via the Bash tool; the chat UI receives a `server_shutdown` SSE frame and reconnects automatically.
|
|
36
|
-
- Post-restart verification — `ps -ef | grep '[c]loudflared'` confirms the connector is alive, then `curl -I https://<hostname>` against each subdomain (up to 60 s per host) confirms a non-530 response.
|
|
37
|
-
|
|
38
|
-
The agent streams the script's stdout into chat verbatim as it arrives, including any `ACTION REQUIRED` block. If the script exits non-zero, the agent names the literal exit code and cites `reset-guide.md` for the next action — no retry under a different flag, no Playwright-driven dashboard inspection.
|
|
29
|
+
The setup-done claim only fires after the agent runs `curl -I https://<admin-hostname>` from outside the local network and the response shows a `200` line. That HTTP response is the only success terminal.
|
|
39
30
|
|
|
40
31
|
## Getting a domain on Cloudflare
|
|
41
32
|
|
|
@@ -49,19 +40,19 @@ Existing website traffic continues to work during and after the switch. Only DNS
|
|
|
49
40
|
|
|
50
41
|
## Reset / account switch
|
|
51
42
|
|
|
52
|
-
Ask the agent to reset Cloudflare. The agent
|
|
43
|
+
Ask the agent to reset Cloudflare. The agent executes the reset flow from `plugins/cloudflare/references/reset-guide.md`:
|
|
53
44
|
|
|
54
45
|
- Deletes every tunnel on the brand's current Cloudflare account (via the bound cert).
|
|
55
46
|
- Wipes the brand's `${CFG_DIR}`.
|
|
56
|
-
-
|
|
47
|
+
- Stops the brand's cloudflared user service.
|
|
57
48
|
|
|
58
|
-
The
|
|
49
|
+
The agent does **not** stop token-mode connector processes or delete stray misrouted CNAMEs in the dashboard. If any of those apply, the agent guides you through the manual cleanup — `pkill -f 'cloudflared.*tunnel run --token'` on the device, or deleting the stray CNAME in the dashboard.
|
|
59
50
|
|
|
60
51
|
After reset, run setup again. The fresh `cloudflared tunnel login` will pick whichever Cloudflare account you sign into.
|
|
61
52
|
|
|
62
53
|
## Manual runbook
|
|
63
54
|
|
|
64
|
-
|
|
55
|
+
The step-by-step runbook at `plugins/cloudflare/references/manual-setup.md` is the contract the agent follows. It is also what an operator runs by hand when needed — every numbered step is an isolated `cloudflared` command block with success conditions and troubleshooting.
|
|
65
56
|
|
|
66
57
|
## Dashboard operations the CLI cannot do
|
|
67
58
|
|
|
@@ -71,17 +62,17 @@ The CLI cannot add a domain, switch accounts, edit an apex CNAME, or delete stra
|
|
|
71
62
|
|
|
72
63
|
### Tunnel won't start
|
|
73
64
|
|
|
74
|
-
Ask the agent to check. The agent reads `systemctl --user status ${BRAND}.service` and `~/{configDir}/cloudflared
|
|
65
|
+
Ask the agent to check. The agent reads `systemctl --user status ${BRAND}-cloudflared.service` and the cloudflared log under `~/{configDir}/cloudflared/`. Common states:
|
|
75
66
|
|
|
76
|
-
- **No cloudflared process running** — the service
|
|
77
|
-
- **`tunnel not found`** — the UUID in `config.yml` does not match any tunnel on the currently-bound account. Usually follows an account switch that didn't reset local state. The agent
|
|
67
|
+
- **No cloudflared process running** — the cloudflared service exited or never started. The agent runs the manual-setup flow to re-issue tunnel creation.
|
|
68
|
+
- **`tunnel not found`** — the UUID in `config.yml` does not match any tunnel on the currently-bound account. Usually follows an account switch that didn't reset local state. The agent runs the reset flow and then a fresh setup.
|
|
78
69
|
|
|
79
70
|
### URL returns 530
|
|
80
71
|
|
|
81
72
|
DNS propagation or account mismatch. Wait 30–60 seconds and retry first. If the 530 persists:
|
|
82
73
|
|
|
83
|
-
- The domain may be on a Cloudflare account different from the one `cert.pem` is bound to — re-
|
|
84
|
-
- The UDP buffer for QUIC may be undersized on this device — check
|
|
74
|
+
- The domain may be on a Cloudflare account different from the one `cert.pem` is bound to — the agent re-runs the manual setup steps to re-validate.
|
|
75
|
+
- The UDP buffer for QUIC may be undersized on this device — check the cloudflared log for `failed to sufficiently increase receive buffer size`.
|
|
85
76
|
|
|
86
77
|
### URL returns connection refused
|
|
87
78
|
|
|
@@ -104,8 +95,8 @@ The most common cause is wrong nameservers on the domain. The domain must use Cl
|
|
|
104
95
|
|
|
105
96
|
## What the agent does and does not do
|
|
106
97
|
|
|
107
|
-
**Does:** invokes `
|
|
98
|
+
**Does:** invokes `cloudflared` directly via Bash, following `plugins/cloudflare/references/manual-setup.md` step by step; quotes click-paths from the reference files verbatim; verifies external reachability with `curl -I` and surfaces the response.
|
|
108
99
|
|
|
109
|
-
**Does not:** drive the Cloudflare dashboard via Playwright, synthesise alternative `cloudflared` flag sequences, call any Cloudflare API or SDK, write or edit `cert.pem` / `
|
|
100
|
+
**Does not:** drive the Cloudflare dashboard via Playwright, synthesise alternative `cloudflared` flag sequences not in the runbook, call any Cloudflare API or SDK, write or edit `cert.pem` / `config.yml` directly outside the runbook's instructions.
|
|
110
101
|
|
|
111
|
-
When a
|
|
102
|
+
When a command fails, the agent reports the failure and cites the relevant recovery step. It does not improvise.
|
|
@@ -62,7 +62,7 @@ The graph view (at `/graph`) lets you explore the memory directly. Pick a catego
|
|
|
62
62
|
|
|
63
63
|
## The Web Interface
|
|
64
64
|
|
|
65
|
-
The web app runs on your Pi on port 19200. A small always-on front door (`maxy-edge`) owns that port
|
|
65
|
+
The web app runs on your Pi on port 19200. A small always-on front door (`maxy-edge`) owns that port. The edge also hosts the `/api/admin/version` route so the HeaderMenu version display keeps reading even during a mid-restart of the brand service. Login cookies are HMAC-signed with a shared key on disk, so both processes recognise the same session without any coordination and you do not have to log in again after an update. Every request is also classified as LAN or external based on the network shape it arrived on — LAN browsers reach admin directly; the remote password screen only appears on the tunnel-exposed admin domain. It provides:
|
|
66
66
|
|
|
67
67
|
- **Admin chat** (at `/`) — your primary interface, PIN-protected
|
|
68
68
|
- **Public chat** (at `/{agent-name}`) — visitor-facing agents, each with their own URL. On public hostnames, the root path serves the default agent.
|
|
@@ -108,31 +108,13 @@ The Data search panel ranks results by combining vector similarity with keyword
|
|
|
108
108
|
|
|
109
109
|
## Software Update and Cloudflare Setup
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
Both flows run on the native Claude Code PTY surface in admin chat (Task 287). There is no in-app upgrade modal and no Cloudflare setup form — the agent invokes the relevant Bash command directly and its stdout streams into chat verbatim.
|
|
112
112
|
|
|
113
|
-
**Software
|
|
114
|
-
-
|
|
115
|
-
- a heartbeat every 5 seconds carrying `state=active` + `last_phase` so you can see the installer is alive even during silent phases (tarball download, dep install);
|
|
116
|
-
- a final banner on exit with the return code and elapsed time.
|
|
117
|
-
|
|
118
|
-
If the browser drops the SSE connection mid-upgrade (typical during the maxy restart window), the panel reconnects within two seconds and replays any lines you missed from the persisted log.
|
|
113
|
+
- **Software update.** Re-run the installer (`npx -y @rubytech/create-<brand>@latest`) from a shell; HeaderMenu's version row turns sage when `installed === latest`.
|
|
114
|
+
- **Cloudflare setup.** Operator asks in chat; the agent invokes `cloudflared` directly via the Bash tool, following the numbered steps in `plugins/cloudflare/references/manual-setup.md`. cloudflared's stdout and stderr stream into the PTY; the OAuth URL printed by `cloudflared tunnel login` is linkified by the terminal so the operator clicks it and authorises Cloudflare in their own browser.
|
|
119
115
|
|
|
120
116
|
**Mid-turn stream-drop banners.** If a chat turn ends abruptly the bubble shows one of two messages depending on what actually happened. You see "Server is restarting — reconnect will happen automatically." only when the app server itself emits the restart signal — typically during a Software Update or a Cloudflare setup that re-launches the brand service. You see "Lost connection — retrying." when your browser's connection to the Pi dropped mid-stream while the server was still up — typically a flaky Wi-Fi moment or the tunnel hiccupping. Either way the chat resumes once the connection is back; the previously-rendered messages stay on screen so you don't lose context.
|
|
121
117
|
|
|
122
|
-
**Cloudflare setup flow.** Same pattern — POST to `/api/admin/cloudflare/setup` launches a `cloudflare-setup` action that runs `~/setup-tunnel.sh <brand> <port> <hostname...>`. When the script emits the OAuth consent URL on stdout, the log panel surfaces an **"Authorise in Cloudflare"** button; clicking it opens the consent page in a new tab. After you approve, the script's callback receives `cert.pem` and the setup continues through `tunnel create`/`route`/`run`. On devices where a VNC Chromium is also running, the script can drive the click via CDP automatically (same button remains a harmless safety net). Setup failures return a `CloudflareSetupError` carrying `inputsAlreadyHeld:{admin,public,apex}` and `discoveryResults:{tunnels,domains}` (from the process-lifetime discovery cache `/tunnels` and `/domains` populate on success); the form appends both fields as a fenced JSON block to the chat-relay body so the agent's next reply quotes held values verbatim rather than re-soliciting hostnames.
|
|
123
|
-
|
|
124
|
-
**Active-chat stream-log click telemetry.** Clicking "Stream log" in the active chat fetches the URL inline (`/api/admin/logs?type=stream&conversationId=…&download=1`), emits a `[stream-log-click] status=<c> bytes=<n> conversationId=<tail>` line in `server.log` via the `/api/_client-error` event pipe, and downloads the same response. Operator-grep `[stream-log-click] status=404` for client/server identity mismatches.
|
|
125
|
-
|
|
126
|
-
**Bundle-mtime session prelude.** Each admin session boot stamps `[boot] bundleMtime=<iso> conversationId=<tail>` in `server.log` next to `[plugins] MCP servers for session:`; the value is consumed by the Cloudflare setup route's retry-decision branch (it compares against the most recent terminal `:Task.completedAt`), never by the LLM. The prior `<deployment>` block was removed in 2026-05-13 doctrine fix because the admin LLM read it as narration permission for internal state; the route now owns the retry decision, the agent restates the literal envelope.
|
|
127
|
-
|
|
128
|
-
**Post-action restatement block (2026-05-13 doctrine fix).** `assembleSystemPrompt` injects `<post-action>actionId=<id> outcome=<completed|failed> phase=<phase> at=<iso></post-action>` into the system prompt whenever the dispatcher resolves a terminal `:Task {kind:"cloudflare-tunnel-login"}` on the conversation. Agent-type-agnostic. The IDENTITY clause "If `<post-action>` is present, restate the literal outcome and stop" routes the operator-visible reply. Observability: `[post-action-block] injected|no-prior-action|lookup-failed` log line every turn.
|
|
129
|
-
|
|
130
|
-
**Admin reply scrub (2026-05-13 doctrine fix).** Closed-list token scrub at `platform/ui/app/lib/admin-reply-scrub.ts`; tokens `bundle`, `bundleMtime`, `overnight`, `the fix may`, `was patched`, `re-rendering`, `paste the output`, `run the script`, `re-attempt`. Hit records a violation under `llm-narrates-internal-state` (rule_family `extension`) and emits `[admin-reply-scrub] agent=<name> tokens_found=[…] reply_blocked=false`. Future doctrine paragraphs naming a new internal token MUST extend the list in the same PR.
|
|
131
|
-
|
|
132
|
-
**Sudo password** is prompted once per upgrade. The admin server pipes it to `sudo -S -v` to validate + cache, then forwards it to the action unit via `systemd-run --setenv=SUDO_PASSWORD` so the installer's in-unit `sudo -S` reads it directly — per-TTY sudoers configurations where the user-level cache does not cover a fresh systemd-run unit still work. The password is never written to any log, SSE frame, or persisted file.
|
|
133
|
-
|
|
134
|
-
**Log files.** Each action writes its full output to `~/.maxy/logs/actions/<actionId>.log` for seven days. `journalctl --user --identifier=maxy-action-<actionId>` gives the systemd-level view.
|
|
135
|
-
|
|
136
118
|
**Authorisation** is inherited from the same `canAccessAdmin()` gate that wraps every `/api/admin/*` route.
|
|
137
119
|
|
|
138
120
|
## AI Content Provenance
|
|
@@ -152,7 +152,7 @@ After this, every `console.error("[your-tool]...")` from any tool in the plugin
|
|
|
152
152
|
|
|
153
153
|
**How the tee decides which file to write to:** the platform sets `STREAM_LOG_PATH` as an environment variable on every MCP server spawn, pointing to the conversation-scoped stream log. The MCP server does not know about conversations — it just trusts `STREAM_LOG_PATH`. Multiple concurrent conversations produce multiple concurrent MCP server processes, each teeing to its own file; no cross-conversation leakage.
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
**Bash commands stream straight into the PTY.** Maxy Code's admin and public chat run on the native Claude Code PTY (Task 287). The per-conversation server-side stream log that the retired web-UI dispatcher tailed is gone; agent-invoked Bash commands (including direct `cloudflared` invocations for Cloudflare setup — Task 288) print their stdout and stderr directly, and the PTY renders the output in chat verbatim.
|
|
156
156
|
|
|
157
157
|
**Retrieve MCP diagnostic lines for a conversation:**
|
|
158
158
|
|
|
@@ -184,325 +184,13 @@ If the initial Cloudflare login fails during setup, {{productName}} will fall ba
|
|
|
184
184
|
|
|
185
185
|
---
|
|
186
186
|
|
|
187
|
-
## Action runner — upgrade or Cloudflare setup appears stuck
|
|
188
187
|
|
|
189
|
-
|
|
188
|
+
## Software update and Cloudflare setup
|
|
190
189
|
|
|
191
|
-
|
|
190
|
+
Both flows run on the native Claude Code PTY surface in admin chat (Task 287). The retired action-runner / terminal-modal troubleshooting sections that lived here have been removed because those surfaces no longer exist; failures now manifest as plain stderr from the agent-invoked Bash command, visible in chat.
|
|
192
191
|
|
|
193
|
-
**
|
|
194
|
-
|
|
195
|
-
**Heartbeat stalled** (log panel header shows rising `silent Ns` amber badge).
|
|
196
|
-
|
|
197
|
-
- Open the log panel header: `state: <systemd_state>` tells you the unit's current state.
|
|
198
|
-
- `systemd_state: active` + silent >30s → the child is running but emitting nothing. Expected for `npx` while it downloads the tarball, or `cloudflared tunnel login` waiting for an operator click.
|
|
199
|
-
- `systemd_state: inactive` + no `exit` event → the exit event was missed; the server-side heartbeat timer will emit it on the next 5 s tick.
|
|
200
|
-
- `systemd_state: failed` → see the next symptom.
|
|
201
|
-
|
|
202
|
-
**`ActiveState=failed`** (log panel's exit banner shows a non-zero code).
|
|
203
|
-
|
|
204
|
-
- Read the persisted log directly: `~/.maxy/logs/actions/<actionId>.log` (or `.realagent/...`) has every stdout+stderr line the unit emitted.
|
|
205
|
-
- `journalctl --user --identifier=maxy-action-<actionId>` shows systemd's own record including ExecStartPre/ExecStopPost if any.
|
|
206
|
-
- Common cases:
|
|
207
|
-
- Wrong sudo password → `sudo: 1 incorrect password attempt` near the top of the log; re-open the upgrade modal, enter the correct password.
|
|
208
|
-
- Network failure during `npx` → `npm ERR! network` lines; re-open the modal and retry when network is restored.
|
|
209
|
-
- `cloudflared tunnel login` timed out waiting for OAuth → action exits non-zero with `Timed out after Ns waiting for cert.pem`; re-trigger from the Cloudflare setup form.
|
|
210
|
-
|
|
211
|
-
**"Authorise in Cloudflare" button never appears** (cloudflare-setup action).
|
|
212
|
-
|
|
213
|
-
The setup script emits either the raw `https://dash.cloudflare.com/argotunnel?...` URL in cloudflared's own stderr OR an explicit `OAUTH_URL: <url>` stdout line once URL extraction succeeds. The log panel's regex matches either. If neither appears within ~15 s of launch:
|
|
214
|
-
|
|
215
|
-
- The action log file (`~/.maxy/logs/actions/<actionId>.log`) should show `[script:setup-tunnel:cloudflared]` lines. No such lines → cloudflared isn't spawning (check whether the binary is on PATH in the transient unit; `systemctl --user show maxy-action-<actionId>` reveals the environment).
|
|
216
|
-
- Lines present but no URL → cloudflared output-format drift; file a task with the last 20 lines of the action log.
|
|
217
|
-
|
|
218
|
-
**Log file missing (action stream returns 404).**
|
|
219
|
-
|
|
220
|
-
The transient unit was auto-collected by systemd before the client subscribed. Race condition: action finished in <1 s. The per-action log file is retained for 7 days; look for it by name under `~/.maxy/logs/actions/`. If it isn't there, the unit failed before any output (check `journalctl --user -u maxy-action-<id>`).
|
|
221
|
-
|
|
222
|
-
**Cloudflare-setup action card shows "Failed (exit null)" after the tunnel works.**
|
|
223
|
-
|
|
224
|
-
> **Pre-Task-860 misdiagnosis.** Devices on platform versions misrender a successful `cloudflare-setup` run as red `Failed (exit null) · ~20s` because the script-armed brand-service restart kills the SSE generator before it can read the action's exit code. The Cloudflare side is fine in this case — the tunnel is created, DNS is routed, the brand service comes back up.
|
|
225
|
-
>
|
|
226
|
-
> **First-line check:** open the persisted action log directly. Two markers prove success:
|
|
227
|
-
>
|
|
228
|
-
> ```bash
|
|
229
|
-
> grep -E 'step=service-restart-armed exit=0|step=done' \
|
|
230
|
-
> ~/.{configDir}/logs/actions/cloudflare-setup-*.log | tail -2
|
|
231
|
-
> ```
|
|
232
|
-
>
|
|
233
|
-
> Both lines present in the log ⇒ the script succeeded; the UI banner is the bug, not the run. On post-Task-860 platforms the action card renders `Completed · Ns` on the same log shape; the card now distinguishes four states:
|
|
234
|
-
>
|
|
235
|
-
> - `Completed` (green) — `code === 0` (whether reported by systemd or recovered from the log).
|
|
236
|
-
> - `Failed (exit N)` (red) — non-zero exit reported by systemd. Real failure, follow the existing remediation paths.
|
|
237
|
-
> - `Restart in progress` (neutral sage) — arming line present in log but the post-arm `step=done` was not written before the unit was GC'd. Resolves automatically once `/api/admin/version` responds; if it stays >90 s, falls through to amber.
|
|
238
|
-
> - `Failed (exit unobserved)` (amber) — neither systemd nor the log can confirm a terminal state. Check `journalctl --user -u maxy-action-<id>`; the unit failed early or the log was truncated.
|
|
239
|
-
>
|
|
240
|
-
> The server emits `[action-runner] reconcile actionId=<id> result=<succeeded|failed|restart-in-progress|unresolved> source=<systemd|persisted-log> ms=<n>` once per terminal-state resolution. Missing reconcile line on a finished run = stale platform; upgrade.
|
|
241
|
-
|
|
242
|
-
**Cloudflare-setup auto-relays "completed" but the next chat turn 502s.**
|
|
243
|
-
|
|
244
|
-
The current contract is a single client-driven resume: when the setup script exits cleanly, the form fires a resume event, the chat hook waits for `/api/health` to fail then succeed (the brand-service down-then-up cycle), re-binds the conversation to the new server process, and sends the "completed" marker as a normal hidden chat POST that re-invokes the agent in the operator's real session. No relay queue, no boot-drain, no banner.
|
|
245
|
-
|
|
246
|
-
Diagnostic recipe:
|
|
247
|
-
|
|
248
|
-
```
|
|
249
|
-
grep '\[admin-resume\] reason=post-restart' ~/.maxy/logs/server.log | tail # /resume server-side
|
|
250
|
-
grep '\[session\] cookie-bridge accountId=' ~/.maxy/logs/server.log | tail # session re-hydrated
|
|
251
|
-
grep '\[persist\] .* role=user .* Cloudflare setup completed' ~/.maxy/logs/server.log | tail
|
|
252
|
-
grep '\[client-event\] kind=post-restart-resume' ~/.maxy/logs/server.log | tail
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
Failure modes:
|
|
256
|
-
- `[client-event] kind=post-restart-resume phase=start` absent: form's CustomEvent never reached the chat hook (regression in form `onExit` or chat-listener mount).
|
|
257
|
-
- `[client-event] phase=start` present, `[admin-resume] reason=post-restart` absent: `waitForRestartCycle` exhausted its bound (brand never restarted) or `/resume` rejected — check `phase=health-timeout` / `phase=resume-rejected`.
|
|
258
|
-
- All four present except `[persist] role=user … Cloudflare setup completed`: marker chat POST failed — check the chat surface for an inline error or a `phase=resume-error` line.
|
|
259
|
-
- Refresh after a successful Cloudflare setup shows a visible `Cloudflare setup completed (actionId: …)` user bubble: the resume mappers' synthetic-marker suppression broke or the marker shape drifted. Server-side `[admin-resume] syntheticHidden=<n>` field on the same line counts user rows the client should hide (`_componentDone` envelopes, `_lifecycle` envelopes, and the `Cloudflare setup completed (actionId: …)` literal) — a count of 0 against a refresh that should have hidden one means the helper at `platform/ui/app/lib/synthetic-marker.ts` no longer recognises the producing literal (check `CloudflareSetupForm.tsx` and `useAdminChat.ts` for shape drift).
|
|
260
|
-
|
|
261
|
-
---
|
|
262
|
-
|
|
263
|
-
## Software Update click shows an error instead of opening the terminal
|
|
264
|
-
|
|
265
|
-
> **First-line diagnostic for the byte-stream xterm.js terminal surface:** `sudo systemctl --user status maxy-ttyd` plus `sudo grep 'ttyd-proxy' ~/.maxy/logs/edge-boot.log | tail -20`. Failure mode signals: `ttyd-ws-upgrade accepted` with no `ttyd-proxy-open` → `maxy-ttyd.service` is down; `ttyd-proxy-open` with no `ttyd-proxy-chunk dir=upstream→client` → ttyd/tmux is not attaching a PTY.
|
|
266
|
-
|
|
267
|
-
**Symptom:** You clicked **Upgrade** in the Software Update modal, but instead of the VNC terminal overlay appearing, the modal shows a red error row like:
|
|
268
|
-
|
|
269
|
-
```
|
|
270
|
-
[terminal-launch] failed err="window absent from target display after spawn" pid=1234 display=:99 observed_windows=0 transport=vnc reason=upgrade
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
…and the Upgrade button re-labels to "Try again".
|
|
274
|
-
|
|
275
|
-
**What it means:** `POST /api/admin/terminal/launch-upgrade` returned a 502 — the admin server tried to spawn a real terminal on the VNC display `:99` with `npx -y @rubytech/create-maxy@latest` pre-loaded, but the spawn failed or the window never appeared on the target display. The modal's upgrade path uses the same pipeline as the header-menu Terminal; if the operator Terminal button works, the VNC stack itself is healthy and the fault is usually a missing dep or a stale binary. If the operator Terminal also fails, start with the "Header Terminal click shows an error alert" section below.
|
|
276
|
-
|
|
277
|
-
Step-by-step diagnosis — the error string in the modal is identical to the entry in `~/.maxy/logs/vnc-boot.log`, so you can grep it directly:
|
|
278
|
-
|
|
279
|
-
```bash
|
|
280
|
-
# 1. Find the latest upgrade launch attempt
|
|
281
|
-
sudo grep 'action=launch-upgrade' ~/.maxy/logs/vnc-boot.log | tail -10
|
|
282
|
-
|
|
283
|
-
# 2. See the script-level failure line (same string the modal shows)
|
|
284
|
-
sudo tail -n 30 ~/.maxy/logs/terminal-launch.log
|
|
285
|
-
|
|
286
|
-
# 3. Verify binaries are present
|
|
287
|
-
which xterm xdotool
|
|
288
|
-
|
|
289
|
-
# 4. Confirm the VNC display itself is up
|
|
290
|
-
DISPLAY=:99 xdpyinfo >/dev/null 2>&1 && echo "display:99 ok" || echo "display dead"
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
**Common upgrade-specific failures:**
|
|
294
|
-
|
|
295
|
-
- `err="no terminal emulator installed"` → run `sudo apt-get install -y xterm xdotool` or re-run `npx -y @rubytech/create-maxy@latest` — the installer provisions both as hard deps.
|
|
296
|
-
- `err="spawn detached but no terminal PID visible within 1s"... reason=upgrade` → X server on `:99` is wedged. the VNC stack is owned by `maxy-edge`, so the recovery is `sudo systemctl --user restart maxy-edge` (cycles `vnc.sh start` via that unit's ExecStartPre). Then click **Try again** in the modal.
|
|
297
|
-
- `err="window absent from target display after spawn"... reason=upgrade` → the spawn succeeded but landed on the wrong display (earlier platform fixes class). Re-run the installer to refresh the `resolve_terminal_bin` logic. If a stale `gnome-terminal` is hitting `:99` via D-Bus delegation, the installer's `xterm` fallback is the fix.
|
|
298
|
-
- `err="xdotool not installed — re-run installer to repair"` → earlier platform fixes preflight. `sudo apt-get install -y xdotool` or re-run the installer.
|
|
299
|
-
- `err="VNC failed to start after recovery attempt"` → `Xtigervnc` itself is not coming up. Inspect `~/.maxy/logs/vnc-boot.log` for tigervnc startup lines; `ss -ltn '(sport = 6080 or sport = 5900)'` should show both ports listening.
|
|
300
|
-
|
|
301
|
-
**Click Try again** after applying any fix — the modal re-POSTs the launch-upgrade request.
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## Upgrade terminal stays black after clicking Upgrade (VNC WebSocket rejected)
|
|
306
|
-
|
|
307
|
-
**Symptom:** The launch-upgrade POST returns 200 (the server-side spawn succeeded), but the browser's VNC iframe shows a black rectangle and the DevTools console spins on `WebSocket connection to '/websockify' failed` / `Connection closed (code: 1006)` every few seconds.
|
|
308
|
-
|
|
309
|
-
**What it means:** The browser has a session cookie the `/websockify` auth gate refuses to accept., every rejection logs three fields that identify the failing layer:
|
|
310
|
-
|
|
311
|
-
```bash
|
|
312
|
-
sudo tail -200 ~/.maxy/logs/vnc-boot.log | grep 'decision="rejected"'
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
- `cookieHeaderPresent=false` → the browser never sent a cookie. Check the iframe context / SameSite policy / cookie domain. Most commonly: the user opened admin over HTTP instead of HTTPS, or the cookie is scoped to a different subdomain.
|
|
316
|
-
- `cookieHeaderPresent=true tokenPresent=false` → the cookie is present but the server rejects its signature. This is either tampering or a corrupted/missing shared secret. Check that `~/.maxy/credentials/remote-session-secret` exists on disk (mode `0600`, 64 hex chars) and has not been recently overwritten.
|
|
317
|
-
- `tokenExpired=true` → the 24h session TTL elapsed. Log in again.
|
|
318
|
-
|
|
319
|
-
If the secret file is missing entirely, re-run `npx -y @rubytech/create-maxy@latest` — the installer provisions it idempotently, preserving an existing file on upgrade and creating a fresh one on first install.
|
|
320
|
-
|
|
321
|
-
---
|
|
322
|
-
|
|
323
|
-
## Upgrade terminal opens but npx never runs
|
|
324
|
-
|
|
325
|
-
**Symptom:** You clicked **Upgrade**, the VNC overlay opened with a visible shell prompt, but `npx -y @rubytech/create-maxy@latest` does not execute and the shell is idle.
|
|
326
|
-
|
|
327
|
-
**What it means:** The VNC spawn succeeded but the binary-specific command dispatcher (xterm `-e` or gnome-terminal `--`) did not forward the command. Given the installer ships `xterm` on `:99` by default (with D-Bus-safe dispatching), the likely causes are:
|
|
328
|
-
|
|
329
|
-
- A stale binary override has re-pointed `resolve_terminal_bin` to `gnome-terminal` on `:99` despite the fix.
|
|
330
|
-
- A shell the operator manually spawned (via the header Terminal) wasn't killed before the upgrade click, and `ensureTerminalUpgrade`'s pre-kill step silently failed.
|
|
331
|
-
|
|
332
|
-
**Check:**
|
|
333
|
-
|
|
334
|
-
```bash
|
|
335
|
-
# The spawned binary must appear in this log with the bash-c wrapper
|
|
336
|
-
sudo grep 'started.*reason=upgrade' ~/.maxy/logs/terminal-launch.log | tail -3
|
|
337
|
-
# Expected shape: started pid=<N> display=:99 cmd="/usr/bin/xterm... -e bash -c 'npx -y @rubytech/create-maxy@latest; exec bash'" transport=vnc windowPresent=true reason=upgrade
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
If the `cmd=` field does not contain `-e bash -c`, re-run the installer — the vnc.sh on the device is stale. If the command IS logged correctly but nothing is running, open the VNC overlay and type `history | tail` inside the shell — if the npx line is there, it ran and exited (check `~/.maxy/logs/install-*.log` for the exit status).
|
|
341
|
-
|
|
342
|
-
---
|
|
343
|
-
|
|
344
|
-
## Header Terminal click shows an error alert
|
|
345
|
-
|
|
346
|
-
**Symptom:** You opened the burger menu and clicked **Terminal**, but instead of the overlay appearing you got an inline error like "Terminal failed to start" or "VNC failed to start".
|
|
347
|
-
|
|
348
|
-
**What it means:** `POST /api/admin/terminal/launch` returned a 502 — either the VNC stack on port 5900 is down or the terminal emulator could not be spawned on display `:99`. This is a VNC-stack or display-spawn failure.
|
|
349
|
-
|
|
350
|
-
Step-by-step diagnosis:
|
|
351
|
-
|
|
352
|
-
```bash
|
|
353
|
-
# 1. Check the terminal-launch log for the specific failure reason
|
|
354
|
-
sudo tail -n 50 ~/.maxy/logs/terminal-launch.log
|
|
355
|
-
|
|
356
|
-
# 2. Check the node-side state machine (ensure-terminal entries)
|
|
357
|
-
sudo grep ensure-terminal ~/.maxy/logs/vnc-boot.log | tail -20
|
|
358
|
-
|
|
359
|
-
# 3. Verify the VNC display itself is healthy
|
|
360
|
-
sudo ~/maxy/platform/scripts/vnc.sh status # should print "running"
|
|
361
|
-
DISPLAY=:99 xdpyinfo >/dev/null 2>&1 && echo "display ok" || echo "display dead"
|
|
362
|
-
|
|
363
|
-
# 4. Confirm a terminal binary is installed (xterm is the always-available fallback)
|
|
364
|
-
which gnome-terminal; which xterm
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
Most common failures and fixes:
|
|
368
|
-
|
|
369
|
-
- `[terminal-launch] failed err="no terminal emulator installed"` → run `sudo apt-get install -y xterm xdotool` (or re-run the installer, which installs both as dependencies).
|
|
370
|
-
- `[terminal-launch] failed err="spawn detached but no terminal PID visible within 1s"` → X server on `:99` is wedged. `sudo systemctl --user restart maxy-ui` cycles the VNC stack via `vnc.sh start`.
|
|
371
|
-
- `[terminal-launch] failed err="window absent from target display after spawn" pid=<N> display=:99 observed_windows=0` → the spawned emulator's window landed on the wrong display (earlier platform fixes — almost always a stale gnome-terminal binary on an upgraded install; the fix ships `xterm` as the `:99` default but a stale `resolve_terminal_bin` on an old bundle can still trigger it). Check `which gnome-terminal xterm xdotool` — all three should exist; if not, re-run the installer. Also check `DISPLAY=:99 xdotool search --onlyvisible --class '.'` manually: empty output confirms no window on `:99`; a non-empty result after a fresh click means the window IS there and the check itself is wrong (file an issue).
|
|
372
|
-
- `ensure-terminal action="escalate-vnc-restart"` followed by `degraded` → `Xtigervnc` itself is not coming up. Check `~/.maxy/logs/vnc-boot.log` for the tigervnc startup lines.
|
|
373
|
-
|
|
374
|
-
## Terminal fails after upgrade — `Invalid response` or `window absent from target display`
|
|
375
|
-
|
|
376
|
-
**Symptom:** You upgraded a {{productName}} device and the header-menu **Terminal** click now fails — overlay shows `Invalid response`, or `terminal-launch.log` shows `[terminal-launch] failed err="window absent from target display after spawn" pid=<N> display=:99 observed_windows=0 transport=vnc cmd="/usr/bin/xterm "`. The terminal worked on the previous version and the upgrade reported success.
|
|
377
|
-
|
|
378
|
-
**What it means:** The installer declared a new apt dep between versions (e.g. `xdotool` in 1.0.667), but on your device the installer's apt step was silently skipped because `sudo` requires a password and the installer could not escalate non-interactively. The declared dep was never installed, and `vnc.sh check_window_on_display` then either failed to find the binary (exit 127 now surfaces this as a distinct `failed err="xdotool not installed — re-run installer to repair"` line) or reached the `window absent` path because its preflight tool was missing. See `.docs/deployment.md` ("sudo interactivity contract") for the full mechanism.
|
|
379
|
-
|
|
380
|
-
**Check:**
|
|
381
|
-
|
|
382
|
-
```bash
|
|
383
|
-
dpkg -s xdotool 2>&1 | head -2 # should report "Status: install ok installed"
|
|
384
|
-
which xdotool # should return /usr/bin/xdotool
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
**Fix — two options:**
|
|
388
|
-
|
|
389
|
-
1. **Re-run the installer from an interactive shell** (preferred on upgrade — picks up any future missing deps too):
|
|
390
|
-
|
|
391
|
-
```bash
|
|
392
|
-
npx -y @rubytech/create-maxy@latest
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
The installer now probes `dpkg -s` for every declared apt dep and either prompts you for your sudo password to install missing ones, or loud-fails non-interactively with the exact `sudo apt-get install -y <list>` command to repair. It will no longer print `Skipping apt-get (deps assumed present from prior install)` and continue as if green.
|
|
396
|
-
|
|
397
|
-
2. **Repair manually** (faster if you only want the one binary):
|
|
398
|
-
|
|
399
|
-
```bash
|
|
400
|
-
sudo apt-get install -y xdotool
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
Then click **Terminal** again — it should spawn within a second and the overlay should render the xterm.
|
|
404
|
-
|
|
405
|
-
**Regression boundary:** if you see `[terminal-launch] failed err="xdotool not installed — re-run installer to repair"` in `~/.maxy/logs/terminal-launch.log`, the vnc.sh preflight is telling you the binary is missing before spawn — same class as above, distinct from the earlier platform fixes `window absent from target display after spawn` string. The two strings never appear for the same click.
|
|
406
|
-
|
|
407
|
-
---
|
|
408
|
-
|
|
409
|
-
## Installer aborts on Ubuntu 24.04 with `dpkg -s: chromium`
|
|
410
|
-
|
|
411
|
-
**Symptom:** On a fresh (or re-run) `npx -y @rubytech/create-maxy@latest` on an Ubuntu 24.04 Noble laptop/desktop, step 1/12 aborts:
|
|
412
|
-
|
|
413
|
-
```
|
|
414
|
-
[1/12] System dependencies and network...
|
|
415
|
-
Missing apt deps (1): chromium
|
|
416
|
-
apt install (VNC stack): tigervnc-standalone-server python3-websockify novnc xdg-utils chromium xterm xdotool
|
|
417
|
-
> sudo apt-get install -y... chromium...
|
|
418
|
-
OK in 0.3s
|
|
419
|
-
[ERROR] Setup failed: apt-get install (VNC stack) returned 0 but packages are still not installed per dpkg -s: chromium
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
Directly probing the device shows `dpkg -s chromium` non-zero, `apt-cache policy chromium` reports `Candidate: (none)`, but `/usr/bin/chromium` exists and works, and `snap list chromium` shows the snap is installed.
|
|
423
|
-
|
|
424
|
-
**What it means:** You are on a **pre-637 installer**. On Noble, `chromium` is a virtual package aliasing to `chromium-browser` — `apt-get install chromium` succeeds silently but nothing named `chromium` ever lands in dpkg's state DB. the post-install probe (correctly) notices the discrepancy and aborts. An earlier fix added alias resolution (`chromium` → `chromium-browser`) so the probe matches the dpkg-recorded name and passes.
|
|
425
|
-
|
|
426
|
-
**Fix:** Upgrade to a post-637 version of `@rubytech/create-maxy`:
|
|
427
|
-
|
|
428
|
-
```bash
|
|
429
|
-
npx -y @rubytech/create-maxy@latest
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
**Manual bypass** (if you must install before 637 publishes, or if you're on a restricted shell): pre-install the real.deb name and re-run the installer.
|
|
433
|
-
|
|
434
|
-
```bash
|
|
435
|
-
sudo apt-get install -y chromium-browser
|
|
436
|
-
npx -y @rubytech/create-maxy@latest
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
The installer's resolver will then see `dpkg -s chromium-browser` exit 0 for the alias target, filter `chromium` out of the missing set, and skip the apt-install branch entirely. Raspberry Pi OS (Debian 12 Bookworm) is unaffected — `chromium` IS a concrete.deb on Bookworm.
|
|
440
|
-
|
|
441
|
-
**Deeper diagnostic**: post-637 installer logs carry the full classification in the error message itself — `(resolved-name=<name>, apt-cache-policy=<summary>, command-v=<path>, snap-status=<summary>)`. If you see that longer form and still fail, the apt state itself is inconsistent (snap removed, `chromium-browser` uninstalled after previous install) — repair with `sudo apt-get install --reinstall -y chromium-browser`.
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
## VNC browser will not start on Linux laptop — `Permission denied (13)` on SingletonLock
|
|
446
|
-
|
|
447
|
-
**Symptom:** Boot log `~/.{brand}/logs/vnc-boot.log` shows:
|
|
448
|
-
|
|
449
|
-
```
|
|
450
|
-
Starting Chromium on :<vncDisplay> (vnc) profile=/home/<user>/.{brand}/chromium-profile CDP=:<cdpPort>
|
|
451
|
-
ERROR:chrome/browser/process_singleton_posix.cc:345] Failed to create
|
|
452
|
-
/home/<user>/.{brand}/chromium-profile/SingletonLock: Permission denied (13)
|
|
453
|
-
ERROR: Chromium failed to start on :<vncDisplay> (vnc) — CDP port <cdpPort> not listening (browser-specialist degraded)
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
`dmesg` (or `journalctl -k`) shows AppArmor `DENIED` lines naming `profile="snap.chromium.chromium"` and the `~/.{brand}/chromium-profile/` path. The brand admin chat reports the public-agent VNC browser as unavailable.
|
|
457
|
-
|
|
458
|
-
**What it means:** Your `/usr/bin/chromium` is a snap symlink. Snap's AppArmor profile excludes hidden top-level paths under `$HOME` from its `home` interface, so writes to per-brand Chromium profile dirs at `~/.maxy/chromium-profile/` and `~/.realagent/chromium-profile/` are denied — Chromium cannot create its `SingletonLock` and never starts the CDP listener. This is exclusively a Linux-laptop problem (Ubuntu Noble); Raspberry Pi OS Bookworm ships `chromium` as a real `.deb` and is unaffected.
|
|
459
|
-
|
|
460
|
-
**Fix:** Re-run the installer at version 1.0.849 or later. The installer detects the snap-confined chromium during system-dependency setup and replaces it with Google Chrome stable from Google's signed apt repo:
|
|
461
|
-
|
|
462
|
-
```bash
|
|
463
|
-
npx -y @rubytech/create-maxy@latest
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
The resolved non-snap binary path is recorded at `<INSTALL_DIR>/platform/config/chromium-binary.path` (single line) and read by every Chromium call site (VNC service, in-page wrapper, Playwright server). After re-running, verify with the bundled acceptance script:
|
|
467
|
-
|
|
468
|
-
```bash
|
|
469
|
-
MAXY_PLATFORM_ROOT=$HOME/<install-dir>/platform $HOME/<install-dir>/platform/scripts/test-laptop-vnc-boot.sh
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
The script exits 0 only when (1) the configured Chromium realpath is non-snap, (2) the path is absolute and executable, (3) the per-brand CDP port returns Chromium version JSON, and (4) `vnc-boot.log` since the last `[vnc.sh] start` ends with `VNC + browser stack running` and contains no `Chromium failed to start` line.
|
|
473
|
-
|
|
474
|
-
**Deeper diagnostic:** `vnc.sh` and the in-page wrapper now refuse to start (and exit with a snap-Chromium reference in the boot log) when `chromium-binary.path` is absent or its realpath lands under `/snap/`. If you see those messages, the install completed before the fix shipped — re-run `npx -y @rubytech/create-maxy@latest`. Manual workaround for an emergency (not a fix): `sudo apt-get install -y google-chrome-stable` and confirm `which google-chrome-stable` is non-snap, then re-run the installer to write `chromium-binary.path`.
|
|
475
|
-
|
|
476
|
-
---
|
|
477
|
-
|
|
478
|
-
## Terminal iframe renders black and cursor vanishes over the canvas
|
|
479
|
-
|
|
480
|
-
**Symptom:** Header-menu Terminal click appears to succeed — no error toast, overlay opens — but the iframe renders uniformly black, keystrokes do not reach any shell, and the mouse cursor disappears the moment it enters the iframe (visible elsewhere in the page).
|
|
481
|
-
|
|
482
|
-
**What it means:** This is the exact symptom class that earlier platform fixes closed. Before 632, `/usr/bin/gnome-terminal` would receive `DISPLAY=:99` but D-Bus-delegate the window-create request to the session's `gnome-terminal-server`, which opens the window on `:0` (the operator's physical screen) instead. The iframe, rendering `:99`, has no window to show — hence the black canvas, dead keystrokes, and null-cursor (noVNC's Cursor pseudo-encoding renders `cursor: none` when the server sends no cursor). If you are seeing this *after* earlier platform fixes shipped, the installer did not run on this device or a stale bundle is in place.
|
|
483
|
-
|
|
484
|
-
Step-by-step diagnosis:
|
|
485
|
-
|
|
486
|
-
```bash
|
|
487
|
-
# 1. Check terminal-launch.log for the window-absent failure
|
|
488
|
-
sudo grep 'window absent from target display' ~/.maxy/logs/terminal-launch.log | tail -5
|
|
489
|
-
|
|
490
|
-
# 2. Verify the expected binaries are installed
|
|
491
|
-
which xterm xdotool # both must exist — installer adds them
|
|
492
|
-
|
|
493
|
-
# 3. Confirm the VNC display is serving the iframe
|
|
494
|
-
DISPLAY=:99 xdpyinfo >/dev/null 2>&1 && echo "display:99 ok"
|
|
495
|
-
DISPLAY=:99 xdotool search --onlyvisible --class '.' # non-empty means windows ARE on:99
|
|
496
|
-
|
|
497
|
-
# 4. Check which binary resolve_terminal_bin chose
|
|
498
|
-
grep 'cmd=' ~/.maxy/logs/terminal-launch.log | tail -3
|
|
499
|
-
# Expected for remote-origin clicks: cmd="/usr/bin/xterm"
|
|
500
|
-
# If you see: cmd="/usr/bin/gnome-terminal --wait" on:99 → stale bundle, re-run installer
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
If the failure log shows `window absent from target display`, the fix already ran but spawn still went to the wrong display — re-run the installer (`npx -y @rubytech/create-maxy@latest`) from a shell to pick up the latest `xterm` + `xdotool` preflight. If the failure log shows no recent entries and the iframe is still black, check `ss -ltn '(sport = 6080 or sport = 5900)'` and `pgrep -af Xtigervnc|websockify` — the symptom might be a VNC-stack regression rather than a terminal-binary mismatch.
|
|
504
|
-
|
|
505
|
-
Both the header Terminal and the Software Update modal's Upgrade button now share the same VNC spawn pipeline, so a failure in one usually reproduces in the other — if the header Terminal opens a blank shell cleanly but the Upgrade modal errors, the problem is upgrade-specific (see "Software Update click shows an error" above).
|
|
192
|
+
- **Software update.** Re-run `npx -y @rubytech/create-<brand>@latest` from a shell; if the installer fails, its stdout is the diagnostic record. HeaderMenu turns sage when `installed === latest`.
|
|
193
|
+
- **Cloudflare setup.** The agent invokes `cloudflared` directly via Bash, following the cloudflare plugin's `references/manual-setup.md`. Failures surface as cloudflared's literal stderr plus a non-zero exit. Recovery paths live in `references/reset-guide.md` and `references/manual-setup.md`.
|
|
506
194
|
|
|
507
195
|
## Orphan Account Directory Archived to `.trash/`
|
|
508
196
|
|
|
@@ -23,13 +23,44 @@ Outcome (binding):
|
|
|
23
23
|
|
|
24
24
|
Constraint (binding): **No downstream venture-studio skill (`brand-pack`, `zero-to-prototype`, `investor-data-room` Stages 3+, etc.) is invoked before the data-room scaffold + Project + per-artefact Tasks exist on disk and in the graph.** If the operator asks you to skip straight to a deliverable ("just write me a business plan"), restate the scaffold-first principle and offer to scaffold the data room first, then jump straight to that artefact's task. The principle is the outcome contract; the scaffold proves it.
|
|
25
25
|
|
|
26
|
+
### Deterministic pre-flight gate
|
|
27
|
+
|
|
28
|
+
Before invoking any downstream skill, both checks below must pass. Both are deterministic — exit-code on `ls`, structured output on `project-list`. Neither check depends on LLM judgement.
|
|
29
|
+
|
|
30
|
+
1. **Directory check:** `[ -d "${PROJECT_ROOT}/.docs/data-room/01-narrative" ]` returns exit 0.
|
|
31
|
+
2. **Graph check:** the `project-list` tool returns a Project whose `name` matches the business's working name.
|
|
32
|
+
|
|
33
|
+
If either check fails, run the scaffolding script (see below) before the skill fires. If the script fails, surface the literal stderr error to the operator — do not narrate around it (memory: [[feedback_no_stdout_parsing_for_control_flow]]).
|
|
34
|
+
|
|
35
|
+
### Scaffolding script
|
|
36
|
+
|
|
37
|
+
`bin/scaffold.sh` is the deterministic enforcement layer. It creates the Project + eight artefact Tasks (via the work plugin's `project-create-cli` bridge) and materialises the ten-section directory tree. Graph write first, directories second; idempotent re-run if any partial state lands.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ACCOUNT_ID="${ACCOUNT_ID}" \
|
|
41
|
+
premium-plugins/venture-studio/bin/scaffold.sh \
|
|
42
|
+
"${PROJECT_ROOT}" \
|
|
43
|
+
"${BUSINESS_NAME}"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The script is the binding check, not the prose principle above. The prose explains why; the script is what makes it true.
|
|
47
|
+
|
|
26
48
|
## First-conversation routing
|
|
27
49
|
|
|
28
|
-
When the operator first invokes this agent, confirm the intent ("Are we founding a new business, or working on an existing one?") and run the scaffolding
|
|
50
|
+
When the operator first invokes this agent, confirm the intent ("Are we founding a new business, or working on an existing one?") and run the scaffolding script — it does steps 1–3 below in a single atomic invocation:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ACCOUNT_ID="${ACCOUNT_ID}" \
|
|
54
|
+
premium-plugins/venture-studio/bin/scaffold.sh \
|
|
55
|
+
"${PROJECT_ROOT}" \
|
|
56
|
+
"${BUSINESS_NAME}"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The script's three effects:
|
|
29
60
|
|
|
30
|
-
1. **
|
|
31
|
-
2. **
|
|
32
|
-
3. **
|
|
61
|
+
1. **Scaffolds the data room.** Materialises the ten-section directory tree under `<project-root>/.docs/data-room/`. Every artefact has a slot to land in before any artefact is produced.
|
|
62
|
+
2. **Creates the `Project` node.** Tier `full` (data-room work is multi-phase). Project name is the business's working name; description references the data-room root path.
|
|
63
|
+
3. **Enumerates the eight artefact Tasks** in section order — one transaction, atomic with the Project. The work-item list the script pre-seeds:
|
|
33
64
|
- **Stage 1 — Office-hours design doc** → produces `01-narrative/office-hours-design.md` (skill: `office-hours`)
|
|
34
65
|
- **Brand pack** → produces brand identity files into `06-product-ip/brand/` (skill: `brand-pack`)
|
|
35
66
|
- **Stage 2 — Wedge validation + landing page + PRD** → produces `01-narrative/{PMF, LANDING, PRD}.md` (skill: `zero-to-prototype`)
|