proteum 2.3.0 → 2.4.2
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/AGENTS.md +8 -3
- package/README.md +20 -15
- package/agents/project/AGENTS.md +16 -10
- package/agents/project/DOCUMENTATION.md +1326 -0
- package/agents/project/app-root/AGENTS.md +2 -2
- package/agents/project/diagnostics.md +10 -9
- package/agents/project/optimizations.md +1 -1
- package/agents/project/root/AGENTS.md +15 -8
- package/agents/project/server/services/AGENTS.md +1 -0
- package/agents/project/tests/AGENTS.md +1 -0
- package/cli/commands/db.ts +160 -0
- package/cli/commands/dev.ts +148 -25
- package/cli/commands/diagnose.ts +2 -0
- package/cli/commands/explain.ts +38 -9
- package/cli/commands/mcp.ts +126 -9
- package/cli/commands/orient.ts +44 -17
- package/cli/commands/runtime.ts +100 -17
- package/cli/mcp/router.ts +1028 -0
- package/cli/presentation/commands.ts +56 -25
- package/cli/presentation/help.ts +1 -1
- package/cli/runtime/commands.ts +163 -21
- package/cli/runtime/devSessions.ts +328 -2
- package/cli/runtime/mcpDaemon.ts +288 -0
- package/cli/runtime/ports.ts +151 -0
- package/cli/utils/agents.ts +94 -17
- package/cli/utils/appRoots.ts +232 -0
- package/common/dev/database.ts +226 -0
- package/common/dev/diagnostics.ts +1 -1
- package/common/dev/inspection.ts +8 -1
- package/common/dev/mcpPayloads.ts +456 -17
- package/common/dev/mcpServer.ts +51 -0
- package/docs/agent-routing.md +32 -21
- package/docs/dev-commands.md +1 -1
- package/docs/dev-sessions.md +3 -1
- package/docs/diagnostics.md +21 -20
- package/docs/mcp.md +114 -50
- package/docs/migrate-from-2.1.3.md +3 -5
- package/docs/request-tracing.md +3 -3
- package/package.json +10 -3
- package/server/app/devDiagnostics.ts +92 -0
- package/server/app/devMcp.ts +55 -0
- package/server/services/prisma/mariadb.ts +7 -3
- package/server/services/router/http/index.ts +25 -0
- package/server/services/router/request/ip.test.cjs +0 -1
- package/tests/agents-utils.test.cjs +58 -3
- package/tests/cli-mcp-command.test.cjs +327 -0
- package/tests/codex-mcp-usage.test.cjs +307 -0
- package/tests/dev-sessions.test.cjs +113 -0
- package/tests/dev-transpile-watch.test.cjs +0 -1
- package/tests/eslint-rules.test.cjs +0 -1
- package/tests/inspection.test.cjs +0 -1
- package/tests/mcp.test.cjs +769 -2
- package/tests/router-cache-config.test.cjs +0 -1
- package/vitest.config.mjs +9 -0
- package/cli/mcp/provider.ts +0 -365
- package/cli/mcp/stdio.ts +0 -16
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This file is the app-root-only addendum for a Proteum app that lives inside a larger monorepo.
|
|
4
4
|
Keep the reusable Proteum contract in the nearest ancestor root `AGENTS.md`, and keep this file only for instructions that depend on the current directory being the Proteum app root.
|
|
5
5
|
Role: keep only app-root workflow and local project-semantic rules here.
|
|
6
|
-
Do not put here: reusable Proteum architecture contracts, shared verification rules, diagnostics workflow, optimization checklists, coding-style details, or area-specific rules already covered by broader `AGENTS.md` files or the root-level `diagnostics.md`, `optimizations.md`, and `CODING_STYLE.md`.
|
|
6
|
+
Do not put here: reusable Proteum architecture contracts, shared verification rules, documentation-driven coding workflow, diagnostics workflow, optimization checklists, coding-style details, or area-specific rules already covered by broader `AGENTS.md` files or the root-level `DOCUMENTATION.md`, `diagnostics.md`, `optimizations.md`, and `CODING_STYLE.md`.
|
|
7
7
|
|
|
8
8
|
## App-Root Triggers
|
|
9
9
|
|
|
@@ -13,4 +13,4 @@ Do not put here: reusable Proteum architecture contracts, shared verification ru
|
|
|
13
13
|
- Read and acknowledge the applicable `AGENTS.md` files.
|
|
14
14
|
- Run `npm i`.
|
|
15
15
|
- Run the dev server with the task-safe elevated-permissions launch workflow from the reusable root `AGENTS.md`, keep it running so user can see the results by himself, and print the live server URL as a clickable Markdown link. If `proteum dev` reports blocked instruction paths, resolve them before continuing.
|
|
16
|
-
- If the task changes UX, copy, onboarding, pricing, product semantics, or commercial positioning,
|
|
16
|
+
- If the task changes UX, copy, onboarding, pricing, product semantics, or commercial positioning, use root-level `DOCUMENTATION.md` to choose the smallest relevant `./docs/` pack before editing. If a dev server is already running, print the live dev server URL as a clickable Markdown link.
|
|
@@ -4,9 +4,9 @@ This file is the canonical source of truth for diagnostics, temporary instrument
|
|
|
4
4
|
|
|
5
5
|
## Initial Triage
|
|
6
6
|
|
|
7
|
-
- Start with compact machine-readable app state before reading large parts of the codebase
|
|
8
|
-
-
|
|
9
|
-
- MCP payloads are compact `proteum-mcp-v1` JSON and are capped/paginated by default.
|
|
7
|
+
- Start with compact machine-readable app state before reading large parts of the codebase. When a Proteum MCP client is available, call MCP `workflow_start` with `cwd` or a known `projectId`; if it is ambiguous or returns offline app candidates, call `project_resolve { cwd }`, select the intended app root, start exactly one dev server from that app root when needed, then retry `workflow_start`. Use the returned live `projectId` for follow-up MCP `runtime_status`, `orient`, `instructions_resolve`, `explain_summary`, `route_candidates`, `doctor`, `diagnose`, `trace_latest`, `trace_show`, `perf_top`, `perf_request`, `logs_tail`, and `db_query`.
|
|
8
|
+
- Do not run CLI equivalents after a successful MCP result for the same read. Do not run broad source searches for route/page/controller ownership after MCP returns the owner. Use compact CLI commands such as `npx proteum orient <query>`, `npx proteum runtime status`, `npx proteum connect`, `npx proteum explain`, `npx proteum doctor`, and `npx proteum doctor --contracts` when MCP is unavailable, when generated artifacts or manifest-owned files may be stale, or when you need a reproducible shell command, validation step, or CI-like output.
|
|
9
|
+
- MCP payloads are compact `proteum-mcp-v1` JSON and are capped/paginated by default. Use selected instruction previews for read-only discovery and diagnostics; read full files or request full MCP detail only when returned `fullRead`/`fullReadPolicy` or omitted-detail hints require it.
|
|
10
10
|
- Use full-detail escape hatches only after compact output identifies the missing detail: `npx proteum explain --manifest`, `npx proteum diagnose <target> --full`, `npx proteum trace show <requestId> --events`, or `npx proteum perf request <requestId> --full`.
|
|
11
11
|
- When the user pastes raw errors, reproduce locally before listing possible causes: identify the likely app, route, command, or request target from the error, boot or reuse the relevant dev server with the elevated-permissions workflow below, replay the failing surface once, and base the probability/why/how-to-fix list on local server output, browser console output, diagnostics, traces, or the smallest relevant command result. If there is not enough information to reproduce, state the missing context and ground the cause list in the local evidence that is available.
|
|
12
12
|
- When one app depends on another app's generated controllers, inspect `npx proteum connect --controllers`, `npx proteum explain --connected --controllers`, the producer `proteum.connected.json`, the consumer `proteum.config.ts` connected `source` value, and the producer `./.proteum/proteum.connected.d.ts` before assuming the contract is local.
|
|
@@ -16,16 +16,17 @@ This file is the canonical source of truth for diagnostics, temporary instrument
|
|
|
16
16
|
|
|
17
17
|
## Runtime Diagnostics
|
|
18
18
|
|
|
19
|
-
- For long-lived dev reproductions, always request elevated permissions and run `npx proteum dev` outside the sandbox. Use an explicit task/thread-scoped session file, inspect `npx proteum
|
|
19
|
+
- For long-lived dev reproductions, always request elevated permissions and run `npx proteum dev` outside the sandbox. Use an explicit task/thread-scoped session file, inspect `npx proteum runtime status` first, then use its exact next action so occupied router/HMR ports and untracked same-app runtimes are handled without page-body probes. After the server is ready, print the live server URL as a clickable Markdown link.
|
|
20
20
|
- Use `--replace-existing` only when restarting the exact session file started by the current thread/task. Never replace another live session that belongs to a user, another thread, or an unknown owner.
|
|
21
21
|
- Only the bare `npx proteum build` and bare `npx proteum dev` commands print the welcome banner and active Proteum installation method. Any extra argument or option skips the banner. Only `npx proteum dev` clears the interactive terminal before rendering and reports connected app names plus successful connected `/ping` checks in the ready banner; keep that in mind when capturing or comparing command logs during diagnosis. Every `npx proteum dev` start ensures tracked instruction files contain the current managed `# Proteum Instructions` section before the dev loop begins.
|
|
22
22
|
- During `npx proteum dev`, the running app exposes the read-only Proteum MCP transport at `/__proteum/mcp`. Use it for runtime-adjacent agent reads instead of repeatedly spawning equivalent CLI diagnostics.
|
|
23
|
-
-
|
|
24
|
-
- For
|
|
23
|
+
- If machine MCP routing fails, run `npx proteum mcp status` and `npx proteum runtime status` from the intended app root. If no live session exists, use the exact MCP offline or runtime-status next action so occupied router/HMR ports are avoided. If the same app already responds on the configured port without live tracking, use or repair that runtime instead of starting another server. Do not `curl` normal page routes to identify which app owns a port; use runtime status or Proteum dev-only endpoints. If a live session exists but runtime/MCP is unreachable, stop the listed session file first, then start dev again. Do not start a second dev server in the same worktree, and do not start a second managed MCP daemon. Do not run diagnose, trace, or perf reads while runtime health is unreachable. Then retry MCP `workflow_start` and use the returned `projectId`.
|
|
24
|
+
- For ownership or repo discovery questions, start with MCP `workflow_start`; use MCP `route_candidates { projectId, query }`, MCP `orient { projectId, query }`, and MCP `explain_summary { projectId, query }` only when the bootstrap owner summary is insufficient. Use `npx proteum orient <query>` or `npx proteum explain owner <query>` only when MCP is unavailable or terminal evidence is required.
|
|
25
|
+
- For request-time issues in dev, start with MCP `diagnose { projectId, path }` when you have a concrete failing route, page, controller path, or request target. Use `npx proteum diagnose <path> --port <port>` only when MCP is unavailable or terminal evidence is required. It combines owner lookup, manifest diagnostics, contract diagnostics, matching trace data, and buffered server logs in one pass.
|
|
25
26
|
- Prefer focused verification before global checks: `npx proteum verify owner <query>`, `npx proteum verify request <path>`, and only then browser MCP validation when the bug is browser-visible. Use `npx proteum e2e --port <port> ...` only when automated end-to-end coverage or a Playwright suite is required.
|
|
26
27
|
- When diagnosing a consumer app that depends on local `file:` connected projects, boot every connected producer app too, each on its own free port and task-scoped session file, and run every one of those `proteum dev` processes with elevated permissions outside the sandbox before reproducing the consumer issue.
|
|
27
28
|
- For connected-project failures, confirm the consumer app resolves the expected `connect.<Namespace>.source` and `connect.<Namespace>.urlInternal` values, the producer app exposes `GET /api/__proteum/connected/ping`, and the imported controller entries show `scope=connected` in `proteum explain`.
|
|
28
|
-
- Use `
|
|
29
|
+
- Use MCP `workflow_start`, `route_candidates { projectId, query }`, or `explain_summary { projectId, query }` when you need a fast ownership graph for a route, controller path, source file, or generated artifact before reading code. Use `npx proteum explain owner <query>` only when MCP is unavailable or terminal evidence is required. Do not use `npx proteum explain --routes --full` unless compact owner/route tools explicitly cannot answer a raw route-array question.
|
|
29
30
|
- For performance issues or regressions in dev, use `npx proteum perf top --since <window>` to rank hot paths, `npx proteum perf request <requestId|path>` for one request waterfall plus chain attribution and SQL fingerprints, `npx proteum perf compare --baseline <window> --target <window>` for regressions, and `npx proteum perf memory --since <window>` for heap or RSS drift.
|
|
30
31
|
- For bundle-size inspection, use `npx proteum build --prod --analyze` to emit `bin/bundle-analysis/client.html` and `client-stats.json`, or add `--analyze-serve --analyze-port auto` when you want a local analyzer URL instead of a static HTML file.
|
|
31
32
|
- For request-time issues in dev, inspect traces before adding logs when the diagnose surface is still too coarse.
|
|
@@ -38,7 +39,7 @@ This file is the canonical source of truth for diagnostics, temporary instrument
|
|
|
38
39
|
## Temporary Instrumentation
|
|
39
40
|
|
|
40
41
|
- When manifest inspection, trace data, browser console output, and server errors are still insufficient, add temporary targeted logs in the code to confirm control flow, payload shape, query shape, or branch selection.
|
|
41
|
-
- If SQL is needed during diagnosis,
|
|
42
|
+
- If SQL is needed during diagnosis, use MCP `db_query { projectId, sql }` or `npx proteum db query "<sql>"` against a running dev server. Keep it read-only: only one capped `SELECT`, `SHOW`, or `EXPLAIN` statement is allowed, and the response includes rows, columns, elapsed milliseconds, and cap metadata. Never use SQL to change database structure or execute schema-mutating DDL.
|
|
42
43
|
- Keep temporary logs narrow, contextual, and easy to remove. Do not leave broad debug noise in shared execution paths.
|
|
43
44
|
- Re-run only the smallest relevant repro, request, or test after adding temporary instrumentation.
|
|
44
45
|
- Temporary logs added in the code for diagnosis must be cleaned at the end of tests or the repro cycle and must never be committed.
|
|
@@ -57,7 +58,7 @@ This file is the canonical source of truth for diagnostics, temporary instrument
|
|
|
57
58
|
- After implementing a change, verify at the smallest trustworthy layer required by the changed surface first, then run the full project `npx proteum check` before finishing. Do not default to a running app, browser MCP, or Playwright while iterating when a narrower static or request-level verification is enough.
|
|
58
59
|
- For compile-time or type-safety issues, start with the relevant targeted typecheck or build command. Do not run them by default for unrelated runtime, copy, docs, or local refactor changes.
|
|
59
60
|
- For request/runtime issues, verify through the real page, route, generated controller call, or command on a running app.
|
|
60
|
-
- Start the smallest trustworthy runtime surface first: `
|
|
61
|
+
- Start the smallest trustworthy runtime surface first: MCP `workflow_start`, then MCP `route_candidates { projectId, query }`, MCP `orient { projectId, query }`, or MCP `explain_summary { projectId, query }` only when more owner detail is needed. If runtime health is unreachable, repair/start dev before any diagnose, trace, or perf read. Once runtime is reachable, use the relevant real URL, generated controller call, command, or MCP `diagnose { projectId, path }`. Use CLI equivalents only when MCP is unavailable or terminal evidence is required. Use browser MCP validation only when request-level verification is insufficient or the change is browser-visible.
|
|
61
62
|
- When automated browser assertions or suite coverage are required, use `npx proteum e2e --port <port>` for targeted or full Playwright suites. Do not use direct Playwright for browser validation outside the E2E wrapper, and do not launch raw browser automation against a shared persistent profile.
|
|
62
63
|
- Focused verification should treat unrelated global diagnostics as visible but non-blocking by default. Use `--strict-global` only when the task explicitly requires broad clean-room validation.
|
|
63
64
|
- For browser regressions, prefer a browser MCP repro first and add targeted Playwright E2E coverage only when the user asks for automated coverage, when a stable regression path needs automation, or when browser MCP verification is insufficient.
|
|
@@ -19,7 +19,7 @@ When tradeoffs exist inside optimization work, optimize in this order:
|
|
|
19
19
|
- Prefer established, flexible, well-typed, widely adopted, actively maintained packages.
|
|
20
20
|
- Build custom or keep custom infrastructure only when packages would clearly hurt bundle size, SSR behavior, performance, typing quality, flexibility, licensing, explicit contracts, or long-term maintainability.
|
|
21
21
|
- If you choose custom over a package, state briefly why.
|
|
22
|
-
- For agent-facing repeated diagnostics, prefer the read-only Proteum MCP surface over adding broader CLI output. MCP should expose compact single-line `proteum-mcp-v1` JSON with capped, typed, paginated reads; the CLI should stay compact and reproducible.
|
|
22
|
+
- For agent-facing repeated diagnostics, prefer the read-only Proteum MCP surface over adding broader CLI output. MCP should expose compact single-line `proteum-mcp-v1` JSON with capped, typed, paginated reads; the CLI should stay compact and reproducible. Database diagnostics are limited to one capped `SELECT`, `SHOW`, or `EXPLAIN` read through MCP `db_query` or CLI `proteum db query`.
|
|
23
23
|
|
|
24
24
|
## SSR And Page Size
|
|
25
25
|
|
|
@@ -3,20 +3,24 @@
|
|
|
3
3
|
This is the reusable Proteum-wide contract that is safe to place at the root of a monorepo above one or more Proteum apps.
|
|
4
4
|
Pair this file with an app-root `AGENTS.md` inside each Proteum app when local workflow or product-context instructions depend on the current directory being the app root.
|
|
5
5
|
Role: keep only reusable Proteum workflow, architecture contracts, shared typing rules, and cross-surface verification rules here.
|
|
6
|
-
Do not put here: app-root bootstrap steps,
|
|
6
|
+
Do not put here: app-root bootstrap steps, documentation-driven coding workflow, detailed diagnostics workflow, optimization checklists, coding-style details, or narrow area-specific instructions that belong in `DOCUMENTATION.md`, `diagnostics.md`, `optimizations.md`, `CODING_STYLE.md`, `client/AGENTS.md`, `client/pages/AGENTS.md`, `server/routes/AGENTS.md`, `server/services/AGENTS.md`, or `tests/AGENTS.md`.
|
|
7
7
|
|
|
8
|
+
Documentation source of truth: root-level `DOCUMENTATION.md`.
|
|
8
9
|
Optimization source of truth: root-level `optimizations.md`.
|
|
9
10
|
Diagnostics source of truth: root-level `diagnostics.md`.
|
|
10
11
|
Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
11
12
|
|
|
13
|
+
Managed compact root routers must use trigger -> canonical instruction file references, not copied summaries of this contract. If a trigger points here, load this full file before acting and keep the source rule here.
|
|
14
|
+
|
|
12
15
|
## Fast Triggers
|
|
13
16
|
|
|
14
17
|
- If the user pastes raw errors without asking for a fix, do not implement changes yet. First run the task-safe local reproduction path: identify the likely app, route, command, or request from the error, boot or reuse the relevant dev server with the elevated-permissions workflow in `Task Lifecycle`, reproduce the failing surface locally, and inspect server output, browser console output, diagnostics, traces, or the smallest relevant command result. If the error does not identify enough context to reproduce, say what is missing and use the available local evidence before guessing. Then list likely causes and, for each one, give probability, why, and how to fix it.
|
|
15
18
|
- If the user asks to implement a feature, first inspect the relevant existing surface and state any implementation problem, pain point, attention point, or question you see. If a concern is blocking, or it can materially change product behavior, API shape, architecture, data model, cost, privacy, security, or UX, ask before editing; otherwise state the assumption and continue implementing.
|
|
16
|
-
- If the task is ambiguous, generated, connected, or multi-repo, start with `npx proteum orient <query>`
|
|
17
|
-
- Treat Proteum CLI and MCP output as the workflow router.
|
|
18
|
-
- When a Proteum MCP client is available,
|
|
19
|
+
- If the task is ambiguous, generated, connected, or multi-repo, start with MCP `workflow_start` and then MCP `orient { projectId, query }` only if the bootstrap did not return a sufficient owner or next action; use `npx proteum orient <query>` only when MCP is unavailable or terminal evidence is required.
|
|
20
|
+
- Treat Proteum CLI and MCP output as the workflow router. Treat instruction previews returned by MCP `workflow_start` or `instructions_resolve { projectId }` as the allowed instruction scope for read-only discovery and diagnostics. Read full file contents only before edits or git writes, when returned `fullRead`/`fullReadPolicy` requires it, or when the compact preview is insufficient. Do not read broad instruction folders or every managed instruction file up front.
|
|
21
|
+
- When a Proteum MCP client is available, first call MCP `workflow_start` with `cwd` or a known `projectId`. If it is ambiguous or returns offline app candidates, call `project_resolve { cwd }`, select the intended app root, start exactly one dev server from that app root when needed, then retry `workflow_start`. Pass the returned live `projectId` to every follow-up app-bound MCP tool. `npx proteum dev` ensures one managed machine MCP daemon is running; do not start a second managed daemon. Prefer MCP `runtime_status`, `orient`, `instructions_resolve`, `explain_summary`, `route_candidates`, `doctor`, `diagnose`, `trace_show`, `perf_request`, `logs_tail`, and `db_query` for read-only runtime/status/orientation/owner/route/trace/perf/log/database reads. Do not run CLI equivalents after a successful MCP result for the same read. Do not run broad source searches for route/page/controller ownership after MCP returns the owner. Use CLI commands when you need reproducible terminal validation, dev/build/check workflows, fallback repair, or output to share with a human.
|
|
19
22
|
- MCP payloads are compact single-line `proteum-mcp-v1` JSON with capped and paginated detail. Do not expand MCP output for human readability.
|
|
23
|
+
- For every non-trivial coding task, load and follow root-level `DOCUMENTATION.md` before coding.
|
|
20
24
|
- If the user reports an issue, or the agent encounters one during exploration, implementation, verification, or runtime reproduction, load and follow root-level `diagnostics.md`.
|
|
21
25
|
- If the task touches client-side files, especially `client/**` and page files, load and apply root-level `optimizations.md` only after implementation for post-implementation checking and optimization. Skip it at task start and skip it for server-only, test-only, doc-only, and non-client refactor tasks unless the user explicitly asks for optimization work.
|
|
22
26
|
- If the task needs new app or artifact boilerplate, prefer `npx proteum init ...` and `npx proteum create ...` before creating files by hand. Use `--dry-run --json` when an agent needs a machine-readable plan before writing files.
|
|
@@ -47,16 +51,18 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
47
51
|
### During Implementation
|
|
48
52
|
|
|
49
53
|
- After running `npx proteum create ...`, adapt the generated code to the real feature instead of leaving placeholder logic in place.
|
|
50
|
-
- When starting a long-lived dev server for an agent task, always request elevated permissions and run `npx proteum dev` outside the sandbox. Use an explicit task/thread-scoped session file such as `var/run/proteum/dev/agents/<task>.json`, inspect `npx proteum
|
|
54
|
+
- When starting a long-lived dev server for an agent task, always request elevated permissions and run `npx proteum dev` outside the sandbox. Use an explicit task/thread-scoped session file such as `var/run/proteum/dev/agents/<task>.json`, inspect `npx proteum runtime status` first, then use its exact Start Dev next action so occupied router/HMR ports are avoided. Do not `curl` normal page routes to identify a port owner; use Proteum runtime status or dev-only `/__proteum/*` endpoints. After the server is ready, print the live server URL as a clickable Markdown link.
|
|
51
55
|
- Use `--replace-existing` only when restarting the exact session file started by the current thread/task. Never replace another live session that belongs to a user, another thread, or an unknown owner.
|
|
56
|
+
- Do not start a second `npx proteum dev` server in the same worktree, and do not start a second managed MCP daemon. If machine MCP routing fails, run `npx proteum mcp status` and `npx proteum runtime status` from the intended app root; if no live session exists, use the exact MCP offline or runtime-status next action instead of assuming the manifest default port. If the same app already responds on the configured port without live tracking, use or repair that runtime instead of starting another server. If a live session exists but runtime/MCP is unreachable, stop the listed session file first, then start dev again. Do not run diagnose, trace, or perf reads while runtime health is unreachable. Then retry MCP `workflow_start` and use the returned `projectId`.
|
|
52
57
|
- If the current app depends on local `file:` connected projects, boot every connected producer app too, each with its own task-scoped session file and free port, and run every one of those `proteum dev` processes with elevated permissions outside the sandbox before starting or verifying the consumer app.
|
|
53
|
-
- During `npx proteum dev`, the app exposes the read-only Proteum MCP runtime endpoint at `/__proteum/mcp`; use it for repeated agent reads instead of spawning equivalent diagnostics commands.
|
|
58
|
+
- During `npx proteum dev`, the app exposes the read-only Proteum MCP runtime endpoint at `/__proteum/mcp`; use it for repeated agent reads instead of spawning equivalent diagnostics commands. For route/page/controller ownership, prefer MCP `workflow_start`, `route_candidates { projectId, query }`, or `explain_summary { projectId, query }` over broad `npx proteum explain --routes --controllers --full` dumps.
|
|
54
59
|
- For browser validation, use the browser MCP against the running app. Keep Playwright inside `npx proteum e2e --port <port>` for targeted/full end-to-end suites. Bootstrap protected browser MCP state with `npx proteum session`; bootstrap protected E2E runs with `npx proteum e2e --session-email <email> --session-role <role>`.
|
|
55
60
|
- Current CLI banner contract: only the bare `proteum build` and bare `proteum dev` commands print the welcome banner and include the active Proteum installation method. Any extra argument or option skips the banner. Only `proteum dev` clears the interactive terminal before rendering, exposes `CTRL+R` reload plus `CTRL+C` shutdown hotkeys in its session UI, and reports connected app names plus successful connected `/ping` checks in the ready banner. Every `proteum dev` start ensures tracked instruction files contain the current managed `# Proteum Instructions` section before the dev loop begins.
|
|
56
61
|
|
|
57
62
|
### Before Finishing
|
|
58
63
|
|
|
59
64
|
- Before finishing, re-check touched files against root-level `CODING_STYLE.md` and any narrower area `AGENTS.md` that applied to the edit. Re-check against root-level `optimizations.md` only for touched client-side files. Re-check against root-level `diagnostics.md` only if the task involved an issue, diagnosis, runtime reproduction, or verification failure.
|
|
65
|
+
- For production changes, always add or update focused unit tests for the touched behavior when applicable. Target 100% meaningful unit coverage for changed production paths, and document any generated files, migrations, framework shims, unreachable defensive branches, or changes that cannot reasonably be unit-tested.
|
|
60
66
|
- Run the full project `npx proteum check` before finishing each feature or change. Targeted lint, typecheck, diagnose, request, browser, or E2E runs are still useful while iterating, but they do not replace the final full check. After implementing a new feature or changing existing feature behavior, always update the end-to-end coverage for that behavior and run the full Playwright test suite before finishing. For docs-only, wording-only, type-only, test-only, generated-output cleanup, or clearly local non-runtime refactors, skip Playwright unless the user explicitly asks for it or verification reveals a real issue.
|
|
61
67
|
- Before finishing a task, stop every `proteum dev` session started during the task and confirm cleanup with `npx proteum dev list --json` or an explicit `npx proteum dev stop --session-file <path>`.
|
|
62
68
|
- When you have finished your work, ask the user whether they want a commit message. After providing a commit message or after creating a commit, immediately follow it with this exact prompt and obey it:
|
|
@@ -173,7 +179,7 @@ Verify at the correct layer:
|
|
|
173
179
|
- SSR changes: use the browser MCP to load the real page and inspect rendered HTML plus browser console.
|
|
174
180
|
- Router or plugin changes: verify request context, auth, redirects, metrics, and validation on a running app.
|
|
175
181
|
- New features or feature-behavior changes: use the cheapest trustworthy verification while iterating, use the browser MCP for browser-visible validation, then update the relevant end-to-end coverage and finish by running the full Playwright suite plus the full project `npx proteum check`.
|
|
176
|
-
- Generated, connected, or ownership-ambiguous changes: start with `npx proteum orient <query>` and
|
|
182
|
+
- Generated, connected, or ownership-ambiguous changes: start with MCP `workflow_start`, then `orient { projectId, query }` and `explain_summary { projectId, query }` only when more detail is needed; use `npx proteum orient <query>` and `npx proteum verify owner <query>` when MCP is unavailable or terminal evidence is required.
|
|
177
183
|
- Browser-visible issues: use the browser MCP after request-level verification is insufficient. Use `npx proteum e2e --port <port> ...` only when automated end-to-end coverage or a Playwright suite is required.
|
|
178
184
|
- Raw browser execution outside end-to-end suites: use the browser MCP only. Keep Playwright in `npx proteum e2e --port <port>` for targeted/full end-to-end suites.
|
|
179
185
|
- For trace-first reproduction, session-based auth setup, temporary logs, and post-fix surface checks, follow root-level `diagnostics.md`.
|
|
@@ -216,6 +222,7 @@ Verify at the correct layer:
|
|
|
216
222
|
## Hard Stops
|
|
217
223
|
|
|
218
224
|
- Never run schema-mutating SQL such as `ALTER TABLE`, `CREATE TABLE`, `DROP TABLE`, or `CREATE INDEX` to change database structure.
|
|
225
|
+
- For read-only SQL diagnosis, use MCP `db_query` or `npx proteum db query "<sql>"`; only one capped `SELECT`, `SHOW`, or `EXPLAIN` statement is allowed.
|
|
219
226
|
- Do not run `prisma *` yourself. If a schema change requires migration, ask the user to run `npx prisma migrate dev --config ./prisma.config.ts --name <migration name>` and wait for `continue`.
|
|
220
227
|
- Do not run `git restore` or `git reset`.
|
|
221
228
|
- Do not run write-mode git commands by default. The built-in exception is an exact `commit` reply, which allows `git add` and `git commit` in every affected repository or worktree touched during the whole conversation. Any other write-mode git action requires an explicit user request.
|
|
@@ -271,10 +278,10 @@ Prefer structured CLI surfaces over re-deriving framework facts from source:
|
|
|
271
278
|
- `npx proteum orient <query>`
|
|
272
279
|
- `npx proteum runtime status`
|
|
273
280
|
- `npx proteum mcp`
|
|
274
|
-
- `npx proteum mcp --url http://localhost:<port>`
|
|
275
281
|
- `npx proteum explain`
|
|
276
282
|
- `npx proteum explain --manifest`
|
|
277
283
|
- `npx proteum explain --connected --controllers`
|
|
284
|
+
- `npx proteum explain --connected --controllers --full` only when raw connected/controller arrays are required
|
|
278
285
|
- `npx proteum explain owner <query>`
|
|
279
286
|
- `npx proteum doctor`
|
|
280
287
|
- `npx proteum doctor --contracts`
|
|
@@ -31,6 +31,7 @@ Diagnostics source of truth: root-level `diagnostics.md`.
|
|
|
31
31
|
- In database queries, prefer explicit `select` or narrow `include`.
|
|
32
32
|
- For database structure changes, edit the app's `schema.prisma` only. Never create or edit migration files manually.
|
|
33
33
|
- Never use raw SQL DDL or other schema-mutating SQL to change database structure.
|
|
34
|
+
- For read-only SQL diagnosis, use MCP `db_query` or `npx proteum db query "<sql>"`; only one capped `SELECT`, `SHOW`, or `EXPLAIN` statement is allowed.
|
|
34
35
|
- Prefer inferred return types such as `Awaited<ReturnType<MyService['methodName']>>` over manual DTO duplication.
|
|
35
36
|
|
|
36
37
|
## Errors
|
|
@@ -9,6 +9,7 @@ Diagnostics source of truth: root-level `diagnostics.md`.
|
|
|
9
9
|
|
|
10
10
|
- Understand the real user flow and the main feature branches before writing tests.
|
|
11
11
|
- Test the current controller/page runtime model, not legacy `@Route` or `api.fetch(...)` behavior.
|
|
12
|
+
- For every production change, add or update focused unit tests when applicable. Target 100% meaningful coverage for changed production paths, and document any generated files, migrations, framework shims, unreachable defensive branches, or changes that cannot reasonably be unit-tested.
|
|
12
13
|
- Verify routing, controllers, SSR, and router plugins against a running app when behavior depends on real request handling.
|
|
13
14
|
- After implementing a new feature or changing existing feature behavior, update the end-to-end coverage for that behavior and run the full Playwright suite before finishing. Prefer `npx proteum e2e --port <port>` for Playwright runs so base URLs and auth tokens are passed through Proteum-managed child env instead of shell-leading environment assignments. Use a browser MCP repro against a running app during iteration when it is the fastest trustworthy loop.
|
|
14
15
|
- Exercise real URLs, generated controller calls, or real browser flows instead of re-deriving framework internals in tests.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import got from 'got';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { UsageError } from 'clipanion';
|
|
5
|
+
|
|
6
|
+
import cli from '..';
|
|
7
|
+
import {
|
|
8
|
+
defaultDatabaseReadTimeoutMs,
|
|
9
|
+
maxDatabaseReadLimit,
|
|
10
|
+
maxDatabaseReadTimeoutMs,
|
|
11
|
+
type TDatabaseReadQueryResponse,
|
|
12
|
+
} from '../../common/dev/database';
|
|
13
|
+
import { printAgentResponse, printJson, quoteCommandArgument } from '../utils/agentOutput';
|
|
14
|
+
|
|
15
|
+
type TDbAction = 'query';
|
|
16
|
+
|
|
17
|
+
const allowedActions = new Set<TDbAction>(['query']);
|
|
18
|
+
const normalizeBaseUrl = (value: string) => value.replace(/\/+$/, '');
|
|
19
|
+
|
|
20
|
+
const getRouterPortFromManifest = () => {
|
|
21
|
+
const manifestFilepath = path.join(cli.args.workdir as string, '.proteum', 'manifest.json');
|
|
22
|
+
if (!fs.existsSync(manifestFilepath)) return undefined;
|
|
23
|
+
|
|
24
|
+
const manifest = fs.readJsonSync(manifestFilepath, { throws: false }) as
|
|
25
|
+
| { env?: { resolved?: { routerPort?: number } } }
|
|
26
|
+
| undefined;
|
|
27
|
+
const port = manifest?.env?.resolved?.routerPort;
|
|
28
|
+
|
|
29
|
+
if (typeof port !== 'number' || port <= 0) return undefined;
|
|
30
|
+
|
|
31
|
+
return String(port);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const getRouterPort = () => {
|
|
35
|
+
const overridePort = typeof cli.args.port === 'string' && cli.args.port ? cli.args.port : '';
|
|
36
|
+
if (overridePort) return overridePort;
|
|
37
|
+
|
|
38
|
+
const envPort = process.env.PORT?.trim();
|
|
39
|
+
if (envPort) return envPort;
|
|
40
|
+
|
|
41
|
+
const manifestPort = getRouterPortFromManifest();
|
|
42
|
+
if (manifestPort) return manifestPort;
|
|
43
|
+
|
|
44
|
+
throw new UsageError(
|
|
45
|
+
`Could not determine the router port from PORT or .proteum/manifest.json in ${cli.args.workdir as string}. Pass --port or --url explicitly.`,
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const getRouterBaseUrls = () => {
|
|
50
|
+
const explicitUrl = typeof cli.args.url === 'string' && cli.args.url ? cli.args.url.trim() : '';
|
|
51
|
+
if (explicitUrl) return [normalizeBaseUrl(explicitUrl)];
|
|
52
|
+
|
|
53
|
+
const port = getRouterPort();
|
|
54
|
+
return [...new Set([`http://127.0.0.1:${port}`, `http://localhost:${port}`, `http://[::1]:${port}`])];
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const parsePositiveInteger = (value: unknown, label: string, max: number) => {
|
|
58
|
+
if (typeof value !== 'string' || !value.trim()) return undefined;
|
|
59
|
+
|
|
60
|
+
const parsed = Number(value);
|
|
61
|
+
if (!Number.isInteger(parsed) || parsed <= 0) throw new UsageError(`${label} must be a positive integer.`);
|
|
62
|
+
if (parsed > max) throw new UsageError(`${label} must be ${max} or lower.`);
|
|
63
|
+
|
|
64
|
+
return parsed;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const requestJson = async <TResponse>(pathname: string, json: object) => {
|
|
68
|
+
const attempts: string[] = [];
|
|
69
|
+
|
|
70
|
+
for (const baseUrl of getRouterBaseUrls()) {
|
|
71
|
+
try {
|
|
72
|
+
const response = await got(`${baseUrl}${pathname}`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
json,
|
|
75
|
+
responseType: 'json',
|
|
76
|
+
retry: { limit: 0 },
|
|
77
|
+
throwHttpErrors: false,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (response.statusCode >= 400) {
|
|
81
|
+
const body = response.body as { error?: string } | undefined;
|
|
82
|
+
throw new UsageError(body?.error || `Database query failed with status ${response.statusCode}.`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return response.body as TResponse;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (error instanceof UsageError) throw error;
|
|
88
|
+
|
|
89
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
90
|
+
attempts.push(`${baseUrl}${pathname}: ${message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
throw new UsageError(
|
|
95
|
+
[
|
|
96
|
+
'Could not reach the Proteum database diagnostics server.',
|
|
97
|
+
...attempts.map((attempt) => `- ${attempt}`),
|
|
98
|
+
'Make sure the app is running with `proteum dev`, or pass `--url http://host:port` if it is bound elsewhere.',
|
|
99
|
+
].join('\n'),
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const buildFullCommand = (sql: string) =>
|
|
104
|
+
[
|
|
105
|
+
'proteum db query',
|
|
106
|
+
quoteCommandArgument(sql),
|
|
107
|
+
typeof cli.args.limit === 'string' && cli.args.limit ? `--limit ${cli.args.limit}` : '',
|
|
108
|
+
typeof cli.args.timeout === 'string' && cli.args.timeout ? `--timeout ${cli.args.timeout}` : '',
|
|
109
|
+
typeof cli.args.port === 'string' && cli.args.port ? `--port ${cli.args.port}` : '',
|
|
110
|
+
typeof cli.args.url === 'string' && cli.args.url ? `--url ${quoteCommandArgument(cli.args.url)}` : '',
|
|
111
|
+
'--full',
|
|
112
|
+
]
|
|
113
|
+
.filter(Boolean)
|
|
114
|
+
.join(' ');
|
|
115
|
+
|
|
116
|
+
export const run = async () => {
|
|
117
|
+
const action = typeof cli.args.action === 'string' && cli.args.action ? cli.args.action : 'query';
|
|
118
|
+
if (!allowedActions.has(action as TDbAction)) {
|
|
119
|
+
throw new UsageError(`Unsupported db action "${action}". Expected: query.`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const sql = typeof cli.args.sql === 'string' ? cli.args.sql.trim() : '';
|
|
123
|
+
if (!sql) throw new UsageError('A SELECT, SHOW, or EXPLAIN SQL statement is required.');
|
|
124
|
+
|
|
125
|
+
const limit = parsePositiveInteger(cli.args.limit, '--limit', maxDatabaseReadLimit);
|
|
126
|
+
const timeoutMs = parsePositiveInteger(cli.args.timeout, '--timeout', maxDatabaseReadTimeoutMs);
|
|
127
|
+
const response = await requestJson<TDatabaseReadQueryResponse>('/__proteum/db/query', {
|
|
128
|
+
sql,
|
|
129
|
+
...(limit !== undefined ? { limit } : {}),
|
|
130
|
+
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (cli.args.full === true) {
|
|
134
|
+
printJson(response);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
printAgentResponse({
|
|
139
|
+
summary: `${response.kind.toUpperCase()} returned ${response.rows.length}/${response.rowCount} rows in ${response.elapsedMs} ms${response.limited ? ` (limited to ${response.limit})` : ''}.`,
|
|
140
|
+
data: {
|
|
141
|
+
kind: response.kind,
|
|
142
|
+
elapsedMs: response.elapsedMs,
|
|
143
|
+
rowCount: response.rowCount,
|
|
144
|
+
returnedRowCount: response.rows.length,
|
|
145
|
+
limit: response.limit,
|
|
146
|
+
limited: response.limited,
|
|
147
|
+
columns: response.columns,
|
|
148
|
+
rows: response.rows,
|
|
149
|
+
},
|
|
150
|
+
fullDetailCommand: buildFullCommand(sql),
|
|
151
|
+
omitted: response.limited
|
|
152
|
+
? [
|
|
153
|
+
{
|
|
154
|
+
reason: `Rows are capped at ${response.limit}. Raise --limit up to ${maxDatabaseReadLimit} or narrow the query for more detail.`,
|
|
155
|
+
command: `proteum db query ${quoteCommandArgument(sql)} --limit ${Math.min(response.limit * 2, maxDatabaseReadLimit)} --timeout ${timeoutMs || defaultDatabaseReadTimeoutMs}`,
|
|
156
|
+
},
|
|
157
|
+
]
|
|
158
|
+
: undefined,
|
|
159
|
+
});
|
|
160
|
+
};
|
package/cli/commands/dev.ts
CHANGED
|
@@ -28,19 +28,24 @@ import { clearInteractiveConsole } from '../presentation/welcome';
|
|
|
28
28
|
import { renderWarning } from '../presentation/ink';
|
|
29
29
|
import {
|
|
30
30
|
createDevSessionRecord,
|
|
31
|
-
inspectDevSessionFile,
|
|
32
31
|
listDevSessionInspections,
|
|
32
|
+
prepareDevSessionStart,
|
|
33
33
|
removeDevSessionRecord,
|
|
34
34
|
removeDevSessionRecordSync,
|
|
35
35
|
resolveDevSessionFilePath,
|
|
36
36
|
stopDevSessionFile,
|
|
37
37
|
updateDevSessionRecord,
|
|
38
|
+
writeDevSessionRecord,
|
|
39
|
+
writeMachineDevSessionRecord,
|
|
38
40
|
type TDevSessionInspection,
|
|
39
41
|
type TStopDevSessionResult,
|
|
40
42
|
} from '../runtime/devSessions';
|
|
41
43
|
import { resolveFrameworkInstallInfo } from '../paths';
|
|
42
44
|
import { logVerbose } from '../runtime/verbose';
|
|
45
|
+
import { ensureMachineMcpDaemonProcess } from '../runtime/mcpDaemon';
|
|
46
|
+
import { inspectDevPort, type TDevPortInspection } from '../runtime/ports';
|
|
43
47
|
import { configureProjectAgentInstructions, resolveProjectAgentMonorepoRoot } from '../utils/agents';
|
|
48
|
+
import { quoteCommandArgument } from '../utils/agentOutput';
|
|
44
49
|
|
|
45
50
|
// Core
|
|
46
51
|
import { app, App } from '../app';
|
|
@@ -335,6 +340,40 @@ const describeStopResult = (result: TStopDevSessionResult) => {
|
|
|
335
340
|
.join(' | ');
|
|
336
341
|
};
|
|
337
342
|
|
|
343
|
+
const describeBlockingDevSession = (inspection: TDevSessionInspection) => {
|
|
344
|
+
if (!inspection.record) {
|
|
345
|
+
return [
|
|
346
|
+
'- invalid session',
|
|
347
|
+
inspection.sessionFilePath,
|
|
348
|
+
inspection.parseError || 'Unreadable session file.',
|
|
349
|
+
]
|
|
350
|
+
.filter(Boolean)
|
|
351
|
+
.join(' | ');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const publicUrl = inspection.record.publicUrl || `http://localhost:${inspection.record.routerPort}`;
|
|
355
|
+
|
|
356
|
+
return [
|
|
357
|
+
`- pid ${inspection.record.pid}`,
|
|
358
|
+
`port ${inspection.record.routerPort}`,
|
|
359
|
+
publicUrl,
|
|
360
|
+
`session ${inspection.sessionFilePath}`,
|
|
361
|
+
].join(' | ');
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const createBlockingDevSessionMessage = (blocking: TDevSessionInspection[]) => {
|
|
365
|
+
const firstSessionFilePath = blocking[0]?.sessionFilePath || '<session-file>';
|
|
366
|
+
|
|
367
|
+
return [
|
|
368
|
+
`A Proteum dev session is already running for ${app.paths.root}.`,
|
|
369
|
+
'Stop the existing session before starting another server in the same worktree:',
|
|
370
|
+
...blocking.map(describeBlockingDevSession),
|
|
371
|
+
'',
|
|
372
|
+
`Run: npx proteum dev stop --session-file ${quoteCommandArgument(firstSessionFilePath)}`,
|
|
373
|
+
'Then start dev again with the intended session file and port.',
|
|
374
|
+
].join('\n');
|
|
375
|
+
};
|
|
376
|
+
|
|
338
377
|
const printJson = (payload: unknown) => {
|
|
339
378
|
process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
|
|
340
379
|
};
|
|
@@ -400,38 +439,120 @@ const runStopCommand = async () => {
|
|
|
400
439
|
|
|
401
440
|
const ensureDevSessionSlot = async () => {
|
|
402
441
|
const sessionFilePath = getResolvedDevSessionFilePath();
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
`A Proteum dev session is already registered at ${sessionFilePath} (pid ${existingInspection.record.pid}, port ${existingInspection.record.routerPort}). ` +
|
|
409
|
-
'Use `proteum dev stop` or restart with `proteum dev --replace-existing`.',
|
|
410
|
-
);
|
|
411
|
-
}
|
|
442
|
+
const startPreparation = await prepareDevSessionStart({
|
|
443
|
+
appRoot: app.paths.root,
|
|
444
|
+
replaceExisting: cli.args.replaceExisting === true,
|
|
445
|
+
sessionFilePath,
|
|
446
|
+
});
|
|
412
447
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
throw new Error(`Could not stop the existing Proteum dev session registered at ${sessionFilePath}.`);
|
|
416
|
-
}
|
|
417
|
-
} else if (existingInspection) {
|
|
418
|
-
await stopDevSessionFile(sessionFilePath);
|
|
448
|
+
if (startPreparation.blocking.length > 0) {
|
|
449
|
+
throw new Error(createBlockingDevSessionMessage(startPreparation.blocking));
|
|
419
450
|
}
|
|
420
451
|
|
|
421
452
|
currentDevSessionFilePath = sessionFilePath;
|
|
422
453
|
registerDevSessionExitCleanup();
|
|
423
|
-
|
|
424
|
-
|
|
454
|
+
const sessionRecord = createDevSessionRecord({
|
|
455
|
+
appRoot: app.paths.root,
|
|
456
|
+
port: app.env.router.port,
|
|
425
457
|
sessionFilePath,
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}),
|
|
431
|
-
{ spaces: 2 },
|
|
432
|
-
);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
await writeDevSessionRecord(sessionRecord);
|
|
461
|
+
await writeMachineDevSessionRecord(sessionRecord);
|
|
433
462
|
|
|
434
463
|
logVerbose(`Registered Proteum dev session at ${sessionFilePath}.`);
|
|
464
|
+
if (startPreparation.cleaned.length > 0) {
|
|
465
|
+
logVerbose(
|
|
466
|
+
`Cleaned ${startPreparation.cleaned.length} stale Proteum dev session file${startPreparation.cleaned.length === 1 ? '' : 's'}.`,
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
if (startPreparation.replaced) {
|
|
470
|
+
logVerbose(`Replaced Proteum dev session at ${startPreparation.replaced.sessionFilePath}.`);
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const ensureMachineMcpDaemonForDev = async () => {
|
|
475
|
+
try {
|
|
476
|
+
const result = await ensureMachineMcpDaemonProcess({ coreRoot: cli.paths.core.root });
|
|
477
|
+
const record = result.inspection.record;
|
|
478
|
+
if (!record) return;
|
|
479
|
+
|
|
480
|
+
logVerbose(
|
|
481
|
+
result.started
|
|
482
|
+
? `Started Proteum machine MCP daemon at ${record.mcpUrl}.`
|
|
483
|
+
: `Proteum machine MCP daemon already running at ${record.mcpUrl}.`,
|
|
484
|
+
);
|
|
485
|
+
} catch (error) {
|
|
486
|
+
console.warn(
|
|
487
|
+
`Warning: Proteum could not ensure the machine MCP daemon. ${
|
|
488
|
+
error instanceof Error ? error.message : String(error)
|
|
489
|
+
}`,
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
const describeDevPortBlocker = (inspection: TDevPortInspection) => {
|
|
495
|
+
const lines = [
|
|
496
|
+
`Proteum cannot start this dev server on port ${inspection.router.port}.`,
|
|
497
|
+
`Router port ${inspection.router.port}: ${inspection.router.available ? 'free' : 'occupied'}.`,
|
|
498
|
+
`HMR port ${inspection.hmr.port}: ${inspection.hmr.available ? 'free' : 'occupied'}.`,
|
|
499
|
+
];
|
|
500
|
+
|
|
501
|
+
if (!inspection.router.available && inspection.router.proteum && inspection.router.matchesApp) {
|
|
502
|
+
lines.push(
|
|
503
|
+
`The router port is already serving this Proteum app${inspection.router.app?.appRoot ? ` from ${inspection.router.app.appRoot}` : ''}.`,
|
|
504
|
+
);
|
|
505
|
+
lines.push('Next action: run `npx proteum runtime status`, use or stop the existing runtime, then start one tracked dev session.');
|
|
506
|
+
lines.push('Do not start a second dev server for the same worktree.');
|
|
507
|
+
} else if (!inspection.router.available && inspection.router.proteum) {
|
|
508
|
+
lines.push(
|
|
509
|
+
`The router port is already serving ${inspection.router.app?.identifier || inspection.router.app?.name || 'another Proteum app'}${inspection.router.app?.appRoot ? ` from ${inspection.router.app.appRoot}` : ''}.`,
|
|
510
|
+
);
|
|
511
|
+
lines.push(
|
|
512
|
+
inspection.recommendedPort
|
|
513
|
+
? `Next action: npx proteum dev --session-file var/run/proteum/dev/agents/<task>.json --port ${inspection.recommendedPort}`
|
|
514
|
+
: 'Next action: choose a free router/HMR port pair, then rerun proteum dev with --port <free-port>.',
|
|
515
|
+
);
|
|
516
|
+
} else if (!inspection.router.available) {
|
|
517
|
+
lines.push('The router port is occupied by a non-Proteum or unrecognized process.');
|
|
518
|
+
lines.push(
|
|
519
|
+
inspection.recommendedPort
|
|
520
|
+
? `Next action: npx proteum dev --session-file var/run/proteum/dev/agents/<task>.json --port ${inspection.recommendedPort}`
|
|
521
|
+
: 'Next action: choose a free router/HMR port pair, then rerun proteum dev with --port <free-port>.',
|
|
522
|
+
);
|
|
523
|
+
} else if (!inspection.hmr.available) {
|
|
524
|
+
lines.push('The HMR port is occupied.');
|
|
525
|
+
lines.push(
|
|
526
|
+
inspection.recommendedPort
|
|
527
|
+
? `Next action: npx proteum dev --session-file var/run/proteum/dev/agents/<task>.json --port ${inspection.recommendedPort}`
|
|
528
|
+
: 'Next action: choose a free router/HMR port pair, then rerun proteum dev with --port <free-port>.',
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
lines.push('Do not inspect page bodies to identify the owner; use `npx proteum runtime status` for compact port/runtime state.');
|
|
533
|
+
|
|
534
|
+
return lines.join('\n');
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
const ensureConfiguredDevPortsAvailable = async () => {
|
|
538
|
+
const inspection = await inspectDevPort({
|
|
539
|
+
appRoot: app.paths.root,
|
|
540
|
+
port: app.env.router.port,
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
if (inspection.canStartOnConfiguredPort) return;
|
|
544
|
+
|
|
545
|
+
if (cli.args.replaceExisting === true) {
|
|
546
|
+
const requestedSessionFilePath = getResolvedDevSessionFilePath();
|
|
547
|
+
const [requestedSession] = await listDevSessionInspections({
|
|
548
|
+
appRoot: app.paths.root,
|
|
549
|
+
sessionFilePath: requestedSessionFilePath,
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
if (requestedSession?.record && requestedSession.live) return;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
throw new Error(describeDevPortBlocker(inspection));
|
|
435
556
|
};
|
|
436
557
|
|
|
437
558
|
async function startApp(app: App) {
|
|
@@ -757,8 +878,10 @@ const createIndexedSourceWatching = ({
|
|
|
757
878
|
|
|
758
879
|
const runDevLoop = async () => {
|
|
759
880
|
devSessionStopping = false;
|
|
881
|
+
await ensureConfiguredDevPortsAvailable();
|
|
760
882
|
clearInteractiveConsole();
|
|
761
883
|
await ensureDevSessionSlot();
|
|
884
|
+
await ensureMachineMcpDaemonForDev();
|
|
762
885
|
const proteumInstall = resolveFrameworkInstallInfo({
|
|
763
886
|
appRoot: app.paths.root,
|
|
764
887
|
framework: cli.paths.framework,
|
package/cli/commands/diagnose.ts
CHANGED
|
@@ -187,6 +187,7 @@ const renderOrientation = (response: TDiagnoseResponse) =>
|
|
|
187
187
|
: [
|
|
188
188
|
'Orientation',
|
|
189
189
|
`- agents=${response.orientation.guidance.agents}`,
|
|
190
|
+
`- documentation=${response.orientation.guidance.documentation}`,
|
|
190
191
|
`- diagnostics=${response.orientation.guidance.diagnostics}`,
|
|
191
192
|
`- optimizations=${response.orientation.guidance.optimizations}`,
|
|
192
193
|
`- codingStyle=${response.orientation.guidance.codingStyle}`,
|
|
@@ -343,6 +344,7 @@ const printCompactDiagnose = ({
|
|
|
343
344
|
instructions: response.orientation
|
|
344
345
|
? {
|
|
345
346
|
mustRead: [...new Set([response.orientation.guidance.agents, ...response.orientation.guidance.areaAgents])],
|
|
347
|
+
documentation: response.orientation.guidance.documentation,
|
|
346
348
|
diagnostics: response.orientation.guidance.diagnostics,
|
|
347
349
|
codingStyle: response.orientation.guidance.codingStyle,
|
|
348
350
|
optimizations: response.orientation.guidance.optimizations,
|