proteum 2.2.6 → 2.2.7
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 +1 -1
- package/README.md +4 -4
- package/agents/project/AGENTS.md +2 -1
- package/agents/project/app-root/AGENTS.md +1 -1
- package/agents/project/diagnostics.md +1 -1
- package/agents/project/root/AGENTS.md +2 -1
- package/cli/commands/configure.ts +14 -35
- package/cli/commands/dev.ts +105 -52
- package/cli/compiler/artifacts/manifest.ts +1 -5
- package/cli/presentation/commands.ts +9 -9
- package/cli/presentation/help.ts +1 -1
- package/cli/scaffold/index.ts +2 -5
- package/cli/scaffold/templates.ts +1 -7
- package/cli/utils/agents.ts +281 -199
- package/package.json +1 -1
- package/tests/agents-utils.test.cjs +207 -0
- package/tests/dev-transpile-watch.test.cjs +513 -0
package/AGENTS.md
CHANGED
|
@@ -58,7 +58,7 @@ npx prisma migrate dev --config ./prisma.config.ts --name <migration name>
|
|
|
58
58
|
- Inspect how both apps currently use the touched feature, runtime, API, compiler behavior, or generated output before proposing or implementing changes.
|
|
59
59
|
- Keep the developer-facing contract synchronized when framework work changes CLI commands, profiler capabilities, or the `proteum dev` banner. Update the live surfaces together in the same pass: CLI command/help definitions, profiler panels and dev-only endpoints, banner text/examples, and the most relevant agent docs that describe them, especially `AGENTS.md`, `agents/project/AGENTS.md`, `agents/project/root/AGENTS.md`, `agents/project/app-root/AGENTS.md`, `agents/project/diagnostics.md`, and any narrower `agents/project/**/AGENTS.md` file that mentions the changed workflow.
|
|
60
60
|
- Keep the same-system trace contract explicit when request instrumentation changes: `TRACE_*` controls the retained dev trace store plus the trace/perf CLI, dev-only HTTP endpoints, and bottom profiler, while `ENABLE_PROFILER` enables the reduced request-local `request.profiling` snapshot and `request.finished` hook payload without retaining finished requests globally unless dev trace is also enabled.
|
|
61
|
-
- 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.
|
|
61
|
+
- 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.
|
|
62
62
|
- Keep core changes aligned with the explicit controller/page architecture in `agents/project/root/AGENTS.md` and its standalone composition in `agents/project/AGENTS.md`.
|
|
63
63
|
- Prefer removing framework magic when the same result can be expressed with explicit contracts, generated code, or typed context.
|
|
64
64
|
- Apply the pruning rules from `agents/project/optimizations.md`, especially for webpack plugins, Babel plugins, aliases, helpers, runtime services, and npm packages that are not meaningfully used by both apps.
|
package/README.md
CHANGED
|
@@ -347,7 +347,7 @@ Proteum ships with a compact CLI focused on the real app lifecycle:
|
|
|
347
347
|
| `proteum e2e` | Run Playwright with Proteum-managed `E2E_*` values instead of shell-leading env assignments |
|
|
348
348
|
| `proteum verify` | Validate framework-facing workflows across one or more running dev apps; `framework-change` is the built-in cross-reference-app check |
|
|
349
349
|
| `proteum init` | Scaffold a new Proteum app with built-in deterministic templates |
|
|
350
|
-
| `proteum configure agents` | Interactively configure Proteum
|
|
350
|
+
| `proteum configure agents` | Interactively configure tracked Proteum instruction files for standalone or monorepo apps |
|
|
351
351
|
| `proteum create` | Scaffold a page, controller, command, route, or root service inside an app |
|
|
352
352
|
|
|
353
353
|
Recommended daily workflow:
|
|
@@ -361,7 +361,7 @@ proteum build --prod --analyze
|
|
|
361
361
|
proteum build --prod --analyze --analyze-serve --analyze-port auto
|
|
362
362
|
```
|
|
363
363
|
|
|
364
|
-
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. `proteum dev` is the only command that clears the interactive terminal before rendering its live session UI, exposes `CTRL+R` reload plus `CTRL+C` shutdown hotkeys, and prints connected app names plus successful connected `/ping` checks in the server-ready banner.
|
|
364
|
+
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. `proteum dev` is the only command that clears the interactive terminal before rendering its live session UI, exposes `CTRL+R` reload plus `CTRL+C` shutdown hotkeys, and prints connected app names plus successful connected `/ping` checks in the server-ready banner. Every `proteum dev` start ensures tracked Proteum instruction files contain the current managed `# Proteum Instructions` section before the dev loop begins.
|
|
365
365
|
|
|
366
366
|
Useful inspection commands:
|
|
367
367
|
|
|
@@ -404,9 +404,9 @@ proteum create controller Founder/projects --method list
|
|
|
404
404
|
proteum create service Conversion/Plans
|
|
405
405
|
```
|
|
406
406
|
|
|
407
|
-
`proteum configure agents`
|
|
407
|
+
`proteum configure agents` embeds the full Proteum project instruction corpus into the managed `# Proteum Instructions` section of each tracked instruction file. It preserves content outside that section and asks before replacing directories or foreign symlinks. If you decline, that path is left untouched.
|
|
408
408
|
|
|
409
|
-
|
|
409
|
+
Every `proteum dev` start runs the same idempotent instruction check. It updates missing or stale managed sections automatically and prompts only when a blocked path would need to be replaced.
|
|
410
410
|
|
|
411
411
|
`proteum connect`, `proteum explain`, `proteum doctor`, and `proteum diagnose` share the same generated manifest and contract state. `proteum perf` uses the same dev request-trace store as the profiler `Perf` tab. For the full diagnostics and tracing model, see [docs/diagnostics.md](docs/diagnostics.md) and [docs/request-tracing.md](docs/request-tracing.md).
|
|
412
412
|
|
package/agents/project/AGENTS.md
CHANGED
|
@@ -21,6 +21,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
21
21
|
- 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. After this, every time you implement a fix:
|
|
22
22
|
- test, re-run analysis and give a comparison table of before and after
|
|
23
23
|
- re-print the complete list of suggested fixes, but strike the ones we already implemented or not necessary anymore
|
|
24
|
+
- 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.
|
|
24
25
|
- If the task is ambiguous, generated, connected, or multi-repo, start with `npx proteum orient <query>` before reading large parts of the codebase.
|
|
25
26
|
- 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`.
|
|
26
27
|
- 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.
|
|
@@ -57,7 +58,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
57
58
|
- 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.
|
|
58
59
|
- 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.
|
|
59
60
|
- 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>`.
|
|
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.
|
|
61
|
+
- 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.
|
|
61
62
|
|
|
62
63
|
### Before Finishing
|
|
63
64
|
|
|
@@ -12,5 +12,5 @@ Do not put here: reusable Proteum architecture contracts, shared verification ru
|
|
|
12
12
|
- Run `npx proteum refresh`.
|
|
13
13
|
- Read and acknowledge the applicable `AGENTS.md` files.
|
|
14
14
|
- Run `npm i`.
|
|
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
|
|
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
16
|
- If the task changes UX, copy, onboarding, pricing, product semantics, or commercial positioning, read the relevant files under `./docs/` first, especially `docs/PERSONAS.md`, `docs/PRODUCT.md`, and `docs/MARKETING.md` when they exist. If a dev server is already running, print the live dev server URL as a clickable Markdown link.
|
|
@@ -15,7 +15,7 @@ This file is the canonical source of truth for diagnostics, temporary instrument
|
|
|
15
15
|
|
|
16
16
|
- 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 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.
|
|
17
17
|
- 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.
|
|
18
|
-
- 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.
|
|
18
|
+
- 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.
|
|
19
19
|
- For ownership or repo discovery questions, start with `npx proteum orient <query>` instead of jumping straight into source searches.
|
|
20
20
|
- For request-time issues in dev, start with `npx proteum diagnose <path> --port <port>` when you have a concrete failing route, page, controller path, or request target. It combines owner lookup, manifest diagnostics, contract diagnostics, matching trace data, and buffered server logs in one pass.
|
|
21
21
|
- 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.
|
|
@@ -12,6 +12,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
12
12
|
## Fast Triggers
|
|
13
13
|
|
|
14
14
|
- 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
|
+
- 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.
|
|
15
16
|
- If the task is ambiguous, generated, connected, or multi-repo, start with `npx proteum orient <query>` before reading large parts of the codebase.
|
|
16
17
|
- 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
18
|
- 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.
|
|
@@ -47,7 +48,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
47
48
|
- 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
49
|
- 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
50
|
- 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>`.
|
|
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
|
+
- 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.
|
|
51
52
|
|
|
52
53
|
### Before Finishing
|
|
53
54
|
|
|
@@ -13,39 +13,18 @@ import cli from '..';
|
|
|
13
13
|
import { renderRows } from '../presentation/layout';
|
|
14
14
|
import { isLikelyProteumAppRoot } from '../presentation/commands';
|
|
15
15
|
import { renderStep, renderSuccess, renderTitle, renderWarning } from '../presentation/ink';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
configureProjectAgentInstructions,
|
|
18
|
+
findLikelyRepoRoot,
|
|
19
|
+
isInsideDirectory,
|
|
20
|
+
resolveCanonicalPath,
|
|
21
|
+
type TConfigureProjectAgentInstructionsResult,
|
|
22
|
+
} from '../utils/agents';
|
|
17
23
|
|
|
18
24
|
/*----------------------------------
|
|
19
25
|
- HELPERS
|
|
20
26
|
----------------------------------*/
|
|
21
27
|
|
|
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
28
|
const assertProteumAppRoot = (appRoot: string) => {
|
|
50
29
|
if (isLikelyProteumAppRoot(appRoot)) return;
|
|
51
30
|
|
|
@@ -92,10 +71,10 @@ const promptMonorepoRoot = async ({
|
|
|
92
71
|
const promptBlockedOverwritePaths = async (blockedPaths: string[]) => {
|
|
93
72
|
if (blockedPaths.length === 0) return [];
|
|
94
73
|
|
|
95
|
-
console.info(await renderWarning('Proteum found existing
|
|
74
|
+
console.info(await renderWarning('Proteum found existing paths that block managed instruction updates.'));
|
|
96
75
|
console.info(
|
|
97
76
|
[
|
|
98
|
-
'Choose whether to overwrite each path with a Proteum
|
|
77
|
+
'Choose whether to overwrite each path with a tracked Proteum instruction file:',
|
|
99
78
|
...blockedPaths.map((entry) => `- ${entry}`),
|
|
100
79
|
].join('\n'),
|
|
101
80
|
);
|
|
@@ -145,7 +124,7 @@ const renderConfigureResultSections = (result: TConfigureProjectAgentInstruction
|
|
|
145
124
|
if (result.blocked.length > 0)
|
|
146
125
|
sections.push(
|
|
147
126
|
[
|
|
148
|
-
'Skipped
|
|
127
|
+
'Skipped blocked paths:',
|
|
149
128
|
...result.blocked.map((entry) => `- ${entry}`),
|
|
150
129
|
].join('\n'),
|
|
151
130
|
);
|
|
@@ -183,7 +162,7 @@ export const runConfigureAgentsWizard = async ({
|
|
|
183
162
|
: undefined;
|
|
184
163
|
console.info(
|
|
185
164
|
[
|
|
186
|
-
await renderTitle('PROTEUM CONFIGURE AGENTS', 'Configure Proteum
|
|
165
|
+
await renderTitle('PROTEUM CONFIGURE AGENTS', 'Configure tracked Proteum instruction files.'),
|
|
187
166
|
renderRows([{ label: 'app', value: appRoot === process.cwd() ? '.' : appRoot }]),
|
|
188
167
|
].join('\n\n'),
|
|
189
168
|
);
|
|
@@ -221,8 +200,8 @@ export const runConfigureAgentsWizard = async ({
|
|
|
221
200
|
await renderStep(
|
|
222
201
|
'[1/1]',
|
|
223
202
|
isMonorepo
|
|
224
|
-
? `Writing monorepo-aware instruction
|
|
225
|
-
: 'Writing standalone instruction
|
|
203
|
+
? `Writing monorepo-aware instruction files using ${monorepoRoot}.`
|
|
204
|
+
: 'Writing standalone instruction files.',
|
|
226
205
|
),
|
|
227
206
|
);
|
|
228
207
|
|
|
@@ -234,7 +213,7 @@ export const runConfigureAgentsWizard = async ({
|
|
|
234
213
|
});
|
|
235
214
|
const sections = renderConfigureResultSections(result);
|
|
236
215
|
|
|
237
|
-
console.info(await renderSuccess('Proteum-managed instruction
|
|
216
|
+
console.info(await renderSuccess('Proteum-managed instruction files are configured.'));
|
|
238
217
|
|
|
239
218
|
if (sections.length > 0) console.info(`\n${sections.join('\n\n')}`);
|
|
240
219
|
};
|
package/cli/commands/dev.ts
CHANGED
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
|
|
23
23
|
// Configs
|
|
24
24
|
import Compiler from '../compiler';
|
|
25
|
-
import { regex } from '../compiler/common';
|
|
26
25
|
import { createDevEventServer } from './devEvents';
|
|
27
26
|
import { renderDevSession, renderServerReadyBanner, renderDevShutdownBanner } from '../presentation/devSession';
|
|
28
27
|
import { clearInteractiveConsole } from '../presentation/welcome';
|
|
@@ -41,8 +40,7 @@ import {
|
|
|
41
40
|
} from '../runtime/devSessions';
|
|
42
41
|
import { resolveFrameworkInstallInfo } from '../paths';
|
|
43
42
|
import { logVerbose } from '../runtime/verbose';
|
|
44
|
-
import {
|
|
45
|
-
import { runConfigureAgentsWizard } from './configure';
|
|
43
|
+
import { configureProjectAgentInstructions, resolveProjectAgentMonorepoRoot } from '../utils/agents';
|
|
46
44
|
|
|
47
45
|
// Core
|
|
48
46
|
import { app, App } from '../app';
|
|
@@ -61,6 +59,7 @@ const hotReloadableServerPathPatterns = [
|
|
|
61
59
|
/^server\/services\/.+\.controller\.[jt]sx?$/,
|
|
62
60
|
];
|
|
63
61
|
const hotReloadableRoots = [() => app.paths.root, () => cli.paths.core.root];
|
|
62
|
+
const transpileSourceWatchPattern = /\.(ts|tsx|js|jsx|css|less|scss)$/;
|
|
64
63
|
|
|
65
64
|
/*----------------------------------
|
|
66
65
|
- STATE
|
|
@@ -144,43 +143,74 @@ const createIgnoredWatchMatcher = (outputPaths: string[]) => (watchPath: string)
|
|
|
144
143
|
return ignoredWatchPathPatterns.test(normalizedWatchPath);
|
|
145
144
|
};
|
|
146
145
|
|
|
147
|
-
const
|
|
148
|
-
if (
|
|
149
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
const promptBlockedAgentInstructionOverwrites = async (blockedPaths: string[]) => {
|
|
147
|
+
if (blockedPaths.length === 0) return [];
|
|
148
|
+
if (cli.args.json === true || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
149
|
+
throw new UsageError(
|
|
150
|
+
[
|
|
151
|
+
'Proteum could not update managed instruction files because existing paths are blocked:',
|
|
152
|
+
...blockedPaths.map((entry) => `- ${entry}`),
|
|
153
|
+
'Run `proteum configure agents` in an interactive terminal to choose which paths can be replaced.',
|
|
154
|
+
].join('\n'),
|
|
155
|
+
);
|
|
156
|
+
}
|
|
153
157
|
|
|
154
|
-
console.info(await renderWarning('Proteum
|
|
158
|
+
console.info(await renderWarning('Proteum found existing paths that block managed instruction updates.'));
|
|
155
159
|
console.info(
|
|
156
160
|
[
|
|
157
|
-
'
|
|
158
|
-
...
|
|
159
|
-
'',
|
|
160
|
-
'Run `proteum configure agents` now before starting the dev server?',
|
|
161
|
+
'Choose whether to overwrite each blocked path with a tracked Proteum instruction file:',
|
|
162
|
+
...blockedPaths.map((entry) => `- ${entry}`),
|
|
161
163
|
].join('\n'),
|
|
162
164
|
);
|
|
163
165
|
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
throw new UsageError('Cancelled `proteum dev`.');
|
|
166
|
+
const overwriteBlockedPaths: string[] = [];
|
|
167
|
+
|
|
168
|
+
for (const blockedPath of blockedPaths) {
|
|
169
|
+
const response = await prompts(
|
|
170
|
+
{
|
|
171
|
+
type: 'confirm',
|
|
172
|
+
name: 'value',
|
|
173
|
+
message: `Overwrite ${blockedPath}?`,
|
|
174
|
+
initial: false,
|
|
174
175
|
},
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
{
|
|
177
|
+
onCancel: () => {
|
|
178
|
+
throw new UsageError('Cancelled `proteum dev`.');
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
if (response.value === true) overwriteBlockedPaths.push(blockedPath);
|
|
184
|
+
}
|
|
177
185
|
|
|
178
|
-
|
|
186
|
+
return overwriteBlockedPaths;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const ensureProjectAgentInstructions = async () => {
|
|
190
|
+
const monorepoRoot = resolveProjectAgentMonorepoRoot(app.paths.root);
|
|
191
|
+
const preview = configureProjectAgentInstructions({
|
|
192
|
+
appRoot: app.paths.root,
|
|
193
|
+
coreRoot: cli.paths.core.root,
|
|
194
|
+
dryRun: true,
|
|
195
|
+
monorepoRoot,
|
|
196
|
+
});
|
|
197
|
+
const overwriteBlockedPaths = await promptBlockedAgentInstructionOverwrites(preview.blocked);
|
|
179
198
|
|
|
180
|
-
|
|
199
|
+
const result = configureProjectAgentInstructions({
|
|
181
200
|
appRoot: app.paths.root,
|
|
182
201
|
coreRoot: cli.paths.core.root,
|
|
202
|
+
monorepoRoot,
|
|
203
|
+
overwriteBlockedPaths,
|
|
183
204
|
});
|
|
205
|
+
|
|
206
|
+
if (result.blocked.length === 0) return;
|
|
207
|
+
|
|
208
|
+
throw new UsageError(
|
|
209
|
+
[
|
|
210
|
+
'Proteum could not update all managed instruction files because these paths were left blocked:',
|
|
211
|
+
...result.blocked.map((entry) => `- ${entry}`),
|
|
212
|
+
].join('\n'),
|
|
213
|
+
);
|
|
184
214
|
};
|
|
185
215
|
|
|
186
216
|
const getDevAppName = (app: App) =>
|
|
@@ -530,11 +560,11 @@ type TIndexedSourceWatchEvent = 'change' | 'rename';
|
|
|
530
560
|
type TIndexedSourceWatchCompilerName = 'server' | 'client';
|
|
531
561
|
type TIndexedSourceWatchInvalidateTarget = 'all' | TIndexedSourceWatchCompilerName;
|
|
532
562
|
type TIndexedSourceWatchRule = {
|
|
533
|
-
|
|
563
|
+
compilerNames: TIndexedSourceWatchCompilerName[];
|
|
534
564
|
rootPath: string;
|
|
535
565
|
relativePathPattern: RegExp;
|
|
536
566
|
eventTypes: TIndexedSourceWatchEvent[];
|
|
537
|
-
|
|
567
|
+
invalidateTargets: TIndexedSourceWatchInvalidateTarget[];
|
|
538
568
|
};
|
|
539
569
|
type TNamedWatching = { compiler: { name?: string }; invalidate: () => void };
|
|
540
570
|
type TMultiWatchingLike = TDevWatching & { watchings?: TNamedWatching[] };
|
|
@@ -553,26 +583,26 @@ const resolveIndexedSourceWatchRules = (): TIndexedSourceWatchRule[] => {
|
|
|
553
583
|
|
|
554
584
|
return [
|
|
555
585
|
{
|
|
556
|
-
|
|
586
|
+
compilerNames: ['server'],
|
|
557
587
|
rootPath: app.paths.root,
|
|
558
588
|
relativePathPattern: /^commands(?:\/|$)/,
|
|
559
589
|
eventTypes: ['rename'],
|
|
560
|
-
|
|
590
|
+
invalidateTargets: ['all'],
|
|
561
591
|
},
|
|
562
592
|
{
|
|
563
|
-
|
|
593
|
+
compilerNames: ['server'],
|
|
564
594
|
rootPath: cli.paths.core.root,
|
|
565
595
|
relativePathPattern: /^commands(?:\/|$)/,
|
|
566
596
|
eventTypes: ['rename'],
|
|
567
|
-
|
|
597
|
+
invalidateTargets: ['all'],
|
|
568
598
|
},
|
|
569
599
|
...transpileWatchRoots.map(
|
|
570
600
|
(rootPath): TIndexedSourceWatchRule => ({
|
|
571
|
-
|
|
601
|
+
compilerNames: ['client', 'server'],
|
|
572
602
|
rootPath,
|
|
573
|
-
relativePathPattern:
|
|
603
|
+
relativePathPattern: transpileSourceWatchPattern,
|
|
574
604
|
eventTypes: ['change', 'rename'],
|
|
575
|
-
|
|
605
|
+
invalidateTargets: ['client', 'server'],
|
|
576
606
|
}),
|
|
577
607
|
),
|
|
578
608
|
];
|
|
@@ -587,6 +617,12 @@ const findCompilerWatching = (
|
|
|
587
617
|
return childWatchings?.find((childWatching) => childWatching.compiler.name === compilerName);
|
|
588
618
|
};
|
|
589
619
|
|
|
620
|
+
const formatInvalidateTargets = (invalidateTargets: TIndexedSourceWatchCompilerName[]) => {
|
|
621
|
+
if (invalidateTargets.length === 1) return invalidateTargets[0];
|
|
622
|
+
if (invalidateTargets.length === 2) return `${invalidateTargets[0]} and ${invalidateTargets[1]}`;
|
|
623
|
+
return `${invalidateTargets.slice(0, -1).join(', ')}, and ${invalidateTargets[invalidateTargets.length - 1]}`;
|
|
624
|
+
};
|
|
625
|
+
|
|
590
626
|
const closeFsWatcher = async (watcher: FSWatcher) => {
|
|
591
627
|
await new Promise<void>((resolve) => {
|
|
592
628
|
watcher.once('close', () => resolve());
|
|
@@ -618,7 +654,7 @@ const createIndexedSourceWatching = ({
|
|
|
618
654
|
|
|
619
655
|
if (pendingInvalidateTargets.has('all')) {
|
|
620
656
|
pendingInvalidateTargets.clear();
|
|
621
|
-
logVerbose('Indexed source files changed. Invalidating
|
|
657
|
+
logVerbose('Indexed source files changed. Invalidating all dev compilers to refresh generated artifacts.');
|
|
622
658
|
watching.invalidate();
|
|
623
659
|
return;
|
|
624
660
|
}
|
|
@@ -630,40 +666,57 @@ const createIndexedSourceWatching = ({
|
|
|
630
666
|
|
|
631
667
|
if (invalidateTargets.length === 0) return;
|
|
632
668
|
|
|
633
|
-
|
|
669
|
+
const compilerWatchings: TNamedWatching[] = [];
|
|
670
|
+
|
|
634
671
|
for (const invalidateTarget of invalidateTargets) {
|
|
635
672
|
const compilerWatching = findCompilerWatching(watching, invalidateTarget);
|
|
636
673
|
|
|
637
674
|
if (!compilerWatching) {
|
|
675
|
+
logVerbose('Transpiled source files changed. Invalidating all dev compilers to refresh mutable package code.');
|
|
638
676
|
watching.invalidate();
|
|
639
677
|
return;
|
|
640
678
|
}
|
|
641
679
|
|
|
680
|
+
compilerWatchings.push(compilerWatching);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
logVerbose(
|
|
684
|
+
`Transpiled source files changed. Invalidating ${formatInvalidateTargets(
|
|
685
|
+
invalidateTargets,
|
|
686
|
+
)} compilers to refresh mutable package code.`,
|
|
687
|
+
);
|
|
688
|
+
for (const compilerWatching of compilerWatchings) {
|
|
642
689
|
compilerWatching.invalidate();
|
|
643
690
|
}
|
|
644
691
|
};
|
|
645
692
|
|
|
646
693
|
const queueInvalidate = ({
|
|
647
|
-
|
|
694
|
+
compilerNames,
|
|
648
695
|
filepath,
|
|
649
|
-
|
|
696
|
+
invalidateTargets,
|
|
650
697
|
}: {
|
|
651
|
-
|
|
698
|
+
compilerNames: TIndexedSourceWatchCompilerName[];
|
|
652
699
|
filepath: string;
|
|
653
|
-
|
|
700
|
+
invalidateTargets: TIndexedSourceWatchInvalidateTarget[];
|
|
654
701
|
}) => {
|
|
655
702
|
const normalizedFilepath = normalizeWatchPath(filepath);
|
|
656
|
-
const queueKey = `${
|
|
703
|
+
const queueKey = `${invalidateTargets.join(',')}:${compilerNames.join(',')}:${normalizedFilepath}`;
|
|
657
704
|
const queuedAt = recentQueuedChanges.get(queueKey);
|
|
658
705
|
|
|
659
706
|
if (queuedAt !== undefined && Date.now() - queuedAt < 250) return;
|
|
660
707
|
|
|
661
708
|
recentQueuedChanges.set(queueKey, Date.now());
|
|
662
|
-
const changedFiles = pendingChanges.get(compilerName) || new Set<string>();
|
|
663
709
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
710
|
+
for (const compilerName of compilerNames) {
|
|
711
|
+
const changedFiles = pendingChanges.get(compilerName) || new Set<string>();
|
|
712
|
+
|
|
713
|
+
changedFiles.add(normalizedFilepath);
|
|
714
|
+
pendingChanges.set(compilerName, changedFiles);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
for (const invalidateTarget of invalidateTargets) {
|
|
718
|
+
pendingInvalidateTargets.add(invalidateTarget);
|
|
719
|
+
}
|
|
667
720
|
|
|
668
721
|
if (invalidateTimer) return;
|
|
669
722
|
invalidateTimer = setTimeout(flushInvalidate, 40);
|
|
@@ -682,9 +735,9 @@ const createIndexedSourceWatching = ({
|
|
|
682
735
|
if (!watchRule.eventTypes.includes(normalizedEventType) && relativePath) return;
|
|
683
736
|
|
|
684
737
|
queueInvalidate({
|
|
685
|
-
|
|
738
|
+
compilerNames: watchRule.compilerNames,
|
|
686
739
|
filepath: relativePath ? path.join(rootPath, relativePath) : rootPath,
|
|
687
|
-
|
|
740
|
+
invalidateTargets: watchRule.invalidateTargets,
|
|
688
741
|
});
|
|
689
742
|
}),
|
|
690
743
|
);
|
|
@@ -755,7 +808,7 @@ const runDevLoop = async () => {
|
|
|
755
808
|
// - Node modules except 5HTP core (framework dev mode)
|
|
756
809
|
// - Generated files during runtime (cause infinite loop. Ex: models.d.ts)
|
|
757
810
|
// - Webpack output folders (`./dev`, legacy `./bin`)
|
|
758
|
-
ignored: ignoredWatchMatcher,
|
|
811
|
+
ignored: ignoredWatchMatcher as never,
|
|
759
812
|
|
|
760
813
|
//aggregateTimeout: 1000,
|
|
761
814
|
},
|
|
@@ -880,6 +933,6 @@ export const run = async () => {
|
|
|
880
933
|
return;
|
|
881
934
|
}
|
|
882
935
|
|
|
883
|
-
await
|
|
936
|
+
await ensureProjectAgentInstructions();
|
|
884
937
|
await runDevLoop();
|
|
885
938
|
};
|
|
@@ -5,7 +5,6 @@ import app from '../../app';
|
|
|
5
5
|
import cli from '../..';
|
|
6
6
|
import { inspectProteumEnv } from '../../../common/env/proteumEnv';
|
|
7
7
|
import { reservedRouteOptionKeys, routeOptionKeys } from '../../../common/router/pageData';
|
|
8
|
-
import { getProjectInstructionGitignoreEntries } from '../../utils/agents';
|
|
9
8
|
import {
|
|
10
9
|
TProteumManifest,
|
|
11
10
|
TProteumManifestCommand,
|
|
@@ -40,10 +39,7 @@ const collectManifestDiagnostics = ({
|
|
|
40
39
|
routes: TProteumManifest['routes'];
|
|
41
40
|
}) => {
|
|
42
41
|
const diagnostics: TProteumManifestDiagnostic[] = [];
|
|
43
|
-
const expectedGitignoreEntries = [
|
|
44
|
-
...requiredGitignoreEntries,
|
|
45
|
-
...getProjectInstructionGitignoreEntries({ coreRoot: cli.paths.core.root }),
|
|
46
|
-
];
|
|
42
|
+
const expectedGitignoreEntries = [...requiredGitignoreEntries];
|
|
47
43
|
|
|
48
44
|
const pushDiagnostic = (diagnostic: TProteumManifestDiagnostic) => {
|
|
49
45
|
diagnostics.push(diagnostic);
|
|
@@ -113,22 +113,22 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
113
113
|
configure: {
|
|
114
114
|
name: 'configure',
|
|
115
115
|
category: 'Project scaffolding',
|
|
116
|
-
summary: 'Interactively configure Proteum
|
|
116
|
+
summary: 'Interactively configure tracked Proteum instruction files for a standalone app or monorepo app root.',
|
|
117
117
|
usage: 'proteum configure agents',
|
|
118
118
|
bestFor:
|
|
119
|
-
'Creating or switching the
|
|
119
|
+
'Creating or switching the tracked instruction layout intentionally while keeping Proteum-owned instructions embedded in managed sections.',
|
|
120
120
|
examples: [
|
|
121
121
|
{
|
|
122
|
-
description: 'Configure instruction
|
|
122
|
+
description: 'Configure instruction files for the current standalone app',
|
|
123
123
|
command: 'proteum configure agents',
|
|
124
124
|
},
|
|
125
125
|
],
|
|
126
126
|
notes: [
|
|
127
|
-
'This command is interactive. It asks whether the current Proteum app belongs to a monorepo and, if so, which ancestor path should receive the reusable root `AGENTS.md`
|
|
128
|
-
'Standalone mode writes
|
|
129
|
-
'Monorepo mode writes the reusable root `AGENTS.md` into the chosen monorepo root and
|
|
130
|
-
'
|
|
131
|
-
'
|
|
127
|
+
'This command is interactive. It asks whether the current Proteum app belongs to a monorepo and, if so, which ancestor path should receive the reusable root `AGENTS.md` file.',
|
|
128
|
+
'Standalone mode writes tracked instruction files into the current Proteum app root.',
|
|
129
|
+
'Monorepo mode writes the reusable root `AGENTS.md` into the chosen monorepo root and the app-root instruction files into the current Proteum app root.',
|
|
130
|
+
'Every managed instruction file contains a `# Proteum Instructions` section with the full embedded Proteum project instruction corpus.',
|
|
131
|
+
'Existing content outside `# Proteum Instructions` is preserved. Directories and foreign symlinks are replaced only after confirmation.',
|
|
132
132
|
],
|
|
133
133
|
status: 'experimental',
|
|
134
134
|
},
|
|
@@ -191,7 +191,7 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
191
191
|
notes: [
|
|
192
192
|
'Use `--cwd` when the target Proteum app lives in another worktree or checkout and you do not want to `cd` first.',
|
|
193
193
|
'Proteum writes a machine-readable dev session file under `var/run/proteum/dev/<port>.json` by default; override it with `--session-file` when an agent needs a stable path.',
|
|
194
|
-
'Before the
|
|
194
|
+
'Before the dev loop starts, Proteum ensures tracked instruction files contain the current managed `# Proteum Instructions` section.',
|
|
195
195
|
'Use `--replace-existing` when retries should stop the previously tracked matching session before starting a new one.',
|
|
196
196
|
'`proteum dev list` inspects tracked sessions for the current app root. Add `--stale` to show only orphaned or dead sessions.',
|
|
197
197
|
'`proteum dev stop` targets the current session file by default. Add `--all` to stop every tracked session for the current app root.',
|
package/cli/presentation/help.ts
CHANGED
|
@@ -139,7 +139,7 @@ export const renderCliOverview = async ({
|
|
|
139
139
|
indent: ' ',
|
|
140
140
|
nextIndent: ' ',
|
|
141
141
|
}),
|
|
142
|
-
wrapText('
|
|
142
|
+
wrapText('Before the dev loop starts, `proteum dev` ensures tracked instruction files contain the current managed `# Proteum Instructions` section.', {
|
|
143
143
|
indent: ' ',
|
|
144
144
|
nextIndent: ' ',
|
|
145
145
|
}),
|
package/cli/scaffold/index.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { UsageError } from 'clipanion';
|
|
|
5
5
|
|
|
6
6
|
import cli from '..';
|
|
7
7
|
import { loadApplicationIdentityConfig } from '../../common/applicationConfigLoader';
|
|
8
|
-
import { renderProjectInstructionGitignoreBlock } from '../utils/agents';
|
|
9
8
|
import { runProcess } from '../utils/runProcess';
|
|
10
9
|
import {
|
|
11
10
|
createClientTsconfigTemplate,
|
|
@@ -656,9 +655,7 @@ const createInitFilePlans = ({ appRoot, config }: { appRoot: string; config: TSc
|
|
|
656
655
|
},
|
|
657
656
|
{
|
|
658
657
|
relativePath: '.gitignore',
|
|
659
|
-
content: createGitignoreTemplate(
|
|
660
|
-
projectInstructionGitignoreBlock: renderProjectInstructionGitignoreBlock({ coreRoot: cli.paths.core.root }),
|
|
661
|
-
}),
|
|
658
|
+
content: createGitignoreTemplate(),
|
|
662
659
|
},
|
|
663
660
|
{
|
|
664
661
|
relativePath: 'eslint.config.mjs',
|
|
@@ -727,7 +724,7 @@ export const runInitScaffold = async () => {
|
|
|
727
724
|
? 'Run `npm run dev` in the new app directory.'
|
|
728
725
|
: 'Run `npm install`, then `npm run dev` in the new app directory.',
|
|
729
726
|
);
|
|
730
|
-
result.nextSteps.push('Run `proteum configure agents` when you want Proteum
|
|
727
|
+
result.nextSteps.push('Run `proteum configure agents` when you want tracked Proteum instruction files.');
|
|
731
728
|
result.nextSteps.push('Use `proteum create page|controller|command|route|service ...` to add app artifacts.');
|
|
732
729
|
|
|
733
730
|
printResult(result, createInitSummary(result, config));
|
|
@@ -253,11 +253,7 @@ export const createServerTsconfigTemplate = (paths: TTsconfigTemplatePaths) => `
|
|
|
253
253
|
}
|
|
254
254
|
`;
|
|
255
255
|
|
|
256
|
-
export const createGitignoreTemplate = (
|
|
257
|
-
projectInstructionGitignoreBlock,
|
|
258
|
-
}: {
|
|
259
|
-
projectInstructionGitignoreBlock: string;
|
|
260
|
-
}) => `node_modules
|
|
256
|
+
export const createGitignoreTemplate = () => `node_modules
|
|
261
257
|
/.proteum
|
|
262
258
|
/.cache
|
|
263
259
|
/bin
|
|
@@ -265,8 +261,6 @@ export const createGitignoreTemplate = ({
|
|
|
265
261
|
/var
|
|
266
262
|
/proteum.connected.json
|
|
267
263
|
.env
|
|
268
|
-
|
|
269
|
-
${projectInstructionGitignoreBlock}
|
|
270
264
|
`;
|
|
271
265
|
|
|
272
266
|
export const createEnvTemplate = ({ port, url }: { port: number; url: string }) => `ENV_NAME=local
|