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.
Files changed (79) hide show
  1. package/.codex/environments/environment.toml +11 -0
  2. package/AGENTS.md +25 -11
  3. package/README.md +19 -9
  4. package/agents/project/AGENTS.md +165 -120
  5. package/agents/project/CODING_STYLE.md +1 -1
  6. package/agents/project/app-root/AGENTS.md +16 -0
  7. package/agents/project/client/AGENTS.md +5 -5
  8. package/agents/project/client/pages/AGENTS.md +13 -13
  9. package/agents/project/diagnostics.md +19 -10
  10. package/agents/project/optimizations.md +5 -6
  11. package/agents/project/root/AGENTS.md +295 -0
  12. package/agents/project/server/routes/AGENTS.md +2 -2
  13. package/agents/project/server/services/AGENTS.md +4 -2
  14. package/agents/project/tests/AGENTS.md +2 -2
  15. package/cli/app/index.ts +31 -7
  16. package/cli/commands/configure.ts +226 -0
  17. package/cli/commands/dev.ts +0 -2
  18. package/cli/commands/diagnose.ts +33 -1
  19. package/cli/commands/explain.ts +1 -1
  20. package/cli/commands/migrate.ts +51 -0
  21. package/cli/commands/orient.ts +169 -0
  22. package/cli/commands/perf.ts +8 -1
  23. package/cli/commands/verify.ts +1003 -49
  24. package/cli/compiler/artifacts/manifest.ts +4 -4
  25. package/cli/compiler/artifacts/routing.ts +2 -2
  26. package/cli/compiler/artifacts/services.ts +12 -3
  27. package/cli/compiler/client/index.ts +65 -19
  28. package/cli/compiler/common/files/style.ts +47 -2
  29. package/cli/compiler/common/generatedRouteModules.ts +31 -38
  30. package/cli/compiler/common/index.ts +10 -0
  31. package/cli/compiler/common/proteumManifest.ts +1 -0
  32. package/cli/compiler/server/index.ts +34 -9
  33. package/cli/context.ts +6 -1
  34. package/cli/index.ts +7 -8
  35. package/cli/migrate/pageContract.ts +516 -0
  36. package/cli/paths.ts +47 -6
  37. package/cli/presentation/commands.ts +100 -10
  38. package/cli/presentation/devSession.ts +4 -6
  39. package/cli/presentation/help.ts +2 -2
  40. package/cli/presentation/ink.ts +10 -5
  41. package/cli/presentation/welcome.ts +2 -4
  42. package/cli/runtime/commands.ts +94 -1
  43. package/cli/scaffold/index.ts +2 -2
  44. package/cli/scaffold/templates.ts +4 -2
  45. package/cli/utils/agents.ts +273 -58
  46. package/client/dev/profiler/index.tsx +3 -2
  47. package/client/router.ts +10 -2
  48. package/client/services/router/index.tsx +6 -22
  49. package/common/dev/connect.ts +20 -4
  50. package/common/dev/console.ts +7 -0
  51. package/common/dev/contractsDoctor.ts +354 -0
  52. package/common/dev/diagnostics.ts +10 -7
  53. package/common/dev/inspection.ts +830 -38
  54. package/common/dev/performance.ts +19 -5
  55. package/common/dev/profiler.ts +1 -0
  56. package/common/dev/proteumManifest.ts +5 -4
  57. package/common/dev/requestTrace.ts +12 -1
  58. package/common/router/contracts.ts +8 -11
  59. package/common/router/index.ts +2 -2
  60. package/common/router/pageData.ts +72 -0
  61. package/common/router/register.ts +10 -46
  62. package/common/router/response/page.ts +28 -16
  63. package/docs/dev-sessions.md +8 -4
  64. package/docs/diagnostics.md +77 -11
  65. package/docs/migrate-from-2.1.3.md +388 -0
  66. package/docs/request-tracing.md +25 -6
  67. package/package.json +6 -1
  68. package/scripts/update-codex-agents.ts +2 -2
  69. package/server/app/container/console/index.ts +11 -1
  70. package/server/app/container/trace/index.ts +117 -0
  71. package/server/app/devDiagnostics.ts +1 -1
  72. package/server/app/index.ts +5 -1
  73. package/server/services/auth/index.ts +9 -0
  74. package/server/services/router/index.ts +64 -14
  75. package/server/services/router/request/api.ts +7 -1
  76. package/server/services/router/response/index.ts +8 -28
  77. package/types/global/vendors.d.ts +12 -0
  78. package/types/vendors.d.ts +12 -0
  79. 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 dev', value: 'Start the compiler, SSR server, and hot reload loop.' },
48
- { label: '2. proteum refresh', value: 'Regenerate .proteum contracts and typings after source or framework changes.' },
49
- { label: '3. proteum check', value: 'Refresh, typecheck, and lint before you commit or push.' },
50
- { label: '4. proteum build --prod', value: 'Produce the production server and client bundles.' },
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: 'Validate framework changes against CrossPath, Unique Domains Product, and Unique Domains Website.',
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
- 'Framework-repo smoke validation when Proteum changes must be exercised against CrossPath and the website -> product connected-project flow before review.',
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 = React.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)} responded to /api/__proteum/connected/ping`,
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 = React.createElement;
99
+ const createElement = CliReact.createElement;
102
100
 
103
101
  return createElement(
104
102
  Box,
@@ -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('Every Proteum CLI invocation prints the welcome banner. `proteum dev` is the only command that clears the interactive terminal before rendering its session UI.', {
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
  }),
@@ -1,4 +1,4 @@
1
- const React = require('react') as typeof import('react');
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 = React.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 }) => React.createElement(Text, { bold: true }, title));
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 }) => React.createElement(Text, { color: 'cyan' }, `${label} ${message}`));
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 }) => React.createElement(StatusMessage, { variant }, message));
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 = React.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
  );
@@ -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);
@@ -5,7 +5,7 @@ import { UsageError } from 'clipanion';
5
5
 
6
6
  import cli from '..';
7
7
  import { loadApplicationIdentityConfig } from '../../common/applicationConfigLoader';
8
- import { ensureProjectAgentSymlinks, renderProjectInstructionGitignoreBlock } from '../utils/agents';
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
  }),