proteum 2.2.7 → 2.2.9

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 (43) hide show
  1. package/AGENTS.md +2 -1
  2. package/README.md +1 -1
  3. package/agents/project/AGENTS.md +4 -5
  4. package/agents/project/CODING_STYLE.md +5 -1
  5. package/agents/project/client/AGENTS.md +2 -0
  6. package/agents/project/diagnostics.md +2 -3
  7. package/agents/project/root/AGENTS.md +4 -5
  8. package/agents/project/tests/AGENTS.md +0 -1
  9. package/cli/commands/check.ts +21 -3
  10. package/cli/commands/configure.ts +1 -0
  11. package/cli/compiler/artifacts/controllers.ts +30 -4
  12. package/cli/compiler/artifacts/services.ts +67 -29
  13. package/cli/presentation/commands.ts +2 -2
  14. package/cli/scaffold/templates.ts +2 -3
  15. package/cli/utils/agents.ts +114 -4
  16. package/client/dev/profiler/ApexChart.tsx +4 -3
  17. package/common/dev/inspection.ts +16 -3
  18. package/common/dev/serverHotReload.ts +26 -25
  19. package/eslint.js +220 -0
  20. package/package.json +1 -1
  21. package/server/app/commands.ts +11 -16
  22. package/server/app/commandsManager.ts +5 -1
  23. package/server/app/controller/index.ts +68 -16
  24. package/server/app/devCommands.ts +3 -3
  25. package/server/app/devDiagnostics.ts +2 -2
  26. package/server/app/index.ts +19 -8
  27. package/server/app/service/container.ts +22 -19
  28. package/server/app/service/index.ts +33 -13
  29. package/server/app.tsconfig.json +0 -1
  30. package/server/services/auth/index.ts +12 -6
  31. package/server/services/auth/router/index.ts +12 -14
  32. package/server/services/auth/router/request.ts +34 -13
  33. package/server/services/disks/driver.ts +1 -1
  34. package/server/services/disks/index.ts +11 -8
  35. package/server/services/email/index.ts +1 -1
  36. package/server/services/prisma/Facet.ts +6 -5
  37. package/server/services/router/index.ts +8 -7
  38. package/server/services/router/request/validation/zod.ts +2 -0
  39. package/server/services/router/response/index.ts +9 -9
  40. package/server/services/router/service.ts +12 -8
  41. package/tests/agents-utils.test.cjs +55 -0
  42. package/tests/eslint-rules.test.cjs +110 -0
  43. package/types/global/vendors.d.ts +70 -0
@@ -159,12 +159,67 @@ test('monorepo configure writes root and app instruction files', () => {
159
159
  fs.mkdirSync(path.join(monorepoRoot, '.git'));
160
160
  fs.mkdirSync(path.join(appRoot, 'client'), { recursive: true });
161
161
 
162
+ configureProjectAgentInstructions({ appRoot, coreRoot });
163
+
162
164
  const result = configureProjectAgentInstructions({ appRoot, coreRoot, monorepoRoot });
163
165
 
164
166
  assert.equal(result.mode, 'monorepo');
165
167
  assert.equal(resolveProjectAgentMonorepoRoot(appRoot), fs.realpathSync(monorepoRoot));
166
168
  assert.match(fs.readFileSync(path.join(monorepoRoot, 'AGENTS.md'), 'utf8'), /## Source: AGENTS\.md/);
169
+ assert.match(fs.readFileSync(path.join(monorepoRoot, 'CODING_STYLE.md'), 'utf8'), /## Source: CODING_STYLE\.md/);
170
+ assert.match(fs.readFileSync(path.join(monorepoRoot, 'diagnostics.md'), 'utf8'), /## Source: AGENTS\.md/);
171
+ assert.match(fs.readFileSync(path.join(monorepoRoot, 'optimizations.md'), 'utf8'), /## Source: AGENTS\.md/);
167
172
  assert.match(fs.readFileSync(path.join(appRoot, 'AGENTS.md'), 'utf8'), /## Source: client\/AGENTS\.md/);
173
+ assert.equal(fs.existsSync(path.join(appRoot, 'CODING_STYLE.md')), false);
174
+ assert.equal(fs.existsSync(path.join(appRoot, 'diagnostics.md')), false);
175
+ assert.equal(fs.existsSync(path.join(appRoot, 'optimizations.md')), false);
176
+ assert.equal(result.removed.some((entry) => entry.endsWith('/apps/product/CODING_STYLE.md')), true);
177
+ });
178
+
179
+ test('monorepo configure preserves local app-root documents', () => {
180
+ const coreRoot = createCoreFixture();
181
+ const monorepoRoot = makeTempRoot();
182
+ const appRoot = path.join(monorepoRoot, 'apps', 'product');
183
+ const localCodingStylePath = path.join(appRoot, 'CODING_STYLE.md');
184
+
185
+ fs.mkdirSync(path.join(monorepoRoot, '.git'));
186
+ writeFile(localCodingStylePath, '# Local Coding Style\n\n- Keep this app-local override.\n');
187
+
188
+ const result = configureProjectAgentInstructions({ appRoot, coreRoot, monorepoRoot });
189
+
190
+ assert.match(fs.readFileSync(path.join(monorepoRoot, 'CODING_STYLE.md'), 'utf8'), /## Source: CODING_STYLE\.md/);
191
+ assert.match(fs.readFileSync(localCodingStylePath, 'utf8'), /Keep this app-local override/);
192
+ assert.equal(result.removed.some((entry) => entry.endsWith('/apps/product/CODING_STYLE.md')), false);
193
+ });
194
+
195
+ test('monorepo configure strips retired managed sections from local app-root documents', () => {
196
+ const coreRoot = createCoreFixture();
197
+ const monorepoRoot = makeTempRoot();
198
+ const appRoot = path.join(monorepoRoot, 'apps', 'product');
199
+ const localCodingStylePath = path.join(appRoot, 'CODING_STYLE.md');
200
+
201
+ fs.mkdirSync(path.join(monorepoRoot, '.git'));
202
+ fs.mkdirSync(appRoot, { recursive: true });
203
+ configureProjectAgentInstructions({ appRoot, coreRoot });
204
+
205
+ const managedContent = fs.readFileSync(localCodingStylePath, 'utf8');
206
+ writeFile(
207
+ localCodingStylePath,
208
+ [
209
+ '# Local Coding Style',
210
+ '',
211
+ '- Keep this app-local override.',
212
+ '',
213
+ managedContent,
214
+ ].join('\n'),
215
+ );
216
+
217
+ const result = configureProjectAgentInstructions({ appRoot, coreRoot, monorepoRoot });
218
+ const retainedContent = fs.readFileSync(localCodingStylePath, 'utf8');
219
+
220
+ assert.match(retainedContent, /Keep this app-local override/);
221
+ assert.doesNotMatch(retainedContent, /proteum-instructions:start/);
222
+ assert.equal(result.updated.some((entry) => entry.endsWith('/apps/product/CODING_STYLE.md')), true);
168
223
  });
169
224
 
170
225
  test('configure migrates legacy managed symlinks to embedded files', () => {
@@ -0,0 +1,110 @@
1
+ const assert = require('node:assert/strict');
2
+ const test = require('node:test');
3
+ const { Linter } = require('eslint');
4
+
5
+ const { createProteumEslintConfig } = require('../eslint.js');
6
+
7
+ const lint = (code) => {
8
+ const linter = new Linter({ configType: 'flat' });
9
+ return linter.verify(code, createProteumEslintConfig(), {
10
+ filename: 'client/example.tsx',
11
+ });
12
+ };
13
+
14
+ const swallowedErrorRuleId = 'proteum/no-swallowed-caught-error';
15
+
16
+ test('proteum lint rejects empty catch blocks', () => {
17
+ const messages = lint(`
18
+ export const run = () => {
19
+ try {
20
+ risky();
21
+ } catch {
22
+ return null;
23
+ }
24
+ };
25
+ `);
26
+
27
+ assert.equal(messages.some((message) => message.ruleId === swallowedErrorRuleId), true);
28
+ });
29
+
30
+ test('proteum lint rejects promise catches that discard the error', () => {
31
+ const messages = lint(`
32
+ export const run = () => {
33
+ api.load().catch(() => toast.error('Could not load'));
34
+ };
35
+ `);
36
+
37
+ assert.equal(messages.some((message) => message.ruleId === swallowedErrorRuleId), true);
38
+ });
39
+
40
+ test('proteum lint rejects generic catch feedback that drops original error details', () => {
41
+ const messages = lint(`
42
+ export const run = async () => {
43
+ try {
44
+ await Investor.api.getDashboard();
45
+ } catch (error) {
46
+ toast.error('Could not load API dashboard');
47
+ }
48
+ };
49
+ `);
50
+
51
+ assert.equal(messages.some((message) => message.ruleId === swallowedErrorRuleId), true);
52
+ });
53
+
54
+ test('proteum lint allows rethrowing the caught error', () => {
55
+ const messages = lint(`
56
+ export const run = async () => {
57
+ try {
58
+ await Investor.api.getDashboard();
59
+ } catch (error) {
60
+ toast.error('Could not load API dashboard');
61
+ throw error;
62
+ }
63
+ };
64
+ `);
65
+
66
+ assert.equal(messages.filter((message) => message.ruleId === swallowedErrorRuleId).length, 0);
67
+ });
68
+
69
+ test('proteum lint allows surfacing original error details', () => {
70
+ const messages = lint(`
71
+ export const run = async () => {
72
+ try {
73
+ await Investor.api.getDashboard();
74
+ } catch (error) {
75
+ toast.error('Could not load API dashboard', {
76
+ description: error instanceof Error ? error.message : String(error),
77
+ });
78
+ }
79
+ };
80
+ `);
81
+
82
+ assert.equal(messages.filter((message) => message.ruleId === swallowedErrorRuleId).length, 0);
83
+ });
84
+
85
+ test('proteum lint allows surfacing a message derived from the caught error', () => {
86
+ const messages = lint(`
87
+ export const run = async () => {
88
+ try {
89
+ await Investor.api.getDashboard();
90
+ } catch (error) {
91
+ const message = error instanceof Error ? error.message : String(error);
92
+ setError(message);
93
+ }
94
+ };
95
+ `);
96
+
97
+ assert.equal(messages.filter((message) => message.ruleId === swallowedErrorRuleId).length, 0);
98
+ });
99
+
100
+ test('proteum lint allows routing promise failures to app error handling', () => {
101
+ const messages = lint(`
102
+ export const run = () => {
103
+ Investor.api.ensureApiKey().catch((error) => {
104
+ Router.app.handleError(error);
105
+ });
106
+ };
107
+ `);
108
+
109
+ assert.equal(messages.filter((message) => message.ruleId === swallowedErrorRuleId).length, 0);
110
+ });
@@ -68,6 +68,76 @@ declare module 'morgan' {
68
68
  export default morgan;
69
69
  }
70
70
 
71
+ declare module 'object-hash' {
72
+ export type ObjectHashOptions = {
73
+ unorderedArrays?: boolean;
74
+ unorderedObjects?: boolean;
75
+ };
76
+ export type ObjectHashValue =
77
+ | string
78
+ | number
79
+ | boolean
80
+ | null
81
+ | undefined
82
+ | Date
83
+ | ObjectHashValue[]
84
+ | { [key: string]: ObjectHashValue };
85
+
86
+ const objectHash: (value: ObjectHashValue, options?: ObjectHashOptions) => string;
87
+ export default objectHash;
88
+ }
89
+
90
+ declare module 'fs-extra' {
91
+ type FsJsonValue =
92
+ | string
93
+ | number
94
+ | boolean
95
+ | null
96
+ | FsJsonValue[]
97
+ | { [key: string]: FsJsonValue };
98
+ type FsExtraModule = {
99
+ createReadStream: typeof import('fs').createReadStream;
100
+ ensureDirSync(path: import('fs').PathLike): void;
101
+ existsSync: typeof import('fs').existsSync;
102
+ moveSync(source: import('fs').PathLike, destination: import('fs').PathLike, options?: { overwrite?: boolean }): void;
103
+ outputFileSync(
104
+ file: import('fs').PathOrFileDescriptor,
105
+ data: string | NodeJS.ArrayBufferView,
106
+ options?: import('fs').WriteFileOptions | { encoding?: string },
107
+ ): void;
108
+ readdir: typeof import('fs/promises').readdir;
109
+ readdirSync: typeof import('fs').readdirSync;
110
+ readFile: typeof import('fs/promises').readFile;
111
+ readFileSync: typeof import('fs').readFileSync;
112
+ readJSONSync<TValue = FsJsonValue>(path: import('fs').PathLike): TValue;
113
+ readJsonSync<TValue = FsJsonValue>(path: import('fs').PathLike): TValue;
114
+ removeSync(path: import('fs').PathLike): void;
115
+ statSync: typeof import('fs').statSync;
116
+ writeJSONSync(path: import('fs').PathLike, data: FsJsonValue | object, options?: Record<string, unknown>): void;
117
+ };
118
+
119
+ const fsExtra: FsExtraModule;
120
+ export default fsExtra;
121
+ export const createReadStream: FsExtraModule['createReadStream'];
122
+ export const ensureDirSync: FsExtraModule['ensureDirSync'];
123
+ export const existsSync: FsExtraModule['existsSync'];
124
+ export const moveSync: FsExtraModule['moveSync'];
125
+ export const outputFileSync: FsExtraModule['outputFileSync'];
126
+ export const readdir: typeof import('fs/promises').readdir;
127
+ export const readdirSync: FsExtraModule['readdirSync'];
128
+ export const readFile: typeof import('fs/promises').readFile;
129
+ export const readFileSync: FsExtraModule['readFileSync'];
130
+ export const readJSONSync: FsExtraModule['readJSONSync'];
131
+ export const readJsonSync: FsExtraModule['readJsonSync'];
132
+ export const removeSync: FsExtraModule['removeSync'];
133
+ export const statSync: FsExtraModule['statSync'];
134
+ export const writeJSONSync: FsExtraModule['writeJSONSync'];
135
+ }
136
+
137
+ declare module 'jstoxml' {
138
+ export const toXML: (value: Record<string, unknown>, options?: Record<string, unknown>) => string;
139
+ }
140
+
71
141
  declare module 'stopword' {
72
142
  export const eng: string[];
73
143
  export function removeStopwords(words: string[], stopwords?: string[]): string[];