proteum 2.2.1 → 2.2.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 +2 -2
- package/README.md +3 -1
- package/agents/project/AGENTS.md +3 -3
- package/agents/project/app-root/AGENTS.md +1 -1
- package/agents/project/diagnostics.md +1 -1
- package/agents/project/root/AGENTS.md +3 -3
- package/cli/commands/configure.ts +12 -3
- package/cli/commands/dev.ts +162 -12
- package/cli/compiler/common/index.ts +16 -0
- package/cli/presentation/commands.ts +1 -0
- package/cli/presentation/help.ts +4 -0
- package/cli/utils/agents.ts +36 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -43,7 +43,7 @@ npx prisma migrate dev --config ./prisma.config.ts --name <migration name>
|
|
|
43
43
|
|
|
44
44
|
[optional body]
|
|
45
45
|
```
|
|
46
|
-
If the user replies exactly `commit`,
|
|
46
|
+
If the user replies exactly `commit`, treat it as conversation-wide and cross-project, not task-scoped. Identify every affected git repository or worktree touched since the last `commit` and, if there has been no prior `commit`, since the beginning of the whole conversation. In each affected repository or worktree, stage all conversation-related changed files with `git add` while still excluding unrelated pre-existing user changes or incidental untracked files, then create one `git commit`. Do not omit linked local dependencies, framework repos, connected projects, or producer apps when they were changed to make the delivered behavior actually work.
|
|
47
47
|
After providing a commit message or after creating a commit, immediately follow it with this exact prompt and obey it:
|
|
48
48
|
`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.`
|
|
49
49
|
|
|
@@ -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. When the app root is missing `AGENTS.md`, the bare interactive `proteum dev` start offers to launch `proteum configure agents` 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
|
@@ -360,7 +360,7 @@ proteum build --prod --analyze
|
|
|
360
360
|
proteum build --prod --analyze --analyze-serve --analyze-port auto
|
|
361
361
|
```
|
|
362
362
|
|
|
363
|
-
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.
|
|
363
|
+
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. When the app root is missing `AGENTS.md`, the interactive `proteum dev` start offers to launch `proteum configure agents` before the dev loop begins.
|
|
364
364
|
|
|
365
365
|
Useful inspection commands:
|
|
366
366
|
|
|
@@ -404,6 +404,8 @@ proteum create service Conversion/Plans
|
|
|
404
404
|
|
|
405
405
|
`proteum configure agents` asks before replacing any existing non-managed instruction file or foreign symlink. If you decline, that path is left untouched.
|
|
406
406
|
|
|
407
|
+
Bare interactive `proteum dev` reuses that same wizard when the app root is missing `AGENTS.md`; declining the prompt continues the dev start without writing files.
|
|
408
|
+
|
|
407
409
|
`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).
|
|
408
410
|
|
|
409
411
|
## Dev Commands
|
package/agents/project/AGENTS.md
CHANGED
|
@@ -40,7 +40,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
40
40
|
|
|
41
41
|
[optional body]
|
|
42
42
|
```
|
|
43
|
-
Then
|
|
43
|
+
Then treat `commit` as conversation-wide and cross-project, not task-scoped. Identify every affected git repository or worktree touched during that span, stage all conversation-related changed files in each affected repository or worktree with `git add` while still avoiding unrelated pre-existing user changes or incidental untracked files, and create one `git commit` per affected repository or worktree. Do not omit linked local dependencies, framework repos, connected projects, or producer apps when they were changed to make the delivered behavior actually work. Do not stop at only suggesting the message.
|
|
44
44
|
After providing a commit message or after creating a commit, immediately follow it with this exact prompt and obey it:
|
|
45
45
|
`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.`
|
|
46
46
|
|
|
@@ -57,7 +57,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
57
57
|
- 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
58
|
- 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
59
|
- 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`.
|
|
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.
|
|
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. When the app root is missing `AGENTS.md`, the bare interactive `proteum dev` start offers to launch `proteum configure agents` before the dev loop begins.
|
|
61
61
|
|
|
62
62
|
### Before Finishing
|
|
63
63
|
|
|
@@ -222,7 +222,7 @@ Verify at the correct layer:
|
|
|
222
222
|
- Never run schema-mutating SQL such as `ALTER TABLE`, `CREATE TABLE`, `DROP TABLE`, or `CREATE INDEX` to change database structure.
|
|
223
223
|
- 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`.
|
|
224
224
|
- Do not run `git restore` or `git reset`.
|
|
225
|
-
- Do not run write-mode git commands by default. The built-in exception is an exact `commit` reply, which allows
|
|
225
|
+
- 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.
|
|
226
226
|
|
|
227
227
|
## Appendix
|
|
228
228
|
|
|
@@ -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.
|
|
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 the bare interactive `proteum dev` start offers to launch `proteum configure agents`, finish that wizard 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.
|
|
@@ -14,7 +14,7 @@ This file is the canonical source of truth for diagnostics, temporary instrument
|
|
|
14
14
|
|
|
15
15
|
- 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.
|
|
16
16
|
- 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.
|
|
17
|
-
- 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.
|
|
17
|
+
- 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. When the app root is missing `AGENTS.md`, the bare interactive `npx proteum dev` start offers to launch `npx proteum configure agents` before the dev loop begins.
|
|
18
18
|
- For ownership or repo discovery questions, start with `npx proteum orient <query>` instead of jumping straight into source searches.
|
|
19
19
|
- 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.
|
|
20
20
|
- Prefer focused verification before global checks: `npx proteum verify owner <query>`, `npx proteum verify request <path>`, and only then `npx proteum verify browser <path>` or targeted Playwright when the bug is browser-visible.
|
|
@@ -30,7 +30,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
30
30
|
|
|
31
31
|
[optional body]
|
|
32
32
|
```
|
|
33
|
-
Then
|
|
33
|
+
Then treat `commit` as conversation-wide and cross-project, not task-scoped. Identify every affected git repository or worktree touched during that span, stage all conversation-related changed files in each affected repository or worktree with `git add` while still avoiding unrelated pre-existing user changes or incidental untracked files, and create one `git commit` per affected repository or worktree. Do not omit linked local dependencies, framework repos, connected projects, or producer apps when they were changed to make the delivered behavior actually work. Do not stop at only suggesting the message.
|
|
34
34
|
After providing a commit message or after creating a commit, immediately follow it with this exact prompt and obey it:
|
|
35
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
36
|
|
|
@@ -47,7 +47,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
|
|
|
47
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
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
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.
|
|
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. When the app root is missing `AGENTS.md`, the bare interactive `proteum dev` start offers to launch `proteum configure agents` before the dev loop begins.
|
|
51
51
|
|
|
52
52
|
### Before Finishing
|
|
53
53
|
|
|
@@ -212,7 +212,7 @@ Verify at the correct layer:
|
|
|
212
212
|
- Never run schema-mutating SQL such as `ALTER TABLE`, `CREATE TABLE`, `DROP TABLE`, or `CREATE INDEX` to change database structure.
|
|
213
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
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
|
|
215
|
+
- 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.
|
|
216
216
|
|
|
217
217
|
## Appendix
|
|
218
218
|
|
|
@@ -155,7 +155,16 @@ const renderConfigureResultSections = (result: TConfigureProjectAgentSymlinksRes
|
|
|
155
155
|
export const run = async (): Promise<void> => {
|
|
156
156
|
if (cli.args.action !== 'agents') throw new UsageError('Usage: `proteum configure agents`');
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
await runConfigureAgentsWizard();
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const runConfigureAgentsWizard = async ({
|
|
162
|
+
appRoot = resolveCanonicalPath(cli.paths.appRoot),
|
|
163
|
+
coreRoot = cli.paths.core.root,
|
|
164
|
+
}: {
|
|
165
|
+
appRoot?: string;
|
|
166
|
+
coreRoot?: string;
|
|
167
|
+
} = {}) => {
|
|
159
168
|
assertProteumAppRoot(appRoot);
|
|
160
169
|
|
|
161
170
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
@@ -197,7 +206,7 @@ export const run = async (): Promise<void> => {
|
|
|
197
206
|
|
|
198
207
|
const preview = configureProjectAgentSymlinks({
|
|
199
208
|
appRoot,
|
|
200
|
-
coreRoot
|
|
209
|
+
coreRoot,
|
|
201
210
|
dryRun: true,
|
|
202
211
|
monorepoRoot,
|
|
203
212
|
});
|
|
@@ -214,7 +223,7 @@ export const run = async (): Promise<void> => {
|
|
|
214
223
|
|
|
215
224
|
const result = configureProjectAgentSymlinks({
|
|
216
225
|
appRoot,
|
|
217
|
-
coreRoot
|
|
226
|
+
coreRoot,
|
|
218
227
|
monorepoRoot,
|
|
219
228
|
overwriteBlockedPaths,
|
|
220
229
|
});
|
package/cli/commands/dev.ts
CHANGED
|
@@ -7,6 +7,8 @@ import path from 'path';
|
|
|
7
7
|
import { spawn, ChildProcess } from 'child_process';
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
9
|
import type { FSWatcher } from 'fs';
|
|
10
|
+
import prompts from 'prompts';
|
|
11
|
+
import { UsageError } from 'clipanion';
|
|
10
12
|
|
|
11
13
|
// Cor elibs
|
|
12
14
|
import cli from '..';
|
|
@@ -20,9 +22,11 @@ import {
|
|
|
20
22
|
|
|
21
23
|
// Configs
|
|
22
24
|
import Compiler from '../compiler';
|
|
25
|
+
import { regex } from '../compiler/common';
|
|
23
26
|
import { createDevEventServer } from './devEvents';
|
|
24
27
|
import { renderDevSession, renderServerReadyBanner, renderDevShutdownBanner } from '../presentation/devSession';
|
|
25
28
|
import { clearInteractiveConsole } from '../presentation/welcome';
|
|
29
|
+
import { renderWarning } from '../presentation/ink';
|
|
26
30
|
import {
|
|
27
31
|
createDevSessionRecord,
|
|
28
32
|
inspectDevSessionFile,
|
|
@@ -37,6 +41,8 @@ import {
|
|
|
37
41
|
} from '../runtime/devSessions';
|
|
38
42
|
import { resolveFrameworkInstallInfo } from '../paths';
|
|
39
43
|
import { logVerbose } from '../runtime/verbose';
|
|
44
|
+
import { inspectProjectAgentFiles } from '../utils/agents';
|
|
45
|
+
import { runConfigureAgentsWizard } from './configure';
|
|
40
46
|
|
|
41
47
|
// Core
|
|
42
48
|
import { app, App } from '../app';
|
|
@@ -138,6 +144,45 @@ const createIgnoredWatchMatcher = (outputPaths: string[]) => (watchPath: string)
|
|
|
138
144
|
return ignoredWatchPathPatterns.test(normalizedWatchPath);
|
|
139
145
|
};
|
|
140
146
|
|
|
147
|
+
const promptToConfigureAgentsIfMissing = async () => {
|
|
148
|
+
if (cli.args.json === true) return;
|
|
149
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
150
|
+
|
|
151
|
+
const inspection = inspectProjectAgentFiles({ appRoot: app.paths.root });
|
|
152
|
+
if (!inspection.missing.includes('AGENTS.md')) return;
|
|
153
|
+
|
|
154
|
+
console.info(await renderWarning('Proteum could not find the app-root `AGENTS.md` instruction file.'));
|
|
155
|
+
console.info(
|
|
156
|
+
[
|
|
157
|
+
'Missing standard AGENTS files:',
|
|
158
|
+
...inspection.missing.map((entry) => `- ${entry}`),
|
|
159
|
+
'',
|
|
160
|
+
'Run `proteum configure agents` now before starting the dev server?',
|
|
161
|
+
].join('\n'),
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const response = await prompts(
|
|
165
|
+
{
|
|
166
|
+
type: 'confirm',
|
|
167
|
+
name: 'value',
|
|
168
|
+
message: 'Run the configure-agents wizard now?',
|
|
169
|
+
initial: true,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
onCancel: () => {
|
|
173
|
+
throw new UsageError('Cancelled `proteum dev`.');
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
if (response.value !== true) return;
|
|
179
|
+
|
|
180
|
+
await runConfigureAgentsWizard({
|
|
181
|
+
appRoot: app.paths.root,
|
|
182
|
+
coreRoot: cli.paths.core.root,
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
|
|
141
186
|
const getDevAppName = (app: App) =>
|
|
142
187
|
app.identity.web?.fullTitle || app.identity.web?.title || app.identity.name || app.packageJson.name || app.paths.root;
|
|
143
188
|
|
|
@@ -481,10 +526,66 @@ function normalizeWatchPath(watchPath: string) {
|
|
|
481
526
|
return path.resolve(watchPath).replace(/\\/g, '/').replace(/\/$/, '');
|
|
482
527
|
}
|
|
483
528
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
529
|
+
type TIndexedSourceWatchEvent = 'change' | 'rename';
|
|
530
|
+
type TIndexedSourceWatchCompilerName = 'server' | 'client';
|
|
531
|
+
type TIndexedSourceWatchInvalidateTarget = 'all' | TIndexedSourceWatchCompilerName;
|
|
532
|
+
type TIndexedSourceWatchRule = {
|
|
533
|
+
compilerName: TIndexedSourceWatchCompilerName;
|
|
534
|
+
rootPath: string;
|
|
535
|
+
relativePathPattern: RegExp;
|
|
536
|
+
eventTypes: TIndexedSourceWatchEvent[];
|
|
537
|
+
invalidateTarget: TIndexedSourceWatchInvalidateTarget;
|
|
538
|
+
};
|
|
539
|
+
type TNamedWatching = { compiler: { name?: string }; invalidate: () => void };
|
|
540
|
+
type TMultiWatchingLike = TDevWatching & { watchings?: TNamedWatching[] };
|
|
541
|
+
|
|
542
|
+
const resolveIndexedSourceWatchRules = (): TIndexedSourceWatchRule[] => {
|
|
543
|
+
const transpileWatchRoots = app.transpileModuleDirectories
|
|
544
|
+
.map((rootPath) => {
|
|
545
|
+
try {
|
|
546
|
+
return fs.realpathSync(rootPath);
|
|
547
|
+
} catch {
|
|
548
|
+
return rootPath;
|
|
549
|
+
}
|
|
550
|
+
})
|
|
551
|
+
.map(normalizeWatchPath)
|
|
552
|
+
.filter((rootPath, index, list) => list.indexOf(rootPath) === index);
|
|
553
|
+
|
|
554
|
+
return [
|
|
555
|
+
{
|
|
556
|
+
compilerName: 'server',
|
|
557
|
+
rootPath: app.paths.root,
|
|
558
|
+
relativePathPattern: /^commands(?:\/|$)/,
|
|
559
|
+
eventTypes: ['rename'],
|
|
560
|
+
invalidateTarget: 'all',
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
compilerName: 'server',
|
|
564
|
+
rootPath: cli.paths.core.root,
|
|
565
|
+
relativePathPattern: /^commands(?:\/|$)/,
|
|
566
|
+
eventTypes: ['rename'],
|
|
567
|
+
invalidateTarget: 'all',
|
|
568
|
+
},
|
|
569
|
+
...transpileWatchRoots.map(
|
|
570
|
+
(rootPath): TIndexedSourceWatchRule => ({
|
|
571
|
+
compilerName: 'server',
|
|
572
|
+
rootPath,
|
|
573
|
+
relativePathPattern: regex.scripts,
|
|
574
|
+
eventTypes: ['change', 'rename'],
|
|
575
|
+
invalidateTarget: 'server',
|
|
576
|
+
}),
|
|
577
|
+
),
|
|
578
|
+
];
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
const findCompilerWatching = (
|
|
582
|
+
watching: TDevWatching,
|
|
583
|
+
compilerName: TIndexedSourceWatchCompilerName,
|
|
584
|
+
): TNamedWatching | undefined => {
|
|
585
|
+
const childWatchings = (watching as TMultiWatchingLike).watchings;
|
|
586
|
+
|
|
587
|
+
return childWatchings?.find((childWatching) => childWatching.compiler.name === compilerName);
|
|
588
|
+
};
|
|
488
589
|
|
|
489
590
|
const closeFsWatcher = async (watcher: FSWatcher) => {
|
|
490
591
|
await new Promise<void>((resolve) => {
|
|
@@ -501,7 +602,9 @@ const createIndexedSourceWatching = ({
|
|
|
501
602
|
watching: TDevWatching;
|
|
502
603
|
}): TIndexedSourceWatching => {
|
|
503
604
|
const watchers: FSWatcher[] = [];
|
|
504
|
-
const pendingChanges = new Map<
|
|
605
|
+
const pendingChanges = new Map<TIndexedSourceWatchCompilerName, Set<string>>();
|
|
606
|
+
const pendingInvalidateTargets = new Set<TIndexedSourceWatchInvalidateTarget>();
|
|
607
|
+
const recentQueuedChanges = new Map<string, number>();
|
|
505
608
|
let invalidateTimer: NodeJS.Timeout | undefined;
|
|
506
609
|
|
|
507
610
|
const flushInvalidate = () => {
|
|
@@ -512,31 +615,77 @@ const createIndexedSourceWatching = ({
|
|
|
512
615
|
}
|
|
513
616
|
|
|
514
617
|
pendingChanges.clear();
|
|
515
|
-
|
|
516
|
-
|
|
618
|
+
|
|
619
|
+
if (pendingInvalidateTargets.has('all')) {
|
|
620
|
+
pendingInvalidateTargets.clear();
|
|
621
|
+
logVerbose('Indexed source files changed. Invalidating the dev compiler to refresh generated artifacts.');
|
|
622
|
+
watching.invalidate();
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const invalidateTargets = [...pendingInvalidateTargets].filter(
|
|
627
|
+
(invalidateTarget): invalidateTarget is TIndexedSourceWatchCompilerName => invalidateTarget !== 'all',
|
|
628
|
+
);
|
|
629
|
+
pendingInvalidateTargets.clear();
|
|
630
|
+
|
|
631
|
+
if (invalidateTargets.length === 0) return;
|
|
632
|
+
|
|
633
|
+
logVerbose('Transpiled source files changed. Invalidating the server compiler to refresh mutable package code.');
|
|
634
|
+
for (const invalidateTarget of invalidateTargets) {
|
|
635
|
+
const compilerWatching = findCompilerWatching(watching, invalidateTarget);
|
|
636
|
+
|
|
637
|
+
if (!compilerWatching) {
|
|
638
|
+
watching.invalidate();
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
compilerWatching.invalidate();
|
|
643
|
+
}
|
|
517
644
|
};
|
|
518
645
|
|
|
519
|
-
const queueInvalidate = (
|
|
646
|
+
const queueInvalidate = ({
|
|
647
|
+
compilerName,
|
|
648
|
+
filepath,
|
|
649
|
+
invalidateTarget,
|
|
650
|
+
}: {
|
|
651
|
+
compilerName: TIndexedSourceWatchCompilerName;
|
|
652
|
+
filepath: string;
|
|
653
|
+
invalidateTarget: TIndexedSourceWatchInvalidateTarget;
|
|
654
|
+
}) => {
|
|
520
655
|
const normalizedFilepath = normalizeWatchPath(filepath);
|
|
656
|
+
const queueKey = `${invalidateTarget}:${compilerName}:${normalizedFilepath}`;
|
|
657
|
+
const queuedAt = recentQueuedChanges.get(queueKey);
|
|
658
|
+
|
|
659
|
+
if (queuedAt !== undefined && Date.now() - queuedAt < 250) return;
|
|
660
|
+
|
|
661
|
+
recentQueuedChanges.set(queueKey, Date.now());
|
|
521
662
|
const changedFiles = pendingChanges.get(compilerName) || new Set<string>();
|
|
522
663
|
|
|
523
664
|
changedFiles.add(normalizedFilepath);
|
|
524
665
|
pendingChanges.set(compilerName, changedFiles);
|
|
666
|
+
pendingInvalidateTargets.add(invalidateTarget);
|
|
525
667
|
|
|
526
668
|
if (invalidateTimer) return;
|
|
527
669
|
invalidateTimer = setTimeout(flushInvalidate, 40);
|
|
528
670
|
};
|
|
529
671
|
|
|
530
|
-
for (const watchRule of
|
|
531
|
-
const rootPath = watchRule.
|
|
672
|
+
for (const watchRule of resolveIndexedSourceWatchRules()) {
|
|
673
|
+
const rootPath = watchRule.rootPath;
|
|
674
|
+
if (!fs.existsSync(rootPath)) continue;
|
|
532
675
|
|
|
533
676
|
watchers.push(
|
|
534
677
|
fs.watch(rootPath, { recursive: true }, (eventType, filename) => {
|
|
535
678
|
const relativePath = typeof filename === 'string' ? filename.replace(/\\/g, '/').replace(/^\.\//, '') : '';
|
|
679
|
+
const normalizedEventType: TIndexedSourceWatchEvent = eventType === 'change' ? 'change' : 'rename';
|
|
680
|
+
|
|
536
681
|
if (relativePath && !watchRule.relativePathPattern.test(relativePath)) return;
|
|
537
|
-
if (
|
|
682
|
+
if (!watchRule.eventTypes.includes(normalizedEventType) && relativePath) return;
|
|
538
683
|
|
|
539
|
-
queueInvalidate(
|
|
684
|
+
queueInvalidate({
|
|
685
|
+
compilerName: watchRule.compilerName,
|
|
686
|
+
filepath: relativePath ? path.join(rootPath, relativePath) : rootPath,
|
|
687
|
+
invalidateTarget: watchRule.invalidateTarget,
|
|
688
|
+
});
|
|
540
689
|
}),
|
|
541
690
|
);
|
|
542
691
|
}
|
|
@@ -731,5 +880,6 @@ export const run = async () => {
|
|
|
731
880
|
return;
|
|
732
881
|
}
|
|
733
882
|
|
|
883
|
+
await promptToConfigureAgentsIfMissing();
|
|
734
884
|
await runDevLoop();
|
|
735
885
|
};
|
|
@@ -45,6 +45,15 @@ export default function createCommonConfig(
|
|
|
45
45
|
): Configuration {
|
|
46
46
|
const dev = mode === 'dev';
|
|
47
47
|
const enableFilesystemCache = dev ? cli.args.cache !== false : cli.args.cache === true;
|
|
48
|
+
const transpileModuleDirectories = app.transpileModuleDirectories;
|
|
49
|
+
const transpileModuleSnapshot =
|
|
50
|
+
dev && transpileModuleDirectories.length > 0
|
|
51
|
+
? {
|
|
52
|
+
// Transpiled local packages can resolve through node_modules symlinks,
|
|
53
|
+
// but they still need live invalidation like mutable app sources in dev.
|
|
54
|
+
unmanagedPaths: transpileModuleDirectories,
|
|
55
|
+
}
|
|
56
|
+
: undefined;
|
|
48
57
|
const frameworkPackageRoots = [cli.paths.framework.installedRoot, cli.paths.framework.activeRoot].filter(
|
|
49
58
|
(rootPath, index, list): rootPath is string => typeof rootPath === 'string' && list.indexOf(rootPath) === index,
|
|
50
59
|
);
|
|
@@ -109,6 +118,8 @@ export default function createCommonConfig(
|
|
|
109
118
|
]*/
|
|
110
119
|
},
|
|
111
120
|
|
|
121
|
+
...(transpileModuleSnapshot ? { snapshot: transpileModuleSnapshot } : {}),
|
|
122
|
+
|
|
112
123
|
// Turn off performance processing because we utilize
|
|
113
124
|
// our own hints via the FileSizeReporter
|
|
114
125
|
performance: false,
|
|
@@ -123,6 +134,11 @@ export default function createCommonConfig(
|
|
|
123
134
|
cacheDirectory: path.join(app.paths.cache, 'rspack', side, mode),
|
|
124
135
|
compression: false,
|
|
125
136
|
buildDependencies: { config: [__filename] },
|
|
137
|
+
...(transpileModuleSnapshot
|
|
138
|
+
? {
|
|
139
|
+
snapshot: transpileModuleSnapshot,
|
|
140
|
+
}
|
|
141
|
+
: {}),
|
|
126
142
|
}
|
|
127
143
|
: false,
|
|
128
144
|
|
|
@@ -190,6 +190,7 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
190
190
|
notes: [
|
|
191
191
|
'Use `--cwd` when the target Proteum app lives in another worktree or checkout and you do not want to `cd` first.',
|
|
192
192
|
'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.',
|
|
193
|
+
'Before the interactive dev loop starts, Proteum offers to launch `proteum configure agents` when the app root is missing `AGENTS.md`.',
|
|
193
194
|
'Use `--replace-existing` when retries should stop the previously tracked matching session before starting a new one.',
|
|
194
195
|
'`proteum dev list` inspects tracked sessions for the current app root. Add `--stale` to show only orphaned or dead sessions.',
|
|
195
196
|
'`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,6 +139,10 @@ export const renderCliOverview = async ({
|
|
|
139
139
|
indent: ' ',
|
|
140
140
|
nextIndent: ' ',
|
|
141
141
|
}),
|
|
142
|
+
wrapText('When the app root is missing `AGENTS.md`, the interactive `proteum dev` start offers to launch `proteum configure agents` before the dev loop begins.', {
|
|
143
|
+
indent: ' ',
|
|
144
|
+
nextIndent: ' ',
|
|
145
|
+
}),
|
|
142
146
|
wrapText('Legacy single-dash flags and positional booleans remain accepted for older app scripts, but new docs should prefer modern long flags.', {
|
|
143
147
|
indent: ' ',
|
|
144
148
|
nextIndent: ' ',
|
package/cli/utils/agents.ts
CHANGED
|
@@ -42,6 +42,11 @@ export type TConfigureProjectAgentSymlinksResult = {
|
|
|
42
42
|
updatedGitignores: string[];
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
export type TProjectAgentFileInspection = {
|
|
46
|
+
existing: string[];
|
|
47
|
+
missing: string[];
|
|
48
|
+
};
|
|
49
|
+
|
|
45
50
|
/*----------------------------------
|
|
46
51
|
- CONSTANTS
|
|
47
52
|
----------------------------------*/
|
|
@@ -147,6 +152,37 @@ export function renderProjectInstructionGitignoreBlock({ coreRoot }: TProjectIns
|
|
|
147
152
|
return renderInstructionGitignoreBlock({ linkDefinitions: getAppAgentLinkDefinitions({ coreRoot, mode: 'standalone' }) });
|
|
148
153
|
}
|
|
149
154
|
|
|
155
|
+
export function inspectProjectAgentFiles({ appRoot }: { appRoot: string }): TProjectAgentFileInspection {
|
|
156
|
+
const normalizedAppRoot = path.resolve(appRoot);
|
|
157
|
+
const expectedAgentPaths = Array.from(
|
|
158
|
+
new Set(
|
|
159
|
+
standaloneAppAgentLinkDefinitions
|
|
160
|
+
.map((linkDefinition) => linkDefinition.projectPath)
|
|
161
|
+
.filter((projectPath) => projectPath.endsWith('AGENTS.md')),
|
|
162
|
+
),
|
|
163
|
+
);
|
|
164
|
+
const result: TProjectAgentFileInspection = {
|
|
165
|
+
existing: [],
|
|
166
|
+
missing: [],
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
for (const projectPath of expectedAgentPaths) {
|
|
170
|
+
const absolutePath = path.join(normalizedAppRoot, projectPath);
|
|
171
|
+
const parentPath = path.dirname(absolutePath);
|
|
172
|
+
|
|
173
|
+
if (projectPath !== 'AGENTS.md' && !fs.existsSync(parentPath)) continue;
|
|
174
|
+
|
|
175
|
+
if (fs.existsSync(absolutePath)) {
|
|
176
|
+
result.existing.push(projectPath);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
result.missing.push(projectPath);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
150
186
|
/*----------------------------------
|
|
151
187
|
- HELPERS
|
|
152
188
|
----------------------------------*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proteum",
|
|
3
3
|
"description": "LLM-first Opinionated Typescript Framework for web applications.",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.2",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/proteum.git",
|
|
7
7
|
"license": "MIT",
|