proteum 2.1.9 → 2.2.1
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/.codex/environments/environment.toml +11 -0
- package/AGENTS.md +27 -11
- package/README.md +30 -11
- package/agents/project/AGENTS.md +172 -123
- package/agents/project/CODING_STYLE.md +1 -1
- package/agents/project/app-root/AGENTS.md +16 -0
- package/agents/project/client/AGENTS.md +5 -5
- package/agents/project/client/pages/AGENTS.md +13 -13
- package/agents/project/diagnostics.md +19 -10
- package/agents/project/optimizations.md +5 -6
- package/agents/project/root/AGENTS.md +297 -0
- package/agents/project/server/routes/AGENTS.md +2 -2
- package/agents/project/server/services/AGENTS.md +4 -2
- package/agents/project/tests/AGENTS.md +9 -2
- package/cli/app/index.ts +31 -7
- package/cli/commands/configure.ts +226 -0
- package/cli/commands/dev.ts +0 -2
- package/cli/commands/diagnose.ts +33 -1
- package/cli/commands/explain.ts +1 -1
- package/cli/commands/migrate.ts +51 -0
- package/cli/commands/orient.ts +169 -0
- package/cli/commands/perf.ts +8 -1
- package/cli/commands/verify.ts +1003 -49
- package/cli/compiler/artifacts/manifest.ts +4 -4
- package/cli/compiler/artifacts/routing.ts +2 -2
- package/cli/compiler/artifacts/services.ts +12 -3
- package/cli/compiler/client/index.ts +65 -19
- package/cli/compiler/common/files/style.ts +47 -2
- package/cli/compiler/common/generatedRouteModules.ts +31 -38
- package/cli/compiler/common/index.ts +10 -0
- package/cli/compiler/common/proteumManifest.ts +1 -0
- package/cli/compiler/server/index.ts +34 -9
- package/cli/context.ts +6 -1
- package/cli/index.ts +7 -8
- package/cli/migrate/pageContract.ts +516 -0
- package/cli/paths.ts +47 -6
- package/cli/presentation/commands.ts +100 -10
- package/cli/presentation/devSession.ts +4 -6
- package/cli/presentation/help.ts +2 -2
- package/cli/presentation/ink.ts +10 -5
- package/cli/presentation/welcome.ts +2 -4
- package/cli/runtime/commands.ts +94 -1
- package/cli/scaffold/index.ts +2 -2
- package/cli/scaffold/templates.ts +4 -2
- package/cli/utils/agents.ts +273 -58
- package/client/dev/profiler/index.tsx +3 -2
- package/client/router.ts +10 -2
- package/client/services/router/index.tsx +6 -22
- package/common/dev/connect.ts +20 -4
- package/common/dev/console.ts +7 -0
- package/common/dev/contractsDoctor.ts +354 -0
- package/common/dev/diagnostics.ts +10 -7
- package/common/dev/inspection.ts +830 -38
- package/common/dev/performance.ts +19 -5
- package/common/dev/profiler.ts +1 -0
- package/common/dev/proteumManifest.ts +5 -4
- package/common/dev/requestTrace.ts +78 -1
- package/common/env/proteumEnv.ts +10 -3
- package/common/router/contracts.ts +8 -11
- package/common/router/index.ts +2 -2
- package/common/router/pageData.ts +72 -0
- package/common/router/register.ts +10 -46
- package/common/router/response/page.ts +28 -16
- package/docs/assets/unique-domains-chip.png +0 -0
- package/docs/dev-sessions.md +8 -4
- package/docs/diagnostics.md +77 -11
- package/docs/migrate-from-2.1.3.md +388 -0
- package/docs/request-tracing.md +42 -9
- package/package.json +6 -1
- package/scripts/update-codex-agents.ts +2 -2
- package/server/app/container/console/index.ts +11 -1
- package/server/app/container/trace/index.ts +370 -72
- package/server/app/devDiagnostics.ts +1 -1
- package/server/app/index.ts +5 -1
- package/server/services/auth/index.ts +9 -0
- package/server/services/prisma/index.ts +15 -12
- package/server/services/router/http/index.ts +1 -1
- package/server/services/router/index.ts +105 -23
- package/server/services/router/request/api.ts +7 -1
- package/server/services/router/request/index.ts +2 -1
- package/server/services/router/response/index.ts +8 -28
- package/types/global/vendors.d.ts +12 -0
- package/types/vendors.d.ts +12 -0
- package/common/router/pageSetup.ts +0 -51
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# Proteum Root Contract
|
|
2
|
+
|
|
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
|
+
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
|
+
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, local product-doc reading rules, detailed diagnostics workflow, optimization checklists, coding-style details, or narrow area-specific instructions that belong in `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
|
+
|
|
8
|
+
Optimization source of truth: root-level `optimizations.md`.
|
|
9
|
+
Diagnostics source of truth: root-level `diagnostics.md`.
|
|
10
|
+
Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
11
|
+
|
|
12
|
+
## Fast Triggers
|
|
13
|
+
|
|
14
|
+
- If the user pastes raw errors without asking for a fix, do not implement changes. List likely causes and, for each one, give probability, why, and how to fix it.
|
|
15
|
+
- If the task is ambiguous, generated, connected, or multi-repo, start with `npx proteum orient <query>` before reading large parts of the codebase.
|
|
16
|
+
- 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`.
|
|
17
|
+
- 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.
|
|
18
|
+
- 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.
|
|
19
|
+
- If you changed `schema.prisma`, do not start testing or validation yet. Ask the user to run the following command in the affected worktree directory, replacing the placeholders, and wait for the user to reply exactly `continue` before resuming validation or tests:
|
|
20
|
+
```
|
|
21
|
+
cd <worktree path>
|
|
22
|
+
npx prisma migrate dev --config ./prisma.config.ts --name <migration name>
|
|
23
|
+
```
|
|
24
|
+
- If you encounter `runtime/provider-hook-outside-provider`, `runtime/client-only-hook-in-ssr`, `runtime/router-context-outside-router`, or `runtime/connected-boundary-mismatch`, treat it as a framework contract failure first. Fix the provider, SSR/client, router, or connected boundary before assuming a local leaf-component bug.
|
|
25
|
+
- If the change is runtime-visible, request-time, router, SSR, browser-visible, or controller-behavior, use running-app verification.
|
|
26
|
+
- If the change is docs-only, wording-only, type-only, test-only, generated-output cleanup, or a clearly local non-runtime refactor, use static verification only unless the user explicitly asks for runtime verification or the agent finds a real issue.
|
|
27
|
+
- If the user replies exactly `commit`, generate one top-level short (up to 100 characters) sentence covering all changes made since the last `commit` and, if there has been no prior `commit`, since the beginning of the whole conversation, strictly using the Conventional Commits specification:
|
|
28
|
+
```
|
|
29
|
+
<type>[optional scope]: <description>
|
|
30
|
+
|
|
31
|
+
[optional body]
|
|
32
|
+
```
|
|
33
|
+
Then use that generated message, stage the task-related changed files with `git add` while avoiding unrelated user changes or incidental untracked files, and create the commit by running `git commit`. Do not stop at only suggesting the message.
|
|
34
|
+
After providing a commit message or after creating a commit, immediately follow it with this exact prompt and obey it:
|
|
35
|
+
`Explain in short minimalistic and few bullet points what we changed in this thread, like you would do to your grandma. Start with a verb in the past.`
|
|
36
|
+
|
|
37
|
+
## Task Lifecycle
|
|
38
|
+
|
|
39
|
+
### Before Editing
|
|
40
|
+
|
|
41
|
+
- Before changing any file, load root-level `CODING_STYLE.md` and any narrower area `AGENTS.md` that applies to the touched files. Do not spend response space explicitly acknowledging those reads unless the user asks.
|
|
42
|
+
|
|
43
|
+
### During Implementation
|
|
44
|
+
|
|
45
|
+
- After running `npx proteum create ...`, adapt the generated code to the real feature instead of leaving placeholder logic in place.
|
|
46
|
+
- 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 dev list --json` plus current listeners first, for example with `lsof -nP -iTCP -sTCP:LISTEN`, then choose a port that is not currently used before starting `npx proteum dev --session-file <path> --port <port>`. After the server is ready, print the live server URL as a clickable Markdown link.
|
|
47
|
+
- 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.
|
|
48
|
+
- 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.
|
|
49
|
+
- For raw browser automation, use `npx proteum verify browser` when it matches the task, or direct Playwright with a disposable profile when lower-level control is required. Bootstrap protected browser state through `npx proteum session`.
|
|
50
|
+
- 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.
|
|
51
|
+
|
|
52
|
+
### Before Finishing
|
|
53
|
+
|
|
54
|
+
- 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.
|
|
55
|
+
- Do not default to project-wide typecheck or `npx proteum check` after every change. 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.
|
|
56
|
+
- 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>`.
|
|
57
|
+
- 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:
|
|
58
|
+
`Explain in short minimalistic and few bullet points what we changed in this thread, like you would do to your grandma. Start with a verb in the past.`
|
|
59
|
+
|
|
60
|
+
## Core Contracts
|
|
61
|
+
|
|
62
|
+
- Client pages live in `client/pages/**` and register routes with top-level `Router.page(...)` or `Router.error(...)`.
|
|
63
|
+
- Page URLs come from the explicit `Router.page('/path', ...)` call, not from the file path.
|
|
64
|
+
- Callable app APIs live only in `server/controllers/**/*.ts` files that extend `Controller`.
|
|
65
|
+
- Dev-only internal execution lives only in `commands/**/*.ts` files that extend `Commands`.
|
|
66
|
+
- Manual HTTP endpoints live only in `server/routes/**`.
|
|
67
|
+
- Controllers call `this.input(schema)` inside the method body, at most once per method.
|
|
68
|
+
- Request-scoped state lives only on `this.request` and manual-route/router context objects.
|
|
69
|
+
- Keep one class or one React/Preact component per file.
|
|
70
|
+
- Prefer a deep tree grouped by business concern instead of long file names.
|
|
71
|
+
- Use the default `*.ts` or `*.tsx` file unless an `*.ssr.ts` or `*.ssr.tsx` variant is truly required.
|
|
72
|
+
- Never edit generated files under `.proteum`.
|
|
73
|
+
- When a task changes database structure, edit the app's `schema.prisma` only.
|
|
74
|
+
- Never create or edit migration files manually.
|
|
75
|
+
- Use `@generated/client/*`, `@generated/common/*`, and `@generated/server/*` for generated surfaces.
|
|
76
|
+
- Client context is typically imported from `@/client/context`.
|
|
77
|
+
- Normal service methods do not read request state directly.
|
|
78
|
+
- Do not import runtime values from `@models`.
|
|
79
|
+
- Do not use `@request` runtime globals.
|
|
80
|
+
- Do not use `@app` on the client.
|
|
81
|
+
- Prefer type inference rooted in the explicit application graph in `server/index.ts`.
|
|
82
|
+
|
|
83
|
+
## Surface Contracts
|
|
84
|
+
|
|
85
|
+
### App Bootstrap And Services
|
|
86
|
+
|
|
87
|
+
- `server/index.ts` default-exports the app `Application` subclass and is the canonical type root.
|
|
88
|
+
- Root services are public class fields instantiated with `new ServiceClass(this, config, this)`.
|
|
89
|
+
- Typed root-service config lives in `server/config/*.ts` via `Services.config(ServiceClass, { ... })`.
|
|
90
|
+
- Router plugins are instantiated explicitly inside the `Router` config `plugins` object.
|
|
91
|
+
- Router plugins can subscribe to `request` and `request.finished`; `request.profiling` exists before `request` runs and carries the finalized request/API/SQL snapshot by `request.finished`.
|
|
92
|
+
- Root business services live in `server/services/<Feature>/index.ts`.
|
|
93
|
+
- Root-service config lives in `server/config/*.ts` when the service needs config.
|
|
94
|
+
- Business logic lives in classes that extend `Service` and use `this.services`, `this.models`, and `this.app`.
|
|
95
|
+
- Keep auth, input parsing, locale, cookies, and request-derived values in controllers, then pass explicit typed arguments into services.
|
|
96
|
+
- Split growing features into explicit subservices.
|
|
97
|
+
- Companion client-callable entrypoints live in `server/controllers/**`.
|
|
98
|
+
- `proteum create service ...` scaffolds the service file, a typed config export under `server/config/*.ts`, and the root registration in `server/index.ts`; review and adapt the generated names before committing.
|
|
99
|
+
|
|
100
|
+
### Connected Projects
|
|
101
|
+
|
|
102
|
+
- Declare connected namespaces in `proteum.config.ts` with explicit values such as `connect: { Product: { source: PRODUCT_CONNECTED_SOURCE, urlInternal: PRODUCT_URL_INTERNAL } }`.
|
|
103
|
+
- Proteum does not infer connected env key names from the namespace. The source and internal URL must be provided explicitly in `proteum.config.ts`.
|
|
104
|
+
- Use `npx proteum connect` to inspect configured connect values, cached contract state, and imported controllers for the current app.
|
|
105
|
+
- Before launching a consumer app that depends on local `file:` connected sources, launch every connected producer app too, assign each one a free port, run each `proteum dev` outside the sandbox with elevated permissions, and make sure `connect.<Namespace>.urlInternal` resolves to those live producer URLs.
|
|
106
|
+
- `file:` connected sources point at another Proteum app root and keep strong connected typings.
|
|
107
|
+
- Non-local connected sources provide runtime helper generation but are intentionally typed loosely.
|
|
108
|
+
|
|
109
|
+
### Controllers
|
|
110
|
+
|
|
111
|
+
- Files live under `server/controllers/**/*.ts` and default-export a class extending `Controller`.
|
|
112
|
+
- Methods with bodies become generated client-callable endpoints.
|
|
113
|
+
- Route path comes from the controller file path plus the method name.
|
|
114
|
+
- `export const controllerPath = 'Custom/path'` can override the base path.
|
|
115
|
+
- Generated client calls use `POST`.
|
|
116
|
+
- Prefer `proteum create controller ...` for new controller boilerplate, then adapt the generated method to real service calls.
|
|
117
|
+
|
|
118
|
+
### Commands
|
|
119
|
+
|
|
120
|
+
- Files live under `commands/**/*.ts` and default-export a class extending `Commands` from `@server/app/commands`.
|
|
121
|
+
- Methods with bodies become generated dev commands.
|
|
122
|
+
- Command path comes from the file path plus the method name.
|
|
123
|
+
- `export const commandPath = 'Custom/path'` can override the base path.
|
|
124
|
+
- Commands are for dev-only internal execution through `proteum command ...` or the profiler `Commands` tab.
|
|
125
|
+
- Keep command logic internal; do not turn it into a normal controller unless it is a real app API.
|
|
126
|
+
- Prefer `proteum create command ...` for new command boilerplate.
|
|
127
|
+
|
|
128
|
+
### Client Pages
|
|
129
|
+
|
|
130
|
+
- Proteum scans page files for top-level `Router.page(...)` and `Router.error(...)` calls.
|
|
131
|
+
- File path controls chunk identity and layout discovery; route path comes from the explicit `Router.page(...)` string.
|
|
132
|
+
- The only supported page signature is `Router.page(path, options, data, render)`.
|
|
133
|
+
- `options` is always required. `data` is the only nullable argument and must be `null` when the page has no SSR data loader.
|
|
134
|
+
- `data` returns one flat object. Route-option keys such as `auth`, `layout`, `static`, and `_static` are forbidden in page data and must live in `options`.
|
|
135
|
+
- Controller fetchers and promises returned from `data` resolve before render.
|
|
136
|
+
- `render` consumes resolved page data and uses generated controller methods from render args or `@/client/context`.
|
|
137
|
+
- Use `api.reload(...)` or `api.set(...)` only when intentionally mutating active page data state.
|
|
138
|
+
- Error pages use `Router.error(code, options, render)` in `client/pages/_messages/**`.
|
|
139
|
+
- Prefer `proteum create page ...` for new page boilerplate, then review the explicit route path, options object, and data payload.
|
|
140
|
+
|
|
141
|
+
### Manual Routes
|
|
142
|
+
|
|
143
|
+
- Use `server/routes/**` only for explicit HTTP behavior that should not be a generated controller action.
|
|
144
|
+
- Good fits include redirects, sitemap or RSS output, OAuth callbacks, webhooks, and public resources with custom semantics.
|
|
145
|
+
- Import server-side app services from `@app` and use route handler context for `request`, `response`, router plugins, and custom router context.
|
|
146
|
+
- If the route is a normal app API, prefer a controller.
|
|
147
|
+
- Prefer `proteum create route ...` for new manual-route boilerplate.
|
|
148
|
+
|
|
149
|
+
### Models And Aliases
|
|
150
|
+
|
|
151
|
+
- Use Prisma typings from `@models/types`.
|
|
152
|
+
- Use runtime models through `this.models` or `this.app.Models.client`.
|
|
153
|
+
- Keep Prisma runtime access inside services when possible and prefer explicit `select` or narrow `include`.
|
|
154
|
+
- Do not import runtime values from `@models` or edit generated Prisma client files.
|
|
155
|
+
- Aliases:
|
|
156
|
+
- `@/client/...`, `@/server/...`, `@/common/...`: app code
|
|
157
|
+
- `@client/...`, `@server/...`, `@common/...`: Proteum core modules
|
|
158
|
+
- `@app`: server-side application services for manual routes only
|
|
159
|
+
- `@generated/*`: generated app surfaces
|
|
160
|
+
|
|
161
|
+
## Verification Matrix
|
|
162
|
+
|
|
163
|
+
Verify at the correct layer:
|
|
164
|
+
|
|
165
|
+
- Default: use the cheapest trustworthy verification for the changed surface first, then escalate only if the changed surface justifies it.
|
|
166
|
+
- Route additions: boot the app and hit the real URL.
|
|
167
|
+
- Controller changes: exercise the generated client call or generated `/api/...` endpoint.
|
|
168
|
+
- SSR changes: load the real page and inspect rendered HTML plus browser console.
|
|
169
|
+
- Router or plugin changes: verify request context, auth, redirects, metrics, and validation on a running app.
|
|
170
|
+
- New features or feature-behavior changes: use the cheapest trustworthy verification while iterating, then update the relevant end-to-end coverage and finish by running the full Playwright suite.
|
|
171
|
+
- Generated, connected, or ownership-ambiguous changes: start with `npx proteum orient <query>` and prefer `npx proteum verify owner <query>` before broad global checks.
|
|
172
|
+
- Browser-visible issues: prefer `npx proteum verify browser <path>` or the narrowest targeted Playwright pass only after request-level verification is insufficient.
|
|
173
|
+
- Raw browser execution beyond `npx proteum verify browser`: use direct Playwright with a disposable profile, and keep that step for the final verifier agent unless a narrower surface cannot reproduce the issue.
|
|
174
|
+
- For trace-first reproduction, session-based auth setup, temporary logs, and post-fix surface checks, follow root-level `diagnostics.md`.
|
|
175
|
+
|
|
176
|
+
## Implementation Rules
|
|
177
|
+
|
|
178
|
+
### Dependency Selection
|
|
179
|
+
|
|
180
|
+
- Before implementing a feature or change, first check whether the repo already includes a suitable dependency.
|
|
181
|
+
- If not, search npm before building a new utility, abstraction, component primitive, parser, formatter, or integration from scratch.
|
|
182
|
+
- Prefer the most popular, flexible, maintained packages that fit the project constraints.
|
|
183
|
+
- When the task explicitly involves client-side optimization work, use root-level `optimizations.md` to decide whether custom infrastructure is justified over an existing package.
|
|
184
|
+
- When you choose custom over a package, explain the reason briefly.
|
|
185
|
+
|
|
186
|
+
### Catalogs And Typing
|
|
187
|
+
|
|
188
|
+
- Keep one canonical catalog or registry file and import it everywhere else.
|
|
189
|
+
- Client-only catalogs live in `/client/catalogs/**`, server-only catalogs in `/server/catalogs/**`, and shared catalogs in `/common/catalogs/**`.
|
|
190
|
+
- Do not create nested `catalogs/` folders under pages, components, services, tests, or other feature folders.
|
|
191
|
+
- Keep strong TypeScript typings across the project.
|
|
192
|
+
- Do not introduce `any` or `unknown`, including through casts, helper aliases, or fallback generic defaults.
|
|
193
|
+
- Fix typing issues only on code you wrote.
|
|
194
|
+
- Never cast with `as any` or `as unknown`; fix the contract or add an explicit typed adapter.
|
|
195
|
+
|
|
196
|
+
### Design Rules
|
|
197
|
+
|
|
198
|
+
- Prefer explicit `server/index.ts` bootstrap over hidden registration.
|
|
199
|
+
- Prefer controller-backed app APIs over ad hoc manual `/api/...` routes.
|
|
200
|
+
- Prefer service classes over server helpers with hidden dependencies.
|
|
201
|
+
- Keep one canonical source of truth for catalogs, registries, and shared types.
|
|
202
|
+
- Reuse shared Shadcn-based UI primitives when the project already provides them.
|
|
203
|
+
|
|
204
|
+
### Discouraged Patterns
|
|
205
|
+
|
|
206
|
+
- request-scoped state inside normal service methods
|
|
207
|
+
- hiding route registration behind abstractions that remove the top-level `Router.page(...)` call
|
|
208
|
+
- editing `.proteum` directly
|
|
209
|
+
|
|
210
|
+
## Hard Stops
|
|
211
|
+
|
|
212
|
+
- Never run schema-mutating SQL such as `ALTER TABLE`, `CREATE TABLE`, `DROP TABLE`, or `CREATE INDEX` to change database structure.
|
|
213
|
+
- 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`.
|
|
214
|
+
- Do not run `git restore` or `git reset`.
|
|
215
|
+
- Do not run write-mode git commands by default. The built-in exception is an exact `commit` reply, which allows only task-scoped `git add` and `git commit`. Any other write-mode git action requires an explicit user request.
|
|
216
|
+
|
|
217
|
+
## Appendix
|
|
218
|
+
|
|
219
|
+
### Project Shape
|
|
220
|
+
|
|
221
|
+
This is a TypeScript, Node.js, Preact, Proteum monolith:
|
|
222
|
+
|
|
223
|
+
- `/client`: assets, catalogs, components, hooks, pages
|
|
224
|
+
- `/common`: shared functions, constants, types, and catalogs
|
|
225
|
+
- `/server`: catalogs, config, services, routes, lib
|
|
226
|
+
- `/tests`
|
|
227
|
+
|
|
228
|
+
### Source Of Truth
|
|
229
|
+
|
|
230
|
+
Proteum reads:
|
|
231
|
+
|
|
232
|
+
- `package.json`
|
|
233
|
+
- `identity.config.ts` for app identity via `Application.identity({ ... })`
|
|
234
|
+
- `proteum.config.ts` for compiler setup via `Application.setup({ transpile, connect })`
|
|
235
|
+
- `process.env` via `PORT`, `ENV_*`, `URL`, `URL_INTERNAL`, any app-chosen connected-project values referenced by `proteum.config.ts`, `TRACE_*`, and `ENABLE_PROFILER`
|
|
236
|
+
- `server/config/*.ts`
|
|
237
|
+
- `server/index.ts`
|
|
238
|
+
- `commands/**/*.ts`
|
|
239
|
+
- `server/controllers/**/*.ts`
|
|
240
|
+
- `server/routes/**/*.ts`
|
|
241
|
+
- `client/pages/**/*.ts(x)`
|
|
242
|
+
- `client/pages/**/_layout/index.tsx`
|
|
243
|
+
- `public/**`
|
|
244
|
+
|
|
245
|
+
Proteum owns:
|
|
246
|
+
|
|
247
|
+
- `.proteum/manifest.json`
|
|
248
|
+
- `.proteum/client/*`
|
|
249
|
+
- `.proteum/common/*`
|
|
250
|
+
- `.proteum/server/*`
|
|
251
|
+
|
|
252
|
+
Project code should consume:
|
|
253
|
+
|
|
254
|
+
- `@generated/client/*`
|
|
255
|
+
- `@generated/common/*`
|
|
256
|
+
- `@generated/server/*`
|
|
257
|
+
- `@/client/context` as the generated client context entrypoint
|
|
258
|
+
|
|
259
|
+
### Useful Commands
|
|
260
|
+
|
|
261
|
+
Prefer structured CLI surfaces over re-deriving framework facts from source:
|
|
262
|
+
|
|
263
|
+
- `npx proteum connect --json`
|
|
264
|
+
- `npx proteum connect --controllers --strict`
|
|
265
|
+
- `npx proteum orient <query>`
|
|
266
|
+
- `npx proteum explain --json`
|
|
267
|
+
- `npx proteum explain --connected --controllers`
|
|
268
|
+
- `npx proteum explain owner <query>`
|
|
269
|
+
- `npx proteum doctor --json`
|
|
270
|
+
- `npx proteum doctor --contracts --json`
|
|
271
|
+
- `npx proteum diagnose <path> --port <port>`
|
|
272
|
+
- `npx proteum verify owner <query>`
|
|
273
|
+
- `npx proteum verify request <path>`
|
|
274
|
+
- `npx proteum verify browser <path>`
|
|
275
|
+
- `npx proteum perf ...`
|
|
276
|
+
- `npx proteum trace ...`
|
|
277
|
+
- `npx proteum command ...`
|
|
278
|
+
- `npx proteum session ...`
|
|
279
|
+
- `npx proteum create ... --dry-run --json`
|
|
280
|
+
- `npx proteum dev list --json`
|
|
281
|
+
- `npx proteum dev stop --session-file <path>`
|
|
282
|
+
|
|
283
|
+
Prefer scaffold commands before hand-writing boilerplate:
|
|
284
|
+
|
|
285
|
+
- `npx proteum init <directory> --name <name>`
|
|
286
|
+
- `npx proteum init ... --dry-run --json`
|
|
287
|
+
- `npx proteum create page|controller|command|route|service <target>`
|
|
288
|
+
- `npx proteum create ... --dry-run --json`
|
|
289
|
+
|
|
290
|
+
### High-Impact Files
|
|
291
|
+
|
|
292
|
+
Edit these only when required, and keep changes minimal and explicit:
|
|
293
|
+
|
|
294
|
+
- `tsconfig*.json`
|
|
295
|
+
- `PORT`, `ENV_*`, `URL`, `TRACE_*`, and `ENABLE_PROFILER` env setup
|
|
296
|
+
- Prisma-generated files
|
|
297
|
+
- symbolic links
|
|
@@ -5,8 +5,8 @@ Role: keep only manual-route rules here.
|
|
|
5
5
|
Keep here: explicit HTTP route guidance, public/crawlable endpoint rules, absolute URL generation, and route-specific catalog placement.
|
|
6
6
|
Do not put here: controller contracts, service-layer business logic, page SSR rules, or broad project workflow already defined elsewhere.
|
|
7
7
|
|
|
8
|
-
Optimization source of truth:
|
|
9
|
-
Diagnostics source of truth:
|
|
8
|
+
Optimization source of truth: root-level `optimizations.md`.
|
|
9
|
+
Diagnostics source of truth: root-level `diagnostics.md`.
|
|
10
10
|
|
|
11
11
|
- Use `server/routes/**` only for explicit HTTP behavior that should not be generated from controllers.
|
|
12
12
|
- If the endpoint is a normal app API, prefer `server/controllers/**/*.ts`.
|
|
@@ -5,8 +5,8 @@ Role: keep only service-layer rules here.
|
|
|
5
5
|
Keep here: service placement, service responsibilities, model access, query-shaping, return-type guidance, and service error-handling rules.
|
|
6
6
|
Do not put here: request parsing, page/render rules, controller transport details, or broad project workflow already defined in higher-level AGENTS files.
|
|
7
7
|
|
|
8
|
-
Optimization source of truth:
|
|
9
|
-
Diagnostics source of truth:
|
|
8
|
+
Optimization source of truth: root-level `optimizations.md`.
|
|
9
|
+
Diagnostics source of truth: root-level `diagnostics.md`.
|
|
10
10
|
|
|
11
11
|
## Placement
|
|
12
12
|
|
|
@@ -29,6 +29,8 @@ Diagnostics source of truth: project-root `diagnostics.md`.
|
|
|
29
29
|
- Use runtime models through `this.models` or the app model accessors.
|
|
30
30
|
- Use Prisma typings through `@models/types` only.
|
|
31
31
|
- In database queries, prefer explicit `select` or narrow `include`.
|
|
32
|
+
- For database structure changes, edit the app's `schema.prisma` only. Never create or edit migration files manually.
|
|
33
|
+
- Never use raw SQL DDL or other schema-mutating SQL to change database structure.
|
|
32
34
|
- Prefer inferred return types such as `Awaited<ReturnType<MyService['methodName']>>` over manual DTO duplication.
|
|
33
35
|
|
|
34
36
|
## Errors
|
|
@@ -5,14 +5,21 @@ Role: keep only test-area rules here.
|
|
|
5
5
|
Keep here: runtime verification guidance, selector strategy, test-specific reuse rules, and authenticated test-flow expectations.
|
|
6
6
|
Do not put here: production implementation rules, page/service architecture contracts, or duplicated project workflow that belongs in broader AGENTS files.
|
|
7
7
|
|
|
8
|
-
Diagnostics source of truth:
|
|
8
|
+
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
12
|
- Verify routing, controllers, SSR, and router plugins against a running app when behavior depends on real request handling.
|
|
13
|
-
- After implementing a
|
|
13
|
+
- 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. Use a real browser repro against a running app during iteration when it is the fastest trustworthy loop.
|
|
14
14
|
- Exercise real URLs, generated controller calls, or real browser flows instead of re-deriving framework internals in tests.
|
|
15
|
+
- Organize end-to-end tests following the Crosspath platform layout under `tests/e2e/**`.
|
|
16
|
+
- Put runnable scenario entrypoints in `tests/e2e/features/**`, `tests/e2e/specs/<domain>/**`, or `tests/e2e/journeys/**` depending on scope.
|
|
17
|
+
- Put page objects and reusable UI surface wrappers in `tests/e2e/pages/**`.
|
|
18
|
+
- Put reusable multi-step user flows in `tests/e2e/workflows/**`.
|
|
19
|
+
- Put test data builders in `tests/e2e/factories/**` and generic helpers in `tests/e2e/utils/**`.
|
|
20
|
+
- Keep helpers out of spec files when they are reusable, and do not create ad hoc flat test files or duplicate support abstractions when an existing page, workflow, factory, or utility already fits.
|
|
15
21
|
- Locate elements with `data-testid`.
|
|
16
22
|
- Add `data-testid` where needed instead of relying on brittle selectors.
|
|
23
|
+
- Keep end-to-end tests clean, well organized, and non-redundant. Prefer extending or reshaping the most relevant existing scenario over duplicating coverage, and remove or consolidate overlap when the suite becomes repetitive.
|
|
17
24
|
- Reuse root catalog files from `/client/catalogs/**`, `/server/catalogs/**`, or `/common/catalogs/**` instead of duplicating catalog constants in tests.
|
|
18
25
|
- For protected dev flows, prefer `npx proteum session <email> --role <role>` over automating login unless the login flow itself is under test.
|
package/cli/app/index.ts
CHANGED
|
@@ -38,20 +38,34 @@ const normalizeModulePath = (value: string) => value.replace(/\\/g, '/').replace
|
|
|
38
38
|
|
|
39
39
|
const resolveTranspileModuleDirectories = ({
|
|
40
40
|
moduleNames,
|
|
41
|
-
|
|
41
|
+
resolvePackageRoot,
|
|
42
|
+
getVisiblePackageInstallRoots,
|
|
42
43
|
}: {
|
|
43
44
|
moduleNames: string[];
|
|
44
|
-
|
|
45
|
+
resolvePackageRoot: (moduleName: string) => string;
|
|
46
|
+
getVisiblePackageInstallRoots: (moduleName: string) => string[];
|
|
45
47
|
}) => {
|
|
46
48
|
const directories = new Set<string>();
|
|
47
49
|
|
|
48
50
|
for (const moduleName of moduleNames) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
const candidates = new Set<string>();
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
candidates.add(normalizeModulePath(resolvePackageRoot(moduleName)));
|
|
55
|
+
} catch {}
|
|
56
|
+
|
|
57
|
+
for (const visibleInstallRoot of getVisiblePackageInstallRoots(moduleName)) {
|
|
58
|
+
candidates.add(normalizeModulePath(visibleInstallRoot));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (const candidate of candidates) {
|
|
51
62
|
if (!fs.existsSync(candidate)) continue;
|
|
52
63
|
|
|
53
64
|
directories.add(candidate);
|
|
54
|
-
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
directories.add(normalizeModulePath(fs.realpathSync(candidate)));
|
|
68
|
+
} catch {}
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
71
|
|
|
@@ -136,15 +150,25 @@ export class App {
|
|
|
136
150
|
public get transpileModuleDirectories() {
|
|
137
151
|
return resolveTranspileModuleDirectories({
|
|
138
152
|
moduleNames: this.transpile,
|
|
139
|
-
|
|
153
|
+
resolvePackageRoot: (moduleName) => cli.paths.resolvePackageRoot(moduleName),
|
|
154
|
+
getVisiblePackageInstallRoots: (moduleName) => cli.paths.getVisiblePackageInstallRoots(moduleName),
|
|
140
155
|
});
|
|
141
156
|
}
|
|
142
157
|
|
|
143
158
|
public isTranspileModuleFile(filepath: string) {
|
|
144
159
|
const normalizedFilepath = normalizeModulePath(path.resolve(filepath));
|
|
160
|
+
let normalizedRealFilepath: string | undefined;
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
normalizedRealFilepath = normalizeModulePath(fs.realpathSync(filepath));
|
|
164
|
+
} catch {}
|
|
145
165
|
|
|
146
166
|
return this.transpileModuleDirectories.some(
|
|
147
|
-
(directory) =>
|
|
167
|
+
(directory) =>
|
|
168
|
+
normalizedFilepath === directory ||
|
|
169
|
+
normalizedFilepath.startsWith(directory + '/') ||
|
|
170
|
+
normalizedRealFilepath === directory ||
|
|
171
|
+
normalizedRealFilepath?.startsWith(directory + '/') === true,
|
|
148
172
|
);
|
|
149
173
|
}
|
|
150
174
|
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import prompts from 'prompts';
|
|
9
|
+
import { UsageError } from 'clipanion';
|
|
10
|
+
|
|
11
|
+
// Configs
|
|
12
|
+
import cli from '..';
|
|
13
|
+
import { renderRows } from '../presentation/layout';
|
|
14
|
+
import { isLikelyProteumAppRoot } from '../presentation/commands';
|
|
15
|
+
import { renderStep, renderSuccess, renderTitle, renderWarning } from '../presentation/ink';
|
|
16
|
+
import { configureProjectAgentSymlinks, type TConfigureProjectAgentSymlinksResult } from '../utils/agents';
|
|
17
|
+
|
|
18
|
+
/*----------------------------------
|
|
19
|
+
- HELPERS
|
|
20
|
+
----------------------------------*/
|
|
21
|
+
|
|
22
|
+
const findLikelyRepoRoot = (startPath: string) => {
|
|
23
|
+
let currentPath = path.resolve(startPath);
|
|
24
|
+
|
|
25
|
+
while (true) {
|
|
26
|
+
if (fs.existsSync(path.join(currentPath, '.git'))) return currentPath;
|
|
27
|
+
|
|
28
|
+
const parentPath = path.dirname(currentPath);
|
|
29
|
+
if (parentPath === currentPath) return undefined;
|
|
30
|
+
currentPath = parentPath;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const resolveCanonicalPath = (inputPath: string) => {
|
|
35
|
+
const resolvedPath = path.resolve(inputPath);
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
return fs.realpathSync(resolvedPath);
|
|
39
|
+
} catch {
|
|
40
|
+
return resolvedPath;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const isInsideDirectory = ({ child, parent }: { child: string; parent: string }) => {
|
|
45
|
+
const relativePath = path.relative(parent, child);
|
|
46
|
+
return relativePath !== '' && !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const assertProteumAppRoot = (appRoot: string) => {
|
|
50
|
+
if (isLikelyProteumAppRoot(appRoot)) return;
|
|
51
|
+
|
|
52
|
+
throw new UsageError(
|
|
53
|
+
`This command expects a Proteum app root. Missing one or more required entries in ${appRoot}.`,
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const promptMonorepoRoot = async ({
|
|
58
|
+
appRoot,
|
|
59
|
+
defaultRoot,
|
|
60
|
+
}: {
|
|
61
|
+
appRoot: string;
|
|
62
|
+
defaultRoot?: string;
|
|
63
|
+
}) => {
|
|
64
|
+
const response = await prompts(
|
|
65
|
+
{
|
|
66
|
+
type: 'text',
|
|
67
|
+
name: 'value',
|
|
68
|
+
message: 'Monorepo root path',
|
|
69
|
+
initial: defaultRoot,
|
|
70
|
+
validate: (input) => {
|
|
71
|
+
const resolvedRoot = resolveCanonicalPath(String(input || defaultRoot || ''));
|
|
72
|
+
|
|
73
|
+
if (!input && !defaultRoot) return 'A monorepo root path is required.';
|
|
74
|
+
if (!fs.existsSync(resolvedRoot) || !fs.statSync(resolvedRoot).isDirectory())
|
|
75
|
+
return `Directory not found: ${resolvedRoot}`;
|
|
76
|
+
if (!isInsideDirectory({ child: appRoot, parent: resolvedRoot }))
|
|
77
|
+
return `The Proteum app root must be inside the monorepo root: ${resolvedRoot}`;
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
onCancel: () => {
|
|
84
|
+
throw new UsageError('Cancelled `proteum configure agents`.');
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return resolveCanonicalPath(String(response.value || defaultRoot || ''));
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const promptBlockedOverwritePaths = async (blockedPaths: string[]) => {
|
|
93
|
+
if (blockedPaths.length === 0) return [];
|
|
94
|
+
|
|
95
|
+
console.info(await renderWarning('Proteum found existing non-managed instruction paths.'));
|
|
96
|
+
console.info(['Choose whether to overwrite each path with a Proteum-managed symlink:', ...blockedPaths.map((entry) => `- ${entry}`)].join('\n'));
|
|
97
|
+
|
|
98
|
+
const overwriteBlockedPaths: string[] = [];
|
|
99
|
+
|
|
100
|
+
for (const blockedPath of blockedPaths) {
|
|
101
|
+
const response = await prompts(
|
|
102
|
+
{
|
|
103
|
+
type: 'confirm',
|
|
104
|
+
name: 'value',
|
|
105
|
+
message: `Overwrite ${blockedPath}?`,
|
|
106
|
+
initial: false,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
onCancel: () => {
|
|
110
|
+
throw new UsageError('Cancelled `proteum configure agents`.');
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (response.value === true) overwriteBlockedPaths.push(blockedPath);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return overwriteBlockedPaths;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const renderConfigureResultSections = (result: TConfigureProjectAgentSymlinksResult) => {
|
|
122
|
+
const sections: string[] = [];
|
|
123
|
+
|
|
124
|
+
sections.push(
|
|
125
|
+
renderRows(
|
|
126
|
+
[
|
|
127
|
+
{ label: 'mode', value: result.mode },
|
|
128
|
+
...(result.monorepoRoot ? [{ label: 'monorepo root', value: result.monorepoRoot }] : []),
|
|
129
|
+
],
|
|
130
|
+
{ minLabelWidth: 16, maxLabelWidth: 16 },
|
|
131
|
+
),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
if (result.created.length > 0) sections.push(['Created:', ...result.created.map((entry) => `- ${entry}`)].join('\n'));
|
|
135
|
+
if (result.updated.length > 0) sections.push(['Updated:', ...result.updated.map((entry) => `- ${entry}`)].join('\n'));
|
|
136
|
+
if (result.overwritten.length > 0)
|
|
137
|
+
sections.push(['Overwritten:', ...result.overwritten.map((entry) => `- ${entry}`)].join('\n'));
|
|
138
|
+
if (result.updatedGitignores.length > 0)
|
|
139
|
+
sections.push(['Updated .gitignore:', ...result.updatedGitignores.map((entry) => `- ${entry}`)].join('\n'));
|
|
140
|
+
if (result.blocked.length > 0)
|
|
141
|
+
sections.push(
|
|
142
|
+
[
|
|
143
|
+
'Skipped existing non-managed paths:',
|
|
144
|
+
...result.blocked.map((entry) => `- ${entry}`),
|
|
145
|
+
].join('\n'),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
return sections;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/*----------------------------------
|
|
152
|
+
- COMMAND
|
|
153
|
+
----------------------------------*/
|
|
154
|
+
|
|
155
|
+
export const run = async (): Promise<void> => {
|
|
156
|
+
if (cli.args.action !== 'agents') throw new UsageError('Usage: `proteum configure agents`');
|
|
157
|
+
|
|
158
|
+
const appRoot = resolveCanonicalPath(cli.paths.appRoot);
|
|
159
|
+
assertProteumAppRoot(appRoot);
|
|
160
|
+
|
|
161
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
162
|
+
throw new UsageError('`proteum configure agents` is interactive and requires a TTY.');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const likelyRepoRoot = findLikelyRepoRoot(appRoot);
|
|
166
|
+
const defaultMonorepoRoot =
|
|
167
|
+
likelyRepoRoot && likelyRepoRoot !== appRoot && isInsideDirectory({ child: appRoot, parent: likelyRepoRoot })
|
|
168
|
+
? likelyRepoRoot
|
|
169
|
+
: undefined;
|
|
170
|
+
console.info(
|
|
171
|
+
[
|
|
172
|
+
await renderTitle('PROTEUM CONFIGURE AGENTS', 'Configure Proteum-managed instruction symlinks.'),
|
|
173
|
+
renderRows([{ label: 'app', value: appRoot === process.cwd() ? '.' : appRoot }]),
|
|
174
|
+
].join('\n\n'),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const monorepoResponse = await prompts(
|
|
178
|
+
{
|
|
179
|
+
type: 'confirm',
|
|
180
|
+
name: 'value',
|
|
181
|
+
message: 'Is this Proteum app part of a monorepo?',
|
|
182
|
+
initial: defaultMonorepoRoot !== undefined,
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
onCancel: () => {
|
|
186
|
+
throw new UsageError('Cancelled `proteum configure agents`.');
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
const isMonorepo = monorepoResponse.value === true;
|
|
191
|
+
const monorepoRoot = isMonorepo
|
|
192
|
+
? await promptMonorepoRoot({
|
|
193
|
+
appRoot,
|
|
194
|
+
defaultRoot: defaultMonorepoRoot,
|
|
195
|
+
})
|
|
196
|
+
: undefined;
|
|
197
|
+
|
|
198
|
+
const preview = configureProjectAgentSymlinks({
|
|
199
|
+
appRoot,
|
|
200
|
+
coreRoot: cli.paths.core.root,
|
|
201
|
+
dryRun: true,
|
|
202
|
+
monorepoRoot,
|
|
203
|
+
});
|
|
204
|
+
const overwriteBlockedPaths = await promptBlockedOverwritePaths(preview.blocked);
|
|
205
|
+
|
|
206
|
+
console.info(
|
|
207
|
+
await renderStep(
|
|
208
|
+
'[1/1]',
|
|
209
|
+
isMonorepo
|
|
210
|
+
? `Writing monorepo-aware instruction symlinks using ${monorepoRoot}.`
|
|
211
|
+
: 'Writing standalone instruction symlinks.',
|
|
212
|
+
),
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const result = configureProjectAgentSymlinks({
|
|
216
|
+
appRoot,
|
|
217
|
+
coreRoot: cli.paths.core.root,
|
|
218
|
+
monorepoRoot,
|
|
219
|
+
overwriteBlockedPaths,
|
|
220
|
+
});
|
|
221
|
+
const sections = renderConfigureResultSections(result);
|
|
222
|
+
|
|
223
|
+
console.info(await renderSuccess('Proteum-managed instruction symlinks are configured.'));
|
|
224
|
+
|
|
225
|
+
if (sections.length > 0) console.info(`\n${sections.join('\n\n')}`);
|
|
226
|
+
};
|