proteum 2.1.9 → 2.2.0
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 +25 -11
- package/README.md +19 -9
- package/agents/project/AGENTS.md +165 -120
- 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 +295 -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 +2 -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 +12 -1
- 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/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 +25 -6
- 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 +117 -0
- 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/router/index.ts +64 -14
- package/server/services/router/request/api.ts +7 -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
|
@@ -6,6 +6,8 @@ import type { TRow } from './layout';
|
|
|
6
6
|
export const proteumCommandNames = [
|
|
7
7
|
'init',
|
|
8
8
|
'create',
|
|
9
|
+
'configure',
|
|
10
|
+
'migrate',
|
|
9
11
|
'dev',
|
|
10
12
|
'refresh',
|
|
11
13
|
'build',
|
|
@@ -15,6 +17,7 @@ export const proteumCommandNames = [
|
|
|
15
17
|
'connect',
|
|
16
18
|
'doctor',
|
|
17
19
|
'explain',
|
|
20
|
+
'orient',
|
|
18
21
|
'diagnose',
|
|
19
22
|
'perf',
|
|
20
23
|
'trace',
|
|
@@ -44,17 +47,17 @@ export type TProteumCommandDoc = {
|
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
export const proteumRecommendedFlow: TRow[] = [
|
|
47
|
-
{ label: '1. proteum
|
|
48
|
-
{ label: '2. proteum
|
|
49
|
-
{ label: '3. proteum
|
|
50
|
-
{ label: '4. proteum
|
|
50
|
+
{ label: '1. proteum orient <query>', value: 'Start here for multi-repo, generated, or connected work before reading code.' },
|
|
51
|
+
{ label: '2. proteum dev', value: 'Start the compiler, SSR server, and hot reload loop.' },
|
|
52
|
+
{ label: '3. proteum diagnose <path> --hit <path>', value: 'Validate the smallest trustworthy request surface before broader checks.' },
|
|
53
|
+
{ label: '4. proteum check', value: 'Refresh, typecheck, and lint before you commit or push.' },
|
|
51
54
|
];
|
|
52
55
|
|
|
53
56
|
export const proteumCommandGroups: Array<{ title: string; names: TProteumCommandName[] }> = [
|
|
54
57
|
{ title: 'Daily workflow', names: ['dev', 'refresh', 'build'] },
|
|
55
58
|
{ title: 'Quality gates', names: ['typecheck', 'lint', 'check'] },
|
|
56
|
-
{ title: 'Manifest and contracts', names: ['connect', 'doctor', 'explain', 'diagnose', 'perf', 'trace', 'command', 'session', 'verify'] },
|
|
57
|
-
{ title: 'Project scaffolding', names: ['init', 'create'] },
|
|
59
|
+
{ title: 'Manifest and contracts', names: ['connect', 'doctor', 'explain', 'orient', 'diagnose', 'perf', 'trace', 'command', 'session', 'verify'] },
|
|
60
|
+
{ title: 'Project scaffolding', names: ['init', 'configure', 'create', 'migrate'] },
|
|
58
61
|
];
|
|
59
62
|
|
|
60
63
|
export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> = {
|
|
@@ -106,15 +109,66 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
106
109
|
],
|
|
107
110
|
status: 'experimental',
|
|
108
111
|
},
|
|
112
|
+
configure: {
|
|
113
|
+
name: 'configure',
|
|
114
|
+
category: 'Project scaffolding',
|
|
115
|
+
summary: 'Interactively configure Proteum-managed instruction symlinks for a standalone app or monorepo app root.',
|
|
116
|
+
usage: 'proteum configure agents',
|
|
117
|
+
bestFor:
|
|
118
|
+
'Creating or switching the managed `AGENTS.md` instruction layout intentionally instead of having `init` or `dev` write symlinks implicitly.',
|
|
119
|
+
examples: [
|
|
120
|
+
{
|
|
121
|
+
description: 'Configure instruction symlinks for the current standalone app',
|
|
122
|
+
command: 'proteum configure agents',
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
notes: [
|
|
126
|
+
'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` symlink.',
|
|
127
|
+
'Standalone mode writes the full app-root instruction set into the current Proteum app root.',
|
|
128
|
+
'Monorepo mode writes the reusable root `AGENTS.md` into the chosen monorepo root and switches the current app root `AGENTS.md` to the app-root addendum.',
|
|
129
|
+
'If a target path already contains a non-managed file or foreign symlink, the interactive flow asks whether to overwrite it with the Proteum-managed symlink.',
|
|
130
|
+
'Declined non-managed paths are left untouched; Proteum still creates missing symlinks and updates symlinks it already manages.',
|
|
131
|
+
],
|
|
132
|
+
status: 'experimental',
|
|
133
|
+
},
|
|
134
|
+
migrate: {
|
|
135
|
+
name: 'migrate',
|
|
136
|
+
category: 'Project scaffolding',
|
|
137
|
+
summary: 'Rewrite legacy page registrations to the explicit Router.page(path, options, data, render) contract.',
|
|
138
|
+
usage: 'proteum migrate page-contract [--cwd <path>] [--dry-run] [--json]',
|
|
139
|
+
bestFor:
|
|
140
|
+
'Upgrading existing Proteum apps to the single explicit page contract without hand-editing every `client/pages/**` file.',
|
|
141
|
+
examples: [
|
|
142
|
+
{ description: 'Rewrite the current app in place', command: 'proteum migrate page-contract' },
|
|
143
|
+
{
|
|
144
|
+
description: 'Preview the migration without writing files',
|
|
145
|
+
command: 'proteum migrate page-contract --dry-run --json',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
description: 'Migrate another app root from the current shell',
|
|
149
|
+
command: 'proteum migrate page-contract --cwd /path/to/app',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
notes: [
|
|
153
|
+
'This migration rewrites supported legacy Router.page signatures to the explicit 4-argument form.',
|
|
154
|
+
'If a page data function cannot be analyzed safely, Proteum leaves the file unchanged and reports a manual-fix location.',
|
|
155
|
+
'Run `proteum typecheck` and `proteum build --strict` after the rewrite.',
|
|
156
|
+
],
|
|
157
|
+
status: 'experimental',
|
|
158
|
+
},
|
|
109
159
|
dev: {
|
|
110
160
|
name: 'dev',
|
|
111
161
|
category: 'Daily workflow',
|
|
112
162
|
summary: 'Start the local compiler, SSR server, and hot reload loop.',
|
|
113
|
-
usage: 'proteum dev [list|stop] [--port <port>] [--session-file <path>] [--replace-existing] [--all] [--stale] [--json] [--cache|--no-cache]',
|
|
163
|
+
usage: 'proteum dev [list|stop] [--cwd <path>] [--port <port>] [--session-file <path>] [--replace-existing] [--all] [--stale] [--json] [--cache|--no-cache]',
|
|
114
164
|
bestFor:
|
|
115
165
|
'Day-to-day app work. This is the main entrypoint used by the current reference apps during local development.',
|
|
116
166
|
examples: [
|
|
117
167
|
{ description: 'Start the app on its configured router port', command: 'proteum dev' },
|
|
168
|
+
{
|
|
169
|
+
description: 'Start a worktree or sibling checkout without changing your shell directory',
|
|
170
|
+
command: 'proteum dev --cwd /path/to/platform-worktree --port 3101 --replace-existing',
|
|
171
|
+
},
|
|
118
172
|
{ description: 'Replace the tracked dev session on another port', command: 'proteum dev --port 3101 --replace-existing' },
|
|
119
173
|
{
|
|
120
174
|
description: 'Start a tracked dev session with an explicit session file for an agent task',
|
|
@@ -134,6 +188,7 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
134
188
|
},
|
|
135
189
|
],
|
|
136
190
|
notes: [
|
|
191
|
+
'Use `--cwd` when the target Proteum app lives in another worktree or checkout and you do not want to `cd` first.',
|
|
137
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.',
|
|
138
193
|
'Use `--replace-existing` when retries should stop the previously tracked matching session before starting a new one.',
|
|
139
194
|
'`proteum dev list` inspects tracked sessions for the current app root. Add `--stale` to show only orphaned or dead sessions.',
|
|
@@ -283,6 +338,25 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
283
338
|
],
|
|
284
339
|
status: 'stable',
|
|
285
340
|
},
|
|
341
|
+
orient: {
|
|
342
|
+
name: 'orient',
|
|
343
|
+
category: 'Manifest and contracts',
|
|
344
|
+
summary: 'Resolve owners, guidance files, connected boundaries, and next steps before opening code.',
|
|
345
|
+
usage: 'proteum orient <query> [--port <port>|--url <baseUrl>] [--json]',
|
|
346
|
+
bestFor:
|
|
347
|
+
'Starting multi-repo, generated-artifact, or connected-project work with one explicit orientation step instead of guessing the first files to read.',
|
|
348
|
+
examples: [
|
|
349
|
+
{ description: 'Orient around a generated controller path', command: 'proteum orient /api/Auth/CurrentUser' },
|
|
350
|
+
{ description: 'Orient around a connected namespace or route', command: 'proteum orient Product.Stats.general' },
|
|
351
|
+
{ description: 'Use a running dev server when the local manifest is unavailable', command: 'proteum orient /domains --port 3101 --json' },
|
|
352
|
+
],
|
|
353
|
+
notes: [
|
|
354
|
+
'This command combines manifest owner lookup, local or fallback guidance resolution, connected-boundary hints, and three recommended next commands.',
|
|
355
|
+
'Use it before reading source when the query might map to generated code, connected imports, or framework-owned files.',
|
|
356
|
+
'When `--port` or `--url` is provided, Proteum can read the manifest from a running dev server instead of only from disk.',
|
|
357
|
+
],
|
|
358
|
+
status: 'experimental',
|
|
359
|
+
},
|
|
286
360
|
diagnose: {
|
|
287
361
|
name: 'diagnose',
|
|
288
362
|
category: 'Manifest and contracts',
|
|
@@ -407,21 +481,37 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
407
481
|
verify: {
|
|
408
482
|
name: 'verify',
|
|
409
483
|
category: 'Manifest and contracts',
|
|
410
|
-
summary: '
|
|
411
|
-
usage: 'proteum verify [framework-change] [--crosspath <path>] [--product <path>] [--website <path>] [--crosspath-port <port>] [--product-port <port>] [--website-port <port>] [--route <path>] [--json]',
|
|
484
|
+
summary: 'Run focused owner/request/browser verification or the full framework reference-app validation pass.',
|
|
485
|
+
usage: 'proteum verify [framework-change|owner <query>|request <path>|browser <path>] [--port <port>|--url <baseUrl>] [--session-email <email>] [--session-role <role>] [--method <verb>] [--data-json <json>] [--strict-global] [--crosspath <path>] [--product <path>] [--website <path>] [--crosspath-port <port>] [--product-port <port>] [--website-port <port>] [--route <path>] [--json]',
|
|
412
486
|
bestFor:
|
|
413
|
-
'
|
|
487
|
+
'Choosing the smallest trustworthy verification surface first, then separating introduced blocking findings from unrelated pre-existing diagnostics.',
|
|
414
488
|
examples: [
|
|
415
489
|
{
|
|
416
490
|
description: 'Run the default framework smoke verification against the reference apps',
|
|
417
491
|
command: 'proteum verify framework-change',
|
|
418
492
|
},
|
|
493
|
+
{
|
|
494
|
+
description: 'Verify only the owner-scoped chain for a generated controller or route',
|
|
495
|
+
command: 'proteum verify owner /api/Auth/CurrentUser',
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
description: 'Hit one real request against a running dev server and classify findings',
|
|
499
|
+
command: 'proteum verify request /domains --port 3101',
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
description: 'Run browser verification only when the issue is browser-visible',
|
|
503
|
+
command: 'proteum verify browser /dashboard --port 3101 --session-email admin@example.com --session-role ADMIN',
|
|
504
|
+
},
|
|
419
505
|
{
|
|
420
506
|
description: 'Load a specific route in the website validation pass',
|
|
421
507
|
command: 'proteum verify framework-change --route /domains',
|
|
422
508
|
},
|
|
423
509
|
],
|
|
424
510
|
notes: [
|
|
511
|
+
'`proteum verify owner` starts from `proteum orient`, then chooses the smallest trustworthy verify path instead of defaulting to broad global checks.',
|
|
512
|
+
'`proteum verify owner`, `request`, and `browser` emit `introducedFindings`, `preExistingFindings`, `verificationSteps`, and `result` in JSON.',
|
|
513
|
+
'Focused verification fails on introduced blocking findings by default and only fails on unrelated pre-existing blockers when `--strict-global` is passed.',
|
|
514
|
+
'`proteum verify browser` uses an app-local browser workspace under `var/proteum/browser/<run-id>` and never reuses a previous run profile.',
|
|
425
515
|
'When a reference app is already running on the requested port, Proteum reuses it instead of spawning a new `proteum dev` process.',
|
|
426
516
|
'When Proteum spawns the website reference app, it sets the env values consumed by the website `proteum.config.ts` for the product internal and public URLs.',
|
|
427
517
|
'This command is intended for the framework repo and will be most useful where the reference app paths exist locally.',
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
const React = require('react') as typeof import('react');
|
|
2
|
-
|
|
3
1
|
import type { TServerReadyConnectedProject } from '../../common/dev/serverHotReload';
|
|
4
2
|
import { renderRows } from './layout';
|
|
5
|
-
import { renderInk } from './ink';
|
|
3
|
+
import { CliReact, renderInk } from './ink';
|
|
6
4
|
import { renderWelcomePanel } from './welcome';
|
|
7
5
|
|
|
8
6
|
const formatConnectedProjectLabel = (connectedProject: TServerReadyConnectedProject) =>
|
|
@@ -66,7 +64,7 @@ export const renderServerReadyBanner = async ({
|
|
|
66
64
|
connectedProjects?: TServerReadyConnectedProject[];
|
|
67
65
|
}) =>
|
|
68
66
|
renderInk(({ Box, Text }) => {
|
|
69
|
-
const createElement =
|
|
67
|
+
const createElement = CliReact.createElement;
|
|
70
68
|
const verifiedConnectedProjects = connectedProjects || [];
|
|
71
69
|
|
|
72
70
|
return createElement(
|
|
@@ -87,7 +85,7 @@ export const renderServerReadyBanner = async ({
|
|
|
87
85
|
createElement(
|
|
88
86
|
Text,
|
|
89
87
|
{ key: `connected-ping-${connectedProject.namespace}`, dimColor: true },
|
|
90
|
-
`Ping OK: ${formatConnectedProjectLabel(connectedProject)}
|
|
88
|
+
`Ping OK (/ping): ${formatConnectedProjectLabel(connectedProject)}`,
|
|
91
89
|
),
|
|
92
90
|
),
|
|
93
91
|
createElement(Text, { dimColor: true }, `Diagnose /: proteum diagnose / --port ${routerPort}`),
|
|
@@ -98,7 +96,7 @@ export const renderServerReadyBanner = async ({
|
|
|
98
96
|
|
|
99
97
|
export const renderDevShutdownBanner = async () =>
|
|
100
98
|
renderInk(({ Box, Text }) => {
|
|
101
|
-
const createElement =
|
|
99
|
+
const createElement = CliReact.createElement;
|
|
102
100
|
|
|
103
101
|
return createElement(
|
|
104
102
|
Box,
|
package/cli/presentation/help.ts
CHANGED
|
@@ -100,7 +100,7 @@ export const renderCliOverview = async ({
|
|
|
100
100
|
const status = command.status === 'experimental' ? ' Experimental.' : '';
|
|
101
101
|
|
|
102
102
|
return {
|
|
103
|
-
label: command.name === 'init' ? command.usage : `proteum ${command.name}`,
|
|
103
|
+
label: command.name === 'init' || command.name === 'configure' ? command.usage : `proteum ${command.name}`,
|
|
104
104
|
value: `${command.summary}${status}${initNote}`,
|
|
105
105
|
};
|
|
106
106
|
}),
|
|
@@ -135,7 +135,7 @@ export const renderCliOverview = async ({
|
|
|
135
135
|
indent: ' ',
|
|
136
136
|
nextIndent: ' ',
|
|
137
137
|
}),
|
|
138
|
-
wrapText('
|
|
138
|
+
wrapText('Only the bare `proteum build` and bare `proteum dev` commands print the welcome banner and 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 session UI.', {
|
|
139
139
|
indent: ' ',
|
|
140
140
|
nextIndent: ' ',
|
|
141
141
|
}),
|
package/cli/presentation/ink.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
2
|
|
|
3
3
|
import { importEsm } from '../runtime/importEsm';
|
|
4
4
|
import { getTerminalWidth } from './layout';
|
|
@@ -13,6 +13,9 @@ type TInkRuntime = {
|
|
|
13
13
|
StatusMessage: TInkUiModule['StatusMessage'];
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
// Keep the CLI renderer on the exact React instance Ink resolved for this install shape.
|
|
17
|
+
const CliReact = createRequire(require.resolve('ink'))('react') as typeof import('react');
|
|
18
|
+
|
|
16
19
|
let inkRuntimePromise: Promise<TInkRuntime> | undefined;
|
|
17
20
|
|
|
18
21
|
const loadInkRuntime = () => {
|
|
@@ -41,7 +44,7 @@ export const renderInk = async (
|
|
|
41
44
|
|
|
42
45
|
export const renderTitle = async (title: string, subtitle?: string) =>
|
|
43
46
|
renderInk(({ Box, Text }) => {
|
|
44
|
-
const createElement =
|
|
47
|
+
const createElement = CliReact.createElement;
|
|
45
48
|
|
|
46
49
|
return createElement(
|
|
47
50
|
Box,
|
|
@@ -52,18 +55,20 @@ export const renderTitle = async (title: string, subtitle?: string) =>
|
|
|
52
55
|
});
|
|
53
56
|
|
|
54
57
|
export const renderSection = async (title: string, body: string) => {
|
|
55
|
-
const heading = await renderInk(({ Text }) =>
|
|
58
|
+
const heading = await renderInk(({ Text }) => CliReact.createElement(Text, { bold: true }, title));
|
|
56
59
|
return `${heading}\n${body}`;
|
|
57
60
|
};
|
|
58
61
|
|
|
59
62
|
export const renderStep = async (label: string, message: string) =>
|
|
60
|
-
renderInk(({ Text }) =>
|
|
63
|
+
renderInk(({ Text }) => CliReact.createElement(Text, { color: 'cyan' }, `${label} ${message}`));
|
|
61
64
|
|
|
62
65
|
const renderStatusMessage = async (variant: 'success' | 'warning' | 'error', message: string) =>
|
|
63
|
-
renderInk(({ StatusMessage }) =>
|
|
66
|
+
renderInk(({ StatusMessage }) => CliReact.createElement(StatusMessage, { variant }, message));
|
|
64
67
|
|
|
65
68
|
export const renderSuccess = (message: string) => renderStatusMessage('success', message);
|
|
66
69
|
|
|
67
70
|
export const renderWarning = (message: string) => renderStatusMessage('warning', message);
|
|
68
71
|
|
|
69
72
|
export const renderDanger = (message: string) => renderStatusMessage('error', message);
|
|
73
|
+
|
|
74
|
+
export { CliReact };
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
const React = require('react') as typeof import('react');
|
|
2
|
-
|
|
3
1
|
import { renderRows } from './layout';
|
|
4
|
-
import { renderInk } from './ink';
|
|
2
|
+
import { CliReact, renderInk } from './ink';
|
|
5
3
|
|
|
6
4
|
const ProteumWordmark = [
|
|
7
5
|
String.raw` ____ ____ ___ _____ _____ _ _ __ __`,
|
|
@@ -27,7 +25,7 @@ export const renderWelcomePanel = async ({
|
|
|
27
25
|
tagline: string;
|
|
28
26
|
}) =>
|
|
29
27
|
renderInk(({ Box, Text }) => {
|
|
30
|
-
const createElement =
|
|
28
|
+
const createElement = CliReact.createElement;
|
|
31
29
|
const wordmark = ProteumWordmark.map((line) =>
|
|
32
30
|
createElement(Text, { key: line, bold: true, color: 'blue' }, line),
|
|
33
31
|
);
|
package/cli/runtime/commands.ts
CHANGED
|
@@ -74,11 +74,53 @@ class CreateCommand extends ProteumCommand {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
class ConfigureCommand extends ProteumCommand {
|
|
78
|
+
public static paths = [['configure']];
|
|
79
|
+
|
|
80
|
+
public static usage = buildUsage('configure');
|
|
81
|
+
|
|
82
|
+
public args = Option.Rest();
|
|
83
|
+
|
|
84
|
+
public async execute() {
|
|
85
|
+
const [action = '', ...restArgs] = this.args;
|
|
86
|
+
|
|
87
|
+
assertNoLegacyArgs('configure', restArgs);
|
|
88
|
+
this.setCliArgs({
|
|
89
|
+
action,
|
|
90
|
+
});
|
|
91
|
+
await runCommandModule(() => import('../commands/configure'));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
class MigrateCommand extends ProteumCommand {
|
|
96
|
+
public static paths = [['migrate']];
|
|
97
|
+
|
|
98
|
+
public static usage = buildUsage('migrate');
|
|
99
|
+
|
|
100
|
+
public cwd = Option.String('--cwd', { description: 'Run the migration against another Proteum app root.' });
|
|
101
|
+
public dryRun = Option.Boolean('--dry-run', false, { description: 'Print the rewrite plan without writing files.' });
|
|
102
|
+
public json = Option.Boolean('--json', false, { description: 'Print machine-readable migration output.' });
|
|
103
|
+
public args = Option.Rest();
|
|
104
|
+
|
|
105
|
+
public async execute() {
|
|
106
|
+
const [action = ''] = this.args;
|
|
107
|
+
|
|
108
|
+
this.setCliArgs({
|
|
109
|
+
action,
|
|
110
|
+
workdir: this.cwd ?? '',
|
|
111
|
+
dryRun: this.dryRun,
|
|
112
|
+
json: this.json,
|
|
113
|
+
});
|
|
114
|
+
await runCommandModule(() => import('../commands/migrate'));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
77
118
|
class DevCommand extends ProteumCommand {
|
|
78
119
|
public static paths = [['dev']];
|
|
79
120
|
|
|
80
121
|
public static usage = buildUsage('dev');
|
|
81
122
|
|
|
123
|
+
public cwd = Option.String('--cwd', { description: 'Run the dev command against another Proteum app root.' });
|
|
82
124
|
public json = Option.Boolean('--json', false, { description: 'Print machine-readable dev session output.' });
|
|
83
125
|
public port = Option.String('--port', { description: 'Override the router port.' });
|
|
84
126
|
public cache = Option.Boolean('--cache', true, { description: 'Enable filesystem caching.' });
|
|
@@ -105,6 +147,7 @@ class DevCommand extends ProteumCommand {
|
|
|
105
147
|
action: action || 'start',
|
|
106
148
|
port: this.port ?? '',
|
|
107
149
|
cache: this.cache,
|
|
150
|
+
workdir: this.cwd ?? '',
|
|
108
151
|
json: this.json,
|
|
109
152
|
sessionFile: this.sessionFile ?? '',
|
|
110
153
|
replaceExisting: this.replaceExisting,
|
|
@@ -316,6 +359,30 @@ class ExplainCommand extends ProteumCommand {
|
|
|
316
359
|
}
|
|
317
360
|
}
|
|
318
361
|
|
|
362
|
+
class OrientCommand extends ProteumCommand {
|
|
363
|
+
public static paths = [['orient']];
|
|
364
|
+
|
|
365
|
+
public static usage = buildUsage('orient');
|
|
366
|
+
|
|
367
|
+
public port = Option.String('--port', { description: 'Target an existing dev server on the given port.' });
|
|
368
|
+
public url = Option.String('--url', { description: 'Target an existing dev server at the given base URL.' });
|
|
369
|
+
public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
|
|
370
|
+
public args = Option.Rest();
|
|
371
|
+
|
|
372
|
+
public async execute() {
|
|
373
|
+
const query = this.args.join(' ').trim();
|
|
374
|
+
|
|
375
|
+
this.setCliArgs({
|
|
376
|
+
json: this.json,
|
|
377
|
+
port: this.port ?? '',
|
|
378
|
+
query,
|
|
379
|
+
url: this.url ?? '',
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
await runCommandModule(() => import('../commands/orient'));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
319
386
|
class TraceCommand extends ProteumCommand {
|
|
320
387
|
public static paths = [['trace']];
|
|
321
388
|
|
|
@@ -478,6 +545,17 @@ class VerifyCommand extends ProteumCommand {
|
|
|
478
545
|
public static usage = buildUsage('verify');
|
|
479
546
|
|
|
480
547
|
public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
|
|
548
|
+
public port = Option.String('--port', { description: 'Target an existing dev server on the given port for focused verify actions.' });
|
|
549
|
+
public url = Option.String('--url', { description: 'Target an existing dev server at the given base URL for focused verify actions.' });
|
|
550
|
+
public sessionEmail = Option.String('--session-email', {
|
|
551
|
+
description: 'Mint a dev session before request or browser verification and attach the returned cookie.',
|
|
552
|
+
});
|
|
553
|
+
public sessionRole = Option.String('--session-role', { description: 'Require the dev session user to have this role.' });
|
|
554
|
+
public method = Option.String('--method', { description: 'HTTP method used by request verification.' });
|
|
555
|
+
public dataJson = Option.String('--data-json', { description: 'JSON request body used by request verification.' });
|
|
556
|
+
public strictGlobal = Option.Boolean('--strict-global', false, {
|
|
557
|
+
description: 'Fail focused verification when unrelated pre-existing blocking findings exist.',
|
|
558
|
+
});
|
|
481
559
|
public crosspath = Option.String('--crosspath', { description: 'Override the CrossPath reference app path.' });
|
|
482
560
|
public product = Option.String('--product', { description: 'Override the Unique Domains Product reference app path.' });
|
|
483
561
|
public website = Option.String('--website', { description: 'Override the Unique Domains Website reference app path.' });
|
|
@@ -492,16 +570,25 @@ class VerifyCommand extends ProteumCommand {
|
|
|
492
570
|
public args = Option.Rest();
|
|
493
571
|
|
|
494
572
|
public async execute() {
|
|
495
|
-
const [action = 'framework-change'] = this.args;
|
|
573
|
+
const [action = 'framework-change', ...restArgs] = this.args;
|
|
574
|
+
const target = restArgs.join(' ').trim();
|
|
496
575
|
|
|
497
576
|
this.setCliArgs({
|
|
498
577
|
action,
|
|
499
578
|
crosspath: this.crosspath ?? '',
|
|
500
579
|
crosspathPort: this.crosspathPort ?? '',
|
|
580
|
+
dataJson: this.dataJson ?? '',
|
|
501
581
|
json: this.json,
|
|
582
|
+
method: this.method ?? '',
|
|
583
|
+
port: this.port ?? '',
|
|
502
584
|
product: this.product ?? '',
|
|
503
585
|
productPort: this.productPort ?? '',
|
|
504
586
|
route: this.route ?? '',
|
|
587
|
+
sessionEmail: this.sessionEmail ?? '',
|
|
588
|
+
sessionRole: this.sessionRole ?? '',
|
|
589
|
+
strictGlobal: this.strictGlobal,
|
|
590
|
+
target,
|
|
591
|
+
url: this.url ?? '',
|
|
505
592
|
website: this.website ?? '',
|
|
506
593
|
websitePort: this.websitePort ?? '',
|
|
507
594
|
});
|
|
@@ -513,6 +600,8 @@ class VerifyCommand extends ProteumCommand {
|
|
|
513
600
|
export const registeredCommands = {
|
|
514
601
|
init: InitCommand,
|
|
515
602
|
create: CreateCommand,
|
|
603
|
+
configure: ConfigureCommand,
|
|
604
|
+
migrate: MigrateCommand,
|
|
516
605
|
dev: DevCommand,
|
|
517
606
|
refresh: RefreshCommand,
|
|
518
607
|
build: BuildCommand,
|
|
@@ -522,6 +611,7 @@ export const registeredCommands = {
|
|
|
522
611
|
connect: ConnectCommand,
|
|
523
612
|
doctor: DoctorCommand,
|
|
524
613
|
explain: ExplainCommand,
|
|
614
|
+
orient: OrientCommand,
|
|
525
615
|
diagnose: DiagnoseCommand,
|
|
526
616
|
perf: PerfCommand,
|
|
527
617
|
trace: TraceCommand,
|
|
@@ -542,6 +632,8 @@ export const createCli = (version: string) => {
|
|
|
542
632
|
clipanion.register(Builtins.DefinitionsCommand);
|
|
543
633
|
clipanion.register(InitCommand);
|
|
544
634
|
clipanion.register(CreateCommand);
|
|
635
|
+
clipanion.register(ConfigureCommand);
|
|
636
|
+
clipanion.register(MigrateCommand);
|
|
545
637
|
clipanion.register(DevCommand);
|
|
546
638
|
clipanion.register(RefreshCommand);
|
|
547
639
|
clipanion.register(BuildCommand);
|
|
@@ -551,6 +643,7 @@ export const createCli = (version: string) => {
|
|
|
551
643
|
clipanion.register(ConnectCommand);
|
|
552
644
|
clipanion.register(DoctorCommand);
|
|
553
645
|
clipanion.register(ExplainCommand);
|
|
646
|
+
clipanion.register(OrientCommand);
|
|
554
647
|
clipanion.register(DiagnoseCommand);
|
|
555
648
|
clipanion.register(PerfCommand);
|
|
556
649
|
clipanion.register(TraceCommand);
|
package/cli/scaffold/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { UsageError } from 'clipanion';
|
|
|
5
5
|
|
|
6
6
|
import cli from '..';
|
|
7
7
|
import { loadApplicationIdentityConfig } from '../../common/applicationConfigLoader';
|
|
8
|
-
import {
|
|
8
|
+
import { renderProjectInstructionGitignoreBlock } from '../utils/agents';
|
|
9
9
|
import { runProcess } from '../utils/runProcess';
|
|
10
10
|
import {
|
|
11
11
|
createClientTsconfigTemplate,
|
|
@@ -705,7 +705,6 @@ export const runInitScaffold = async () => {
|
|
|
705
705
|
if (!result.dryRun) {
|
|
706
706
|
fs.ensureDirSync(path.join(appRoot, 'client'));
|
|
707
707
|
fs.ensureDirSync(path.join(appRoot, 'server'));
|
|
708
|
-
ensureProjectAgentSymlinks({ appRoot, coreRoot: cli.paths.core.root });
|
|
709
708
|
}
|
|
710
709
|
|
|
711
710
|
if (config.install) {
|
|
@@ -728,6 +727,7 @@ export const runInitScaffold = async () => {
|
|
|
728
727
|
? 'Run `npm run dev` in the new app directory.'
|
|
729
728
|
: 'Run `npm install`, then `npm run dev` in the new app directory.',
|
|
730
729
|
);
|
|
730
|
+
result.nextSteps.push('Run `proteum configure agents` when you want Proteum-managed instruction symlinks.');
|
|
731
731
|
result.nextSteps.push('Use `proteum create page|controller|command|route|service ...` to add app artifacts.');
|
|
732
732
|
|
|
733
733
|
printResult(result, createInitSummary(result, config));
|
|
@@ -26,9 +26,11 @@ export const createPageTemplate = ({
|
|
|
26
26
|
|
|
27
27
|
Router.page(
|
|
28
28
|
${JSON.stringify(routePath)},
|
|
29
|
+
{
|
|
30
|
+
auth: false,
|
|
31
|
+
layout: false,
|
|
32
|
+
},
|
|
29
33
|
() => ({
|
|
30
|
-
_auth: false,
|
|
31
|
-
_layout: false,
|
|
32
34
|
heading: ${JSON.stringify(heading)},
|
|
33
35
|
message: ${JSON.stringify(message)},
|
|
34
36
|
}),
|