proteum 2.5.8 → 2.5.10

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.
@@ -4,7 +4,13 @@ import { spawn } from 'child_process';
4
4
  import { UsageError } from 'clipanion';
5
5
 
6
6
  import cli from '..';
7
- import type { TDevSessionErrorResponse, TDevSessionStartResponse } from '../../common/dev/session';
7
+ import {
8
+ buildDevSessionLoginUrl,
9
+ devSessionStartPath,
10
+ normalizeDevSessionRedirectPath,
11
+ type TDevSessionErrorResponse,
12
+ type TDevSessionStartResponse,
13
+ } from '../../common/dev/session';
8
14
 
9
15
  const localSessionResultMarker = '__PROTEUM_SESSION_RESULT__';
10
16
 
@@ -13,6 +19,7 @@ type TResolvedSessionOutput = {
13
19
  user: TDevSessionStartResponse['user'];
14
20
  session: TDevSessionStartResponse['session'];
15
21
  browserCookie: string;
22
+ browserLoginUrl: string;
16
23
  curlCookieHeader: string;
17
24
  playwright: {
18
25
  cookies: Array<{
@@ -28,6 +35,13 @@ type TResolvedSessionOutput = {
28
35
  };
29
36
 
30
37
  const normalizeBaseUrl = (value: string) => value.replace(/\/+$/, '');
38
+ const normalizeRedirectPath = (value: string): string => {
39
+ try {
40
+ return normalizeDevSessionRedirectPath(value);
41
+ } catch (error) {
42
+ throw new UsageError(error instanceof Error ? error.message : String(error));
43
+ }
44
+ };
31
45
 
32
46
  const getRouterPortFromManifest = () => {
33
47
  const manifestFilepath = path.join(cli.args.workdir as string, '.proteum', 'manifest.json');
@@ -82,7 +96,7 @@ const requestSession = async (email: string, role: string) => {
82
96
 
83
97
  for (const baseUrl of getRouterBaseUrls()) {
84
98
  try {
85
- const response = await got(`${baseUrl}/__proteum/session/start`, {
99
+ const response = await got(`${baseUrl}${devSessionStartPath}`, {
86
100
  method: 'POST',
87
101
  json: role ? { email, role } : { email },
88
102
  responseType: 'json',
@@ -92,7 +106,7 @@ const requestSession = async (email: string, role: string) => {
92
106
 
93
107
  if (response.statusCode >= 400) {
94
108
  if (response.statusCode === 404 && !hasStructuredSessionError(response.body as TDevSessionErrorResponse | object | string | undefined)) {
95
- attempts.push(`${baseUrl}/__proteum/session/start: returned 404`);
109
+ attempts.push(`${baseUrl}${devSessionStartPath}: returned 404`);
96
110
  continue;
97
111
  }
98
112
 
@@ -109,7 +123,7 @@ const requestSession = async (email: string, role: string) => {
109
123
  if (error instanceof UsageError) throw error;
110
124
 
111
125
  const message = error instanceof Error ? error.message : String(error);
112
- attempts.push(`${baseUrl}/__proteum/session/start: ${message}`);
126
+ attempts.push(`${baseUrl}${devSessionStartPath}: ${message}`);
113
127
  }
114
128
  }
115
129
 
@@ -124,9 +138,13 @@ const requestSession = async (email: string, role: string) => {
124
138
 
125
139
  const buildSessionOutput = ({
126
140
  baseUrl,
141
+ redirect,
142
+ role,
127
143
  response,
128
144
  }: {
129
145
  baseUrl: string;
146
+ redirect: string;
147
+ role: string;
130
148
  response: TDevSessionStartResponse;
131
149
  }): TResolvedSessionOutput => {
132
150
  const expires = Math.floor(Date.parse(response.session.expiresAt) / 1000);
@@ -137,6 +155,12 @@ const buildSessionOutput = ({
137
155
  user: response.user,
138
156
  session: response.session,
139
157
  browserCookie: `${response.session.cookieName}=${response.session.token}; Path=/`,
158
+ browserLoginUrl: buildDevSessionLoginUrl({
159
+ baseUrl,
160
+ email: response.user.email,
161
+ redirect,
162
+ role,
163
+ }),
140
164
  curlCookieHeader: `Cookie: ${response.session.cookieName}=${response.session.token}`,
141
165
  playwright: {
142
166
  cookies: [
@@ -170,6 +194,8 @@ const renderSession = (value: TResolvedSessionOutput) =>
170
194
  JSON.stringify(value.playwright, null, 2),
171
195
  'Browser Cookie',
172
196
  value.browserCookie,
197
+ 'Browser Login URL',
198
+ value.browserLoginUrl,
173
199
  ].join('\n');
174
200
 
175
201
  const runLocalSession = async (email: string, role: string) => {
@@ -232,6 +258,7 @@ const runLocalSession = async (email: string, role: string) => {
232
258
  export const run = async () => {
233
259
  const email = typeof cli.args.email === 'string' ? cli.args.email.trim() : '';
234
260
  const role = typeof cli.args.role === 'string' ? cli.args.role.trim() : '';
261
+ const redirect = normalizeRedirectPath(typeof cli.args.redirect === 'string' ? cli.args.redirect : '/');
235
262
  const shouldPrintJson = cli.args.json === true;
236
263
  const shouldUseRemoteServer =
237
264
  (typeof cli.args.port === 'string' && cli.args.port.length > 0) ||
@@ -242,7 +269,11 @@ export const run = async () => {
242
269
  }
243
270
 
244
271
  const resolved = buildSessionOutput(
245
- shouldUseRemoteServer ? await requestSession(email, role) : await runLocalSession(email, role),
272
+ {
273
+ ...(shouldUseRemoteServer ? await requestSession(email, role) : await runLocalSession(email, role)),
274
+ redirect,
275
+ role,
276
+ },
246
277
  );
247
278
 
248
279
  if (shouldPrintJson) {
@@ -1149,7 +1149,12 @@ const runChangedVerify = async () => {
1149
1149
  code: 'changed/check-failed',
1150
1150
  message: `Verification check "${execution.checkId}" failed with exit code ${execution.exitCode ?? 'unknown'}.`,
1151
1151
  source: 'changed',
1152
- details: [`command=${execution.command}`, `cwd=${execution.cwd}`, `durationMs=${execution.durationMs}`],
1152
+ details: [
1153
+ `command=${execution.command}`,
1154
+ `cwd=${execution.cwd}`,
1155
+ `durationMs=${execution.durationMs}`,
1156
+ 'fix=Fix the failing surface and re-run npx proteum verify changed; broader gates only per the root AGENTS.md Verification Policy.',
1157
+ ],
1153
1158
  }));
1154
1159
 
1155
1160
  return finalizeResult({
@@ -12,6 +12,7 @@ import { rspack, type Configuration, type Module } from '@rspack/core';
12
12
  import createCommonConfig, { TCompileMode, TCompileOutputTarget, regex } from '../common';
13
13
  import { createClientBundleAnalysisPlugins } from '../common/bundleAnalysis';
14
14
  import { toRspackAliases } from '../common/rspackAliases';
15
+ import { resolveUiSingletonAliases } from '../common/uiSingletons';
15
16
  import identityAssets from './identite';
16
17
  import cli from '../..';
17
18
  import { logVerbose } from '../../runtime/verbose';
@@ -35,7 +36,9 @@ const getFrameworkSourceRoot = () => {
35
36
  return activeCoreRoot;
36
37
  };
37
38
 
38
- const resolveFromAppOrCore = (_app: App, request: string) => cli.paths.resolveRequest(request);
39
+ const resolveFromAppOrCore = (request: string) => cli.paths.resolveRequest(request, { preferApp: true });
40
+ const resolvePackageRootFromAppOrCore = (packageName: string) =>
41
+ cli.paths.resolvePackageRoot(packageName, { preferApp: true });
39
42
  const rewriteFrameworkAliasTargets = (aliases: Record<string, string | string[]>) => {
40
43
  const visibleFrameworkRoots = [
41
44
  ...cli.paths.getVisiblePackageInstallRoots('proteum'),
@@ -145,9 +148,13 @@ export default function createCompiler(
145
148
  const rspackAliases = toRspackAliases(resolvedAliases);
146
149
  rspackAliases['proteum'] = frameworkSourceRoot;
147
150
  rspackAliases['@/client/router$'] = frameworkSourceRoot + '/client/router.ts';
148
- rspackAliases['preact/jsx-runtime$'] = resolveFromAppOrCore(app, 'preact/jsx-runtime');
149
- rspackAliases['react/jsx-runtime$'] = resolveFromAppOrCore(app, 'preact/jsx-runtime');
150
- rspackAliases['react/jsx-dev-runtime$'] = resolveFromAppOrCore(app, 'preact/jsx-dev-runtime');
151
+ Object.assign(
152
+ rspackAliases,
153
+ resolveUiSingletonAliases({
154
+ resolvePackageRoot: resolvePackageRootFromAppOrCore,
155
+ resolveRequest: resolveFromAppOrCore,
156
+ }),
157
+ );
151
158
 
152
159
  debug && console.log('client aliases', rspackAliases);
153
160
  const config: Configuration = {
@@ -0,0 +1,76 @@
1
+ type TUiSingletonResolvers = {
2
+ resolvePackageRoot: (packageName: string) => string;
3
+ resolveRequest: (request: string) => string;
4
+ };
5
+
6
+ const uiSingletonPackages = ['preact', 'preact-render-to-string', 'react', 'react-dom'];
7
+
8
+ const uiSingletonPackageAliases: Array<{ alias: string; packageName: string }> = [
9
+ { alias: 'preact', packageName: 'preact' },
10
+ { alias: 'preact-render-to-string', packageName: 'preact-render-to-string' },
11
+ ];
12
+
13
+ const uiSingletonRequestAliases: Array<{ alias: string; request: string }> = [
14
+ { alias: 'preact$', request: 'preact' },
15
+ { alias: 'preact/hooks$', request: 'preact/hooks' },
16
+ { alias: 'preact/compat$', request: 'preact/compat' },
17
+ { alias: 'preact/compat/client$', request: 'preact/compat/client' },
18
+ { alias: 'preact/jsx-runtime$', request: 'preact/jsx-runtime' },
19
+ { alias: 'preact/jsx-dev-runtime$', request: 'preact/jsx-dev-runtime' },
20
+ { alias: 'react$', request: 'preact/compat' },
21
+ { alias: 'react-dom$', request: 'preact/compat' },
22
+ { alias: 'react-dom/client$', request: 'preact/compat/client' },
23
+ { alias: 'react-dom/test-utils$', request: 'preact/test-utils' },
24
+ { alias: 'react/jsx-runtime$', request: 'preact/jsx-runtime' },
25
+ { alias: 'react/jsx-dev-runtime$', request: 'preact/jsx-dev-runtime' },
26
+ { alias: 'preact-render-to-string$', request: 'preact-render-to-string' },
27
+ ];
28
+
29
+ const uiSingletonServerExternalRequests: Array<{ request: string; resolvedRequest: string }> = [
30
+ { request: 'preact', resolvedRequest: 'preact' },
31
+ { request: 'preact/hooks', resolvedRequest: 'preact/hooks' },
32
+ { request: 'preact/compat', resolvedRequest: 'preact/compat' },
33
+ { request: 'preact/compat/client', resolvedRequest: 'preact/compat/client' },
34
+ { request: 'preact/jsx-runtime', resolvedRequest: 'preact/jsx-runtime' },
35
+ { request: 'preact/jsx-dev-runtime', resolvedRequest: 'preact/jsx-dev-runtime' },
36
+ { request: 'preact/test-utils', resolvedRequest: 'preact/test-utils' },
37
+ { request: 'react', resolvedRequest: 'preact/compat' },
38
+ { request: 'react-dom', resolvedRequest: 'preact/compat' },
39
+ { request: 'react-dom/client', resolvedRequest: 'preact/compat/client' },
40
+ { request: 'react-dom/test-utils', resolvedRequest: 'preact/test-utils' },
41
+ { request: 'react/jsx-runtime', resolvedRequest: 'preact/jsx-runtime' },
42
+ { request: 'react/jsx-dev-runtime', resolvedRequest: 'preact/jsx-dev-runtime' },
43
+ ];
44
+
45
+ export const isUiSingletonRequest = (request: string | undefined) =>
46
+ typeof request === 'string' &&
47
+ uiSingletonPackages.some((packageName) => request === packageName || request.startsWith(`${packageName}/`));
48
+
49
+ export const resolveUiSingletonAliases = ({ resolvePackageRoot, resolveRequest }: TUiSingletonResolvers) => ({
50
+ ...Object.fromEntries(
51
+ uiSingletonRequestAliases.map(({ alias, request }) => [
52
+ alias,
53
+ resolveRequest(request),
54
+ ]),
55
+ ),
56
+ ...Object.fromEntries(
57
+ uiSingletonPackageAliases.map(({ alias, packageName }) => [
58
+ alias,
59
+ resolvePackageRoot(packageName),
60
+ ]),
61
+ ),
62
+ });
63
+
64
+ export const resolveUiSingletonServerExternalRequest = (
65
+ request: string | undefined,
66
+ resolveRequest: TUiSingletonResolvers['resolveRequest'],
67
+ ) => {
68
+ if (request === undefined) return undefined;
69
+
70
+ const exactExternalRequest = uiSingletonServerExternalRequests.find((entry) => entry.request === request);
71
+ if (exactExternalRequest) return resolveRequest(exactExternalRequest.resolvedRequest);
72
+
73
+ if (request.startsWith('preact/')) return resolveRequest(request);
74
+
75
+ return undefined;
76
+ };
@@ -0,0 +1,35 @@
1
+ type TResolveRequestOptions = { preferApp: boolean };
2
+
3
+ type TResolveServerExternalRequestOptions = {
4
+ context?: string;
5
+ frameworkRoots: string[];
6
+ request: string;
7
+ resolveRequest: (request: string, options: TResolveRequestOptions) => string;
8
+ };
9
+
10
+ const normalizeModulePath = (value?: string) => (value || '').replace(/\\/g, '/');
11
+
12
+ export const isFrameworkSourceContext = (context: string | undefined, frameworkRoots: string[]) => {
13
+ const normalizedContext = normalizeModulePath(context);
14
+
15
+ return frameworkRoots.some((rootPath) => {
16
+ const normalizedRootPath = normalizeModulePath(rootPath);
17
+
18
+ return normalizedContext === normalizedRootPath || normalizedContext.startsWith(normalizedRootPath + '/');
19
+ });
20
+ };
21
+
22
+ export const resolveServerExternalRequest = ({
23
+ context,
24
+ frameworkRoots,
25
+ request,
26
+ resolveRequest,
27
+ }: TResolveServerExternalRequestOptions) => {
28
+ try {
29
+ return resolveRequest(request, {
30
+ preferApp: !isFrameworkSourceContext(context, frameworkRoots),
31
+ });
32
+ } catch {
33
+ return request;
34
+ }
35
+ };
@@ -10,6 +10,12 @@ import { type Configuration } from '@rspack/core';
10
10
  import cli from '@cli';
11
11
  import createCommonConfig, { TCompileMode, TCompileOutputTarget, regex } from '../common';
12
12
  import { toRspackAliases } from '../common/rspackAliases';
13
+ import {
14
+ isUiSingletonRequest,
15
+ resolveUiSingletonAliases,
16
+ resolveUiSingletonServerExternalRequest,
17
+ } from '../common/uiSingletons';
18
+ import { resolveServerExternalRequest } from './externals';
13
19
 
14
20
  // Type
15
21
  import type { App } from '../../app';
@@ -50,6 +56,9 @@ const getDevGeneratedRuntimeEntries = (app: App) => ({
50
56
  __proteum_dev_routes: [app.paths.server.generated + '/routes.ts'],
51
57
  __proteum_dev_controllers: [app.paths.server.generated + '/controllers.ts'],
52
58
  });
59
+ const resolveFromAppOrCore = (request: string) => cli.paths.resolveRequest(request, { preferApp: true });
60
+ const resolvePackageRootFromAppOrCore = (packageName: string) =>
61
+ cli.paths.resolvePackageRoot(packageName, { preferApp: true });
53
62
  const normalizeModulePath = (value?: string) => (value || '').replace(/\\/g, '/');
54
63
  const getFrameworkSourceRoot = () => {
55
64
  const installedCoreRoot = cli.paths.framework.installedRoot
@@ -119,6 +128,13 @@ export default function createCompiler(
119
128
  const rspackAliases = toRspackAliases(resolvedAliases);
120
129
  rspackAliases['proteum'] = frameworkSourceRoot;
121
130
  rspackAliases['@/client/router$'] = frameworkSourceRoot + '/client/router.ts';
131
+ Object.assign(
132
+ rspackAliases,
133
+ resolveUiSingletonAliases({
134
+ resolvePackageRoot: resolvePackageRootFromAppOrCore,
135
+ resolveRequest: resolveFromAppOrCore,
136
+ }),
137
+ );
122
138
 
123
139
  debug &&
124
140
  console.log(
@@ -158,27 +174,42 @@ export default function createCompiler(
158
174
  './client-manifest.json',
159
175
 
160
176
  // node_modules
161
- function ({ request }, callback) {
177
+ function ({ context, request }, callback) {
178
+ if (request === undefined) return callback();
179
+
180
+ const uiSingletonExternalRequest = resolveUiSingletonServerExternalRequest(request, resolveFromAppOrCore);
181
+ if (uiSingletonExternalRequest !== undefined) {
182
+ return callback(undefined, 'commonjs ' + uiSingletonExternalRequest);
183
+ }
184
+
162
185
  const shouldCompile =
163
- request !== undefined &&
164
186
  // Local files
165
- (request[0] === '.' ||
166
- request[0] === '/' ||
167
- // Aliased modules
168
- app.aliases.server.containsAlias(request) ||
169
- // TODO: proteum.conf: compile: include
170
- app.isTranspileModuleRequest(request) ||
171
- // Compile proteum modules
172
- request.startsWith('proteum') ||
173
- // React-based UI packages must pass through the alias layer on the server,
174
- // otherwise SSR can mix real React packages with the Preact compat runtime.
175
- serverReactCompatCompilePrefixes.some((prefix) => request.startsWith(prefix)));
187
+ request[0] === '.' ||
188
+ request[0] === '/' ||
189
+ // Aliased modules
190
+ app.aliases.server.containsAlias(request) ||
191
+ // TODO: proteum.conf: compile: include
192
+ app.isTranspileModuleRequest(request) ||
193
+ // Compile proteum modules
194
+ request.startsWith('proteum') ||
195
+ // React/Preact singleton packages and React-based UI packages must pass through the alias layer on the server,
196
+ // otherwise SSR can mix real React packages with the Preact compat runtime.
197
+ isUiSingletonRequest(request) ||
198
+ serverReactCompatCompilePrefixes.some((prefix) => request.startsWith(prefix));
176
199
 
177
200
  //console.log('isNodeModule', request, isNodeModule);
178
201
 
179
202
  if (!shouldCompile) {
180
- // Externalize to a commonjs module using the request path
181
- return callback(undefined, 'commonjs ' + request);
203
+ // Resolve server externals from their source owner. Bare runtime requires from
204
+ // the dev output can otherwise hit the framework node_modules symlink first.
205
+ const resolvedRequest = resolveServerExternalRequest({
206
+ context,
207
+ frameworkRoots,
208
+ request,
209
+ resolveRequest: (externalRequest, options) => cli.paths.resolveRequest(externalRequest, options),
210
+ });
211
+
212
+ return callback(undefined, 'commonjs ' + resolvedRequest);
182
213
  }
183
214
 
184
215
  // Continue without externalizing the import
@@ -594,7 +594,7 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
594
594
  name: 'session',
595
595
  category: 'Manifest and contracts',
596
596
  summary: 'Mint a dev-only auth session token and cookie payload for a known user.',
597
- usage: 'proteum session <email> [--role <role>] [--port <port>|--url <baseUrl>] [--json]',
597
+ usage: 'proteum session <email> [--role <role>] [--redirect <path>] [--port <port>|--url <baseUrl>] [--json]',
598
598
  bestFor:
599
599
  'Starting browser or API automation from an authenticated state without driving the login UI, while still using the app-configured auth service.',
600
600
  examples: [
@@ -606,11 +606,16 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
606
606
  description: 'Mint a GOD session for unique.domains and print machine-readable cookie data',
607
607
  command: 'proteum session god@example.com --role GOD --json',
608
608
  },
609
+ {
610
+ description: 'Print a browser login URL that sets the cookie and opens a protected page',
611
+ command: 'proteum session admin@example.com --port 3101 --redirect /admin --json',
612
+ },
609
613
  ],
610
614
  notes: [
611
615
  'Sessions are available only in dev mode and use the auth service registered on the current app router.',
612
616
  'You must provide the target user email explicitly; Proteum does not guess your admin account universally across apps.',
613
617
  'The command returns a token plus Playwright-ready cookie JSON so agents can inject the session into a browser context directly.',
618
+ 'The command also returns a browser login URL that works on localhost dev servers, sets the same session cookie, and redirects to a local path.',
614
619
  'Without `--port` or `--url`, Proteum refreshes generated artifacts, builds the dev output, starts a temporary local dev server, creates the session, prints the payload, and exits.',
615
620
  ],
616
621
  status: 'experimental',
@@ -617,6 +617,7 @@ class SessionCommand extends ProteumCommand {
617
617
  public role = Option.String('--role', { description: 'Require the resolved user to have the given role.' });
618
618
  public port = Option.String('--port', { description: 'Target an existing dev server on the given port.' });
619
619
  public url = Option.String('--url', { description: 'Target an existing dev server at the given base URL.' });
620
+ public redirect = Option.String('--redirect', { description: 'Local path used by the browser login URL.' });
620
621
  public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
621
622
  public args = Option.Rest();
622
623
 
@@ -628,6 +629,7 @@ class SessionCommand extends ProteumCommand {
628
629
  role: this.role ?? '',
629
630
  port: this.port ?? '',
630
631
  url: this.url ?? '',
632
+ redirect: this.redirect ?? '',
631
633
  json: this.json,
632
634
  });
633
635
 
@@ -556,6 +556,9 @@ export const runCreateScaffold = async () => {
556
556
 
557
557
  result.notes.push(...plan.notes);
558
558
  result.nextSteps.push(...plan.nextSteps);
559
+ result.nextSteps.push(
560
+ 'Adapt the generated code to the real feature and record non-obvious decisions as why-comments per `CODING_STYLE.md` (`Decision and context comments`).',
561
+ );
559
562
  printResult(result);
560
563
  };
561
564
 
@@ -22,7 +22,15 @@ export const createPageTemplate = ({
22
22
  routePath: string;
23
23
  heading: string;
24
24
  message: string;
25
- }) => `import { definePageRoute } from '@common/router/definitions';
25
+ }) => `/*----------------------------------
26
+ - DEPENDANCES
27
+ ----------------------------------*/
28
+
29
+ import { definePageRoute } from '@common/router/definitions';
30
+
31
+ /*----------------------------------
32
+ - PAGE
33
+ ----------------------------------*/
26
34
 
27
35
  export default definePageRoute({
28
36
  path: ${JSON.stringify(routePath)},
@@ -53,7 +61,15 @@ export const createControllerTemplate = ({
53
61
  appIdentifier: string;
54
62
  className: string;
55
63
  methodName: string;
56
- }) => `import { defineAction, defineController } from '@generated/server/controller';
64
+ }) => `/*----------------------------------
65
+ - DEPENDANCES
66
+ ----------------------------------*/
67
+
68
+ import { defineAction, defineController } from '@generated/server/controller';
69
+
70
+ /*----------------------------------
71
+ - CONTROLEUR
72
+ ----------------------------------*/
57
73
 
58
74
  export default defineController({
59
75
  actions: {
@@ -74,11 +90,23 @@ export const createCommandTemplate = ({
74
90
  }: {
75
91
  className: string;
76
92
  methodName: string;
77
- }) => `import { Commands } from '@server/app/commands';
93
+ }) => `/*----------------------------------
94
+ - DEPENDANCES
95
+ ----------------------------------*/
96
+
97
+ import { Commands } from '@server/app/commands';
78
98
  import type AppApplication from '@/server/index';
79
99
 
100
+ /*----------------------------------
101
+ - TYPES
102
+ ----------------------------------*/
103
+
80
104
  type App = InstanceType<typeof AppApplication>;
81
105
 
106
+ /*----------------------------------
107
+ - COMMANDS
108
+ ----------------------------------*/
109
+
82
110
  export default class ${className} extends Commands<App> {
83
111
  public async ${methodName}() {
84
112
  return {
@@ -95,7 +123,15 @@ export const createRouteTemplate = ({
95
123
  }: {
96
124
  httpMethod: string;
97
125
  routePath: string;
98
- }) => `import { defineServerRoute } from '@common/router/definitions';
126
+ }) => `/*----------------------------------
127
+ - DEPENDANCES
128
+ ----------------------------------*/
129
+
130
+ import { defineServerRoute } from '@common/router/definitions';
131
+
132
+ /*----------------------------------
133
+ - ROUTES
134
+ ----------------------------------*/
99
135
 
100
136
  export default defineServerRoute({
101
137
  method: ${JSON.stringify(httpMethod.toUpperCase())},
@@ -115,12 +151,24 @@ export const createServiceTemplate = ({
115
151
  }: {
116
152
  appIdentifier: string;
117
153
  className: string;
118
- }) => `import Service from '@server/app/service';
154
+ }) => `/*----------------------------------
155
+ - DEPENDANCES
156
+ ----------------------------------*/
157
+
158
+ import Service from '@server/app/service';
159
+
160
+ /*----------------------------------
161
+ - TYPES
162
+ ----------------------------------*/
119
163
 
120
164
  export type Config = {
121
165
  debug?: boolean;
122
166
  };
123
167
 
168
+ /*----------------------------------
169
+ - SERVICE
170
+ ----------------------------------*/
171
+
124
172
  export default class ${className} extends Service<Config, {}, ${appIdentifier}, ${appIdentifier}> {
125
173
  public async health() {
126
174
  return {
@@ -138,9 +186,17 @@ export const createServiceConfigTemplate = ({
138
186
  configExportName: string;
139
187
  serviceImportPath: string;
140
188
  serviceImportName: string;
141
- }) => `import { Services } from '@server/app';
189
+ }) => `/*----------------------------------
190
+ - DEPENDANCES
191
+ ----------------------------------*/
192
+
193
+ import { Services } from '@server/app';
142
194
  import ${serviceImportName} from ${JSON.stringify(serviceImportPath)};
143
195
 
196
+ /*----------------------------------
197
+ - CONFIG
198
+ ----------------------------------*/
199
+
144
200
  export const ${configExportName} = Services.config(${serviceImportName}, {});
145
201
  `;
146
202
 
@@ -1053,11 +1053,11 @@ function renderEmbeddedProjectInstructions({
1053
1053
  '- Worktree Preflight (`cwd` inside `/.codex/worktrees/`, newly created Proteum worktree, or before editing in a Codex worktree): read Root contract fallback, run `npx proteum worktree init --source <source-app-root>` when the bootstrap marker is missing, run `npx proteum worktree init --source <source-app-root> --refresh` when Proteum reports stale bootstrap state, use `--skip-deps --reason "..."` only for intentional dependency skips, then run `npx proteum runtime status`; for runtime-visible work start or reuse one tracked `npx proteum dev` session using the Task Lifecycle launch workflow.',
1054
1054
  '- Git lifecycle (`commit`, `and commit`, `stage`, `push`, `PR`, pull request): read Root contract fallback before any git write.',
1055
1055
  '- Before git writes after a bug fix, behavior change, decision change, or docs-relevant production change: read `DOCUMENTATION.md` and verify required docs, fix notes, or ADRs were updated or explicitly skipped with a reason.',
1056
- '- Before finishing production code changes: read Root contract fallback, `DOCUMENTATION.md`, `CODING_STYLE.md`, `tests/AGENTS.md`, and any touched area `AGENTS.md`.',
1056
+ '- Before finishing production code changes: read Root contract fallback, `DOCUMENTATION.md`, `CODING_STYLE.md`, `tests/AGENTS.md`, and any touched area `AGENTS.md`. Run the `CODING_STYLE.md` self-check on the final diff; a non-obvious decision, workaround, or bug fix without a why-comment is a defect to fix before finishing.',
1057
1057
  '- Runtime-visible, request-time, router, SSR, browser, or controller behavior: read Root contract fallback and `diagnostics.md` for verification routing.',
1058
1058
  '- Bug fixes, regressions, incidents, broken public routes, auth/OAuth failures, integration failures, or production behavior fixes: read `DOCUMENTATION.md` before editing and update the relevant fix/regression docs when required.',
1059
1059
  '- Non-trivial feature, product, business-rule, UX, copy, or docs changes: read `DOCUMENTATION.md` before editing.',
1060
- '- Implementation edits: read `CODING_STYLE.md` before editing, plus the matching area file from the routing table.',
1060
+ '- Implementation edits: read `CODING_STYLE.md` before editing, plus the matching area file from the routing table. While editing, record non-obvious decisions, workarounds, and constraints as why-comments per its `Decision and context comments` section.',
1061
1061
  '',
1062
1062
  '## Routing Table',
1063
1063
  '',