teamshare-bridge 0.3.0 → 0.4.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 (123) hide show
  1. package/dist/bridge/daemon.js +36 -0
  2. package/dist/bridge/daemon.js.map +1 -1
  3. package/dist/bridge/local-server.d.ts +1 -1
  4. package/dist/bridge/spawn.d.ts +2 -0
  5. package/dist/bridge/spawn.js +17 -0
  6. package/dist/bridge/spawn.js.map +1 -1
  7. package/dist/cli/commands/audit.d.ts +1 -0
  8. package/dist/cli/commands/audit.js +75 -0
  9. package/dist/cli/commands/audit.js.map +1 -0
  10. package/dist/cli/commands/build.js +9 -6
  11. package/dist/cli/commands/build.js.map +1 -1
  12. package/dist/cli/commands/doc.js +1 -1
  13. package/dist/cli/commands/doc.js.map +1 -1
  14. package/dist/cli/commands/run.js +3 -2
  15. package/dist/cli/commands/run.js.map +1 -1
  16. package/dist/cli/commands/scaffold.d.ts +1 -0
  17. package/dist/cli/commands/scaffold.js +111 -0
  18. package/dist/cli/commands/scaffold.js.map +1 -0
  19. package/dist/cli/commands/worker.d.ts +2 -0
  20. package/dist/cli/commands/worker.js +110 -0
  21. package/dist/cli/commands/worker.js.map +1 -0
  22. package/dist/cli/index.js +16 -0
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/lib/api.d.ts +22 -3
  25. package/dist/lib/api.js +9 -2
  26. package/dist/lib/api.js.map +1 -1
  27. package/dist/lib/audit/docs.d.ts +5 -0
  28. package/dist/lib/audit/docs.js +52 -0
  29. package/dist/lib/audit/docs.js.map +1 -0
  30. package/dist/lib/audit/errors.d.ts +15 -0
  31. package/dist/lib/audit/errors.js +154 -0
  32. package/dist/lib/audit/errors.js.map +1 -0
  33. package/dist/lib/audit/gates.d.ts +2 -0
  34. package/dist/lib/audit/gates.js +57 -0
  35. package/dist/lib/audit/gates.js.map +1 -0
  36. package/dist/lib/audit/modularity.d.ts +13 -0
  37. package/dist/lib/audit/modularity.js +200 -0
  38. package/dist/lib/audit/modularity.js.map +1 -0
  39. package/dist/lib/audit/quality.d.ts +9 -0
  40. package/dist/lib/audit/quality.js +128 -0
  41. package/dist/lib/audit/quality.js.map +1 -0
  42. package/dist/lib/audit/rbac.d.ts +14 -0
  43. package/dist/lib/audit/rbac.js +139 -0
  44. package/dist/lib/audit/rbac.js.map +1 -0
  45. package/dist/lib/audit/reporter.d.ts +5 -0
  46. package/dist/lib/audit/reporter.js +107 -0
  47. package/dist/lib/audit/reporter.js.map +1 -0
  48. package/dist/lib/audit/runner.d.ts +2 -0
  49. package/dist/lib/audit/runner.js +150 -0
  50. package/dist/lib/audit/runner.js.map +1 -0
  51. package/dist/lib/audit/security.d.ts +9 -0
  52. package/dist/lib/audit/security.js +151 -0
  53. package/dist/lib/audit/security.js.map +1 -0
  54. package/dist/lib/audit/types.d.ts +67 -0
  55. package/dist/lib/audit/types.js +26 -0
  56. package/dist/lib/audit/types.js.map +1 -0
  57. package/dist/lib/audit/ux.d.ts +9 -0
  58. package/dist/lib/audit/ux.js +112 -0
  59. package/dist/lib/audit/ux.js.map +1 -0
  60. package/dist/lib/config.d.ts +1 -1
  61. package/dist/lib/config.js +1 -1
  62. package/dist/lib/llm.js +1 -0
  63. package/dist/lib/llm.js.map +1 -1
  64. package/dist/lib/lock.d.ts +1 -1
  65. package/dist/lib/scaffold/renderer.d.ts +7 -0
  66. package/dist/lib/scaffold/renderer.js +37 -0
  67. package/dist/lib/scaffold/renderer.js.map +1 -0
  68. package/dist/lib/scaffold/structure.d.ts +3 -0
  69. package/dist/lib/scaffold/structure.js +73 -0
  70. package/dist/lib/scaffold/structure.js.map +1 -0
  71. package/dist/lib/scaffold/types.d.ts +34 -0
  72. package/dist/lib/scaffold/types.js +6 -0
  73. package/dist/lib/scaffold/types.js.map +1 -0
  74. package/dist/lib/scaffold/verify.d.ts +9 -0
  75. package/dist/lib/scaffold/verify.js +48 -0
  76. package/dist/lib/scaffold/verify.js.map +1 -0
  77. package/dist/lib/skills.d.ts +2 -2
  78. package/dist/lib/skills.js +2 -1
  79. package/dist/lib/skills.js.map +1 -1
  80. package/package.json +3 -2
  81. package/skills/teamshare-orchestrator-ask/SKILL.md +14 -0
  82. package/skills/teamshare-scaffold/SKILL.md +133 -0
  83. package/templates/backend/.env.example.tpl +13 -0
  84. package/templates/backend/nest-cli.json.tpl +8 -0
  85. package/templates/backend/package.json.tpl +41 -0
  86. package/templates/backend/prisma/schema.prisma.tpl +39 -0
  87. package/templates/backend/src/app.module.ts.tpl +24 -0
  88. package/templates/backend/src/common/filters/all-exceptions.filter.ts.tpl +59 -0
  89. package/templates/backend/src/common/guards/jwt-auth.guard.ts.tpl +27 -0
  90. package/templates/backend/src/common/guards/rbac.guard.ts.tpl +48 -0
  91. package/templates/backend/src/common/interceptors/transform.interceptor.ts.tpl +44 -0
  92. package/templates/backend/src/common/pipes/zod-validation.pipe.ts.tpl +29 -0
  93. package/templates/backend/src/common/swagger/envelope.schemas.ts.tpl +53 -0
  94. package/templates/backend/src/common/swagger/error.schemas.ts.tpl +62 -0
  95. package/templates/backend/src/main.ts.tpl +27 -0
  96. package/templates/backend/src/modules/example/example.controller.ts.tpl +102 -0
  97. package/templates/backend/src/modules/example/example.dto.ts.tpl +14 -0
  98. package/templates/backend/src/modules/example/example.module.ts.tpl +10 -0
  99. package/templates/backend/src/modules/example/example.service.ts.tpl +45 -0
  100. package/templates/backend/tsconfig.json.tpl +26 -0
  101. package/templates/common/.gitignore.tpl +42 -0
  102. package/templates/common/AGENTS.md.tpl +58 -0
  103. package/templates/common/docs/adr/README.md +25 -0
  104. package/templates/common/docs/api-contract.md.tpl +72 -0
  105. package/templates/web/next.config.ts.tpl +7 -0
  106. package/templates/web/package.json.tpl +37 -0
  107. package/templates/web/src/app/globals.css.tpl +48 -0
  108. package/templates/web/src/app/layout.tsx.tpl +25 -0
  109. package/templates/web/src/components/shared/app-button.tsx.tpl +59 -0
  110. package/templates/web/src/components/shared/app-empty-state.tsx.tpl +39 -0
  111. package/templates/web/src/components/shared/app-list-toolbar.tsx.tpl +63 -0
  112. package/templates/web/src/components/shared/app-skeleton.tsx.tpl +14 -0
  113. package/templates/web/src/components/shared/app-table.tsx.tpl +128 -0
  114. package/templates/web/src/components/shared/index.ts.tpl +5 -0
  115. package/templates/web/src/hooks/use-list-state.ts.tpl +72 -0
  116. package/templates/web/src/hooks/use-url-tab.ts.tpl +25 -0
  117. package/templates/web/src/lib/api/client.ts.tpl +123 -0
  118. package/templates/web/src/lib/providers.tsx.tpl +35 -0
  119. package/templates/web/src/lib/query-keys.ts.tpl +21 -0
  120. package/templates/web/src/lib/utils.ts.tpl +7 -0
  121. package/templates/web/src/lib/validation/schemas.ts.tpl +15 -0
  122. package/templates/web/src/modules/example/views/example-list-view.tsx.tpl +98 -0
  123. package/templates/web/tsconfig.json.tpl +23 -0
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ /**
3
+ * Error handling checker — verifies that the backend uses the response
4
+ * envelope with proper exception filters and interceptors, and that
5
+ * the frontend has structured API error handling.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.runErrorChecks = runErrorChecks;
9
+ const types_1 = require("./types");
10
+ const RAW_THROW = /throw\s+(?:new\s+)?Error\(/;
11
+ /**
12
+ * Check backend for throw new Error() without a code property.
13
+ * These become 500 Internal Server Errors without useful context.
14
+ */
15
+ function checkRawThrows(content, rel) {
16
+ const findings = [];
17
+ const lines = content.split('\n');
18
+ for (let i = 0; i < lines.length; i++) {
19
+ if (!RAW_THROW.test(lines[i]))
20
+ continue;
21
+ // Check if the error has a code property — look ahead up to 5 lines
22
+ let hasCode = false;
23
+ const end = Math.min(lines.length - 1, i + 5);
24
+ for (let j = i; j <= end; j++) {
25
+ if (/code[:\s]/.test(lines[j])) {
26
+ hasCode = true;
27
+ break;
28
+ }
29
+ }
30
+ if (!hasCode) {
31
+ findings.push({
32
+ severity: types_1.Severity.Medium,
33
+ category: types_1.Category.Errors,
34
+ file: rel,
35
+ line: i + 1,
36
+ message: 'Raw throw Error() without code — will surface as generic 500',
37
+ evidence: lines[i].trim(),
38
+ suggestedFix: 'Use a typed exception (e.g., new NotFoundException()) or include a code property.',
39
+ rule: 'ERR-001',
40
+ });
41
+ }
42
+ }
43
+ return findings;
44
+ }
45
+ /**
46
+ * Check that the HTTP exception filter exists.
47
+ */
48
+ function checkExceptionFilter(ctx) {
49
+ const findings = [];
50
+ const filterExists = ctx.fileExists('src/common/filters/http-exception.filter.ts') ||
51
+ ctx.fileExists('src/common/filters/all-exceptions.filter.ts') ||
52
+ ctx.fileExists('src/common/filters/exception.filter.ts');
53
+ if (!filterExists) {
54
+ findings.push({
55
+ severity: types_1.Severity.High,
56
+ category: types_1.Category.Errors,
57
+ file: 'src/common/filters/',
58
+ message: 'Missing HTTP exception filter — errors may leak stack traces',
59
+ suggestedFix: 'Create src/common/filters/http-exception.filter.ts that formats errors into the standard envelope.',
60
+ rule: 'ERR-002',
61
+ });
62
+ }
63
+ return findings;
64
+ }
65
+ /**
66
+ * Check that the transform interceptor exists (response envelope).
67
+ */
68
+ function checkTransformInterceptor(ctx) {
69
+ const findings = [];
70
+ const exists = ctx.fileExists('src/common/interceptors/transform.interceptor.ts') ||
71
+ ctx.fileExists('src/common/interceptors/response.interceptor.ts');
72
+ if (!exists) {
73
+ findings.push({
74
+ severity: types_1.Severity.Medium,
75
+ category: types_1.Category.Errors,
76
+ file: 'src/common/interceptors/',
77
+ message: 'Missing transform interceptor — responses may not follow the envelope format',
78
+ suggestedFix: 'Create src/common/interceptors/transform.interceptor.ts wrapping responses in { success, data }.',
79
+ rule: 'ERR-003',
80
+ });
81
+ }
82
+ return findings;
83
+ }
84
+ /**
85
+ * Check that the frontend API client exists and has an ApiError class.
86
+ */
87
+ function checkFrontendAPIClient(ctx) {
88
+ const findings = [];
89
+ const clientPath = 'src/lib/api/client.ts';
90
+ if (!ctx.fileExists(clientPath)) {
91
+ findings.push({
92
+ severity: types_1.Severity.Medium,
93
+ category: types_1.Category.Errors,
94
+ file: clientPath,
95
+ message: 'Missing API client — no structured error handling for HTTP requests',
96
+ suggestedFix: 'Create src/lib/api/client.ts with a typed fetch wrapper and ApiError class.',
97
+ rule: 'ERR-004',
98
+ });
99
+ return findings;
100
+ }
101
+ const content = ctx.readFile(clientPath);
102
+ if (!content)
103
+ return findings;
104
+ if (!/class\s+ApiError/.test(content)) {
105
+ findings.push({
106
+ severity: types_1.Severity.Medium,
107
+ category: types_1.Category.Errors,
108
+ file: clientPath,
109
+ message: 'API client missing ApiError class — errors not typed',
110
+ suggestedFix: 'Add an ApiError class extending Error with status, code, and details fields.',
111
+ rule: 'ERR-005',
112
+ });
113
+ }
114
+ if (!/onUnauthorized|401/.test(content)) {
115
+ findings.push({
116
+ severity: types_1.Severity.Medium,
117
+ category: types_1.Category.Errors,
118
+ file: clientPath,
119
+ message: 'API client missing 401/unauthorized handling',
120
+ suggestedFix: 'Add a 401 response handler that triggers logout or token refresh.',
121
+ rule: 'ERR-006',
122
+ });
123
+ }
124
+ return findings;
125
+ }
126
+ /**
127
+ * Run all error handling checks against the repository.
128
+ *
129
+ * Type-aware: NestJS-specific checks (exception filter, envelope
130
+ * interceptor, raw-throw 500s) run ONLY for backend repos. The frontend
131
+ * API-client check runs only for web/mobile. Generic repos (repoType
132
+ * "unknown", e.g. plain Node CLIs) get no false-positive backend findings.
133
+ */
134
+ function runErrorChecks(ctx) {
135
+ const findings = [];
136
+ if (ctx.repoType === 'backend') {
137
+ const tsFiles = ctx.listFiles('**/*.ts');
138
+ for (const rel of tsFiles) {
139
+ if (/node_modules|dist|generated|\.d\.ts/.test(rel))
140
+ continue;
141
+ const content = ctx.readFile(rel);
142
+ if (!content)
143
+ continue;
144
+ findings.push(...checkRawThrows(content, rel));
145
+ }
146
+ findings.push(...checkExceptionFilter(ctx));
147
+ findings.push(...checkTransformInterceptor(ctx));
148
+ }
149
+ if (ctx.repoType === 'web' || ctx.repoType === 'mobile') {
150
+ findings.push(...checkFrontendAPIClient(ctx));
151
+ }
152
+ return findings;
153
+ }
154
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/lib/audit/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { CheckerContext, GateResult } from './types';
2
+ export declare function runGateChecks(ctx: CheckerContext): GateResult[];
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runGateChecks = runGateChecks;
4
+ /**
5
+ * Build/typecheck gate checks — runs build and typecheck, reports pass/fail.
6
+ */
7
+ const node_child_process_1 = require("node:child_process");
8
+ function runGateChecks(ctx) {
9
+ const results = [];
10
+ // Detect project type from package.json
11
+ const pkgJson = ctx.readFile('package.json');
12
+ if (!pkgJson) {
13
+ results.push({ name: 'package.json', passed: false, error: 'No package.json found' });
14
+ return results;
15
+ }
16
+ const pkg = JSON.parse(pkgJson);
17
+ const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
18
+ // Frontend (Next.js)
19
+ if (deps['next'] || deps['next.js']) {
20
+ results.push(runCommand(ctx.root, 'npm run build', 'next-build'));
21
+ }
22
+ // Backend (NestJS)
23
+ if (deps['@nestjs/core'] || deps['@nestjs/common']) {
24
+ results.push(runCommand(ctx.root, 'npm run build', 'nest-build'));
25
+ }
26
+ // Mobile (Expo)
27
+ if (deps['expo']) {
28
+ results.push(runCommand(ctx.root, 'npx expo export --dump-sourcemap', 'expo-export'));
29
+ }
30
+ // TypeScript check
31
+ if (deps['typescript']) {
32
+ results.push(runCommand(ctx.root, 'npx tsc --noEmit', 'typecheck'));
33
+ }
34
+ return results;
35
+ }
36
+ function runCommand(cwd, command, name) {
37
+ try {
38
+ const output = (0, node_child_process_1.execSync)(command, {
39
+ cwd,
40
+ timeout: 120_000,
41
+ encoding: 'utf-8',
42
+ stdio: ['pipe', 'pipe', 'pipe'],
43
+ env: { ...process.env, CI: 'true' },
44
+ });
45
+ return { name, passed: true, output: output.slice(0, 2000) };
46
+ }
47
+ catch (err) {
48
+ const e = err;
49
+ return {
50
+ name,
51
+ passed: false,
52
+ output: (e.stdout ?? '').slice(0, 2000),
53
+ error: (e.stderr ?? e.message ?? 'Unknown error').slice(0, 2000),
54
+ };
55
+ }
56
+ }
57
+ //# sourceMappingURL=gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.js","sourceRoot":"","sources":["../../../src/lib/audit/gates.ts"],"names":[],"mappings":";;AAMA,sCAkCC;AAxCD;;GAEG;AACH,2DAA8C;AAG9C,SAAgB,aAAa,CAAC,GAAmB;IAC/C,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,wCAAwC;IACxC,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QACtF,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;IAC3D,MAAM,IAAI,GAAG,EAAE,GAAI,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAA4B,EAAE,GAAI,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAA4B,EAAE,CAAC;IAErI,qBAAqB;IACrB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,mBAAmB;IACnB,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,gBAAgB;IAChB,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,kCAAkC,EAAE,aAAa,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,mBAAmB;IACnB,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,UAAU,CAAC,GAAW,EAAE,OAAe,EAAE,IAAY;IAC5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,6BAAQ,EAAC,OAAO,EAAE;YAC/B,GAAG;YACH,OAAO,EAAE,OAAO;YAChB,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;SACpC,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,GAA6D,CAAC;QACxE,OAAO;YACL,IAAI;YACJ,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;YACvC,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;SACjE,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Modularity checker — enforces vendor boundary rules, modular layouts,
3
+ * and structural conventions for backend and frontend repos.
4
+ */
5
+ import type { Finding, CheckerContext } from './types';
6
+ /**
7
+ * Run all modularity checks against the repository.
8
+ *
9
+ * Type-aware: vendor-boundary, shared-index and folder-naming checks are
10
+ * frontend-specific and run only for web/mobile repos; NestJS layout
11
+ * checks run only for backend repos.
12
+ */
13
+ export declare function runModularityChecks(ctx: CheckerContext): Finding[];
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ /**
3
+ * Modularity checker — enforces vendor boundary rules, modular layouts,
4
+ * and structural conventions for backend and frontend repos.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runModularityChecks = runModularityChecks;
8
+ const types_1 = require("./types");
9
+ const VENDOR_UI_IMPORT = /from\s+['"]@\/components\/ui\//;
10
+ const LUCIDE_IMPORT = /from\s+['"]lucide-react(-native)?['"]/;
11
+ const MODULE_FOLDER_PATTERN = /^src\/modules\/([^/]+)\//;
12
+ const KEBAB_CASE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
13
+ const BACKEND_MODULE_FILES = ['controller', 'service', 'dto', 'module'];
14
+ const BACKEND_COMMON_DIRS = [
15
+ 'guards',
16
+ 'filters',
17
+ 'interceptors',
18
+ 'pipes',
19
+ 'swagger',
20
+ 'constants',
21
+ 'utils',
22
+ 'prisma',
23
+ ];
24
+ /**
25
+ * Check for direct imports of vendor ui/ components from app code.
26
+ * App code should import from @/components/shared, not ui/ directly.
27
+ */
28
+ function checkVendorBoundary(content, rel) {
29
+ const findings = [];
30
+ const lines = content.split('\n');
31
+ // Allow imports inside components/ui/ itself and components/shared/
32
+ if (/^src\/components\/(ui|shared)\//.test(rel))
33
+ return findings;
34
+ for (let i = 0; i < lines.length; i++) {
35
+ if (VENDOR_UI_IMPORT.test(lines[i])) {
36
+ findings.push({
37
+ severity: types_1.Severity.High,
38
+ category: types_1.Category.Modularity,
39
+ file: rel,
40
+ line: i + 1,
41
+ message: 'Direct import from vendor ui/ boundary — must use shared TS* wrappers',
42
+ evidence: lines[i].trim(),
43
+ suggestedFix: 'Import from @/components/shared instead of @/components/ui/.',
44
+ rule: 'MOD-001',
45
+ });
46
+ }
47
+ }
48
+ return findings;
49
+ }
50
+ /**
51
+ * Check for lucide-react imports outside of vendor ui/ components.
52
+ */
53
+ function checkLucideBoundary(content, rel) {
54
+ const findings = [];
55
+ const lines = content.split('\n');
56
+ if (/^src\/components\/ui\//.test(rel))
57
+ return findings;
58
+ for (let i = 0; i < lines.length; i++) {
59
+ if (LUCIDE_IMPORT.test(lines[i])) {
60
+ findings.push({
61
+ severity: types_1.Severity.High,
62
+ category: types_1.Category.Modularity,
63
+ file: rel,
64
+ line: i + 1,
65
+ message: 'Direct lucide-react import outside vendor ui/ — use IconSax icons instead',
66
+ evidence: lines[i].trim(),
67
+ suggestedFix: 'Replace with iconsax-react (web) or iconsax-react-native (mobile). See ui-style-guide.md section 6.4.',
68
+ rule: 'MOD-002',
69
+ });
70
+ }
71
+ }
72
+ return findings;
73
+ }
74
+ /**
75
+ * Check that module folders use kebab-case naming.
76
+ */
77
+ function checkModuleFolderNames(files) {
78
+ const findings = [];
79
+ const moduleFolders = new Set();
80
+ for (const rel of files) {
81
+ const match = rel.match(MODULE_FOLDER_PATTERN);
82
+ if (match) {
83
+ moduleFolders.add(match[1]);
84
+ }
85
+ }
86
+ for (const folder of Array.from(moduleFolders)) {
87
+ if (!KEBAB_CASE.test(folder)) {
88
+ findings.push({
89
+ severity: types_1.Severity.Low,
90
+ category: types_1.Category.Modularity,
91
+ file: `src/modules/${folder}/`,
92
+ message: `Module folder "${folder}" is not kebab-case`,
93
+ suggestedFix: `Rename to "${folder.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '')}".`,
94
+ rule: 'MOD-003',
95
+ });
96
+ }
97
+ }
98
+ return findings;
99
+ }
100
+ /**
101
+ * Check that each backend module has controller, service, dto, and module files.
102
+ */
103
+ function checkBackendModuleStructure(ctx) {
104
+ const findings = [];
105
+ const files = ctx.listFiles('src/modules/*/');
106
+ const moduleFolders = new Set();
107
+ for (const rel of files) {
108
+ const match = rel.match(MODULE_FOLDER_PATTERN);
109
+ if (match) {
110
+ moduleFolders.add(match[1]);
111
+ }
112
+ }
113
+ for (const folder of Array.from(moduleFolders)) {
114
+ for (const suffix of BACKEND_MODULE_FILES) {
115
+ const pattern = `src/modules/${folder}/${folder}.${suffix}.ts`;
116
+ if (!ctx.fileExists(pattern)) {
117
+ findings.push({
118
+ severity: types_1.Severity.Medium,
119
+ category: types_1.Category.Modularity,
120
+ file: `src/modules/${folder}/`,
121
+ message: `Module "${folder}" missing ${suffix} file`,
122
+ suggestedFix: `Create ${folder}.${suffix}.ts following the existing module pattern.`,
123
+ rule: 'MOD-004',
124
+ });
125
+ }
126
+ }
127
+ }
128
+ return findings;
129
+ }
130
+ /**
131
+ * Check that backend common/ directory has required subfolders.
132
+ */
133
+ function checkBackendCommonDirs(ctx) {
134
+ const findings = [];
135
+ for (const dir of BACKEND_COMMON_DIRS) {
136
+ if (!ctx.fileExists(`src/common/${dir}/`)) {
137
+ findings.push({
138
+ severity: types_1.Severity.Low,
139
+ category: types_1.Category.Modularity,
140
+ file: `src/common/${dir}/`,
141
+ message: `Backend missing src/common/${dir}/ directory`,
142
+ suggestedFix: `Create src/common/${dir}/ and add the relevant files.`,
143
+ rule: 'MOD-005',
144
+ });
145
+ }
146
+ }
147
+ return findings;
148
+ }
149
+ /**
150
+ * Check that the shared components index file exists.
151
+ *
152
+ * Frontend-only check — a repo without src/components/shared is not a
153
+ * frontend and must not be flagged.
154
+ */
155
+ function checkSharedIndex(ctx) {
156
+ const findings = [];
157
+ if (!ctx.fileExists('src/components/shared/index.ts') &&
158
+ !ctx.fileExists('src/components/shared/index.tsx')) {
159
+ findings.push({
160
+ severity: types_1.Severity.Medium,
161
+ category: types_1.Category.Modularity,
162
+ file: 'src/components/shared/index.ts',
163
+ message: 'Missing shared components index file — shared components not re-exported',
164
+ suggestedFix: 'Create src/components/shared/index.ts that re-exports all shared wrapper components.',
165
+ rule: 'MOD-006',
166
+ });
167
+ }
168
+ return findings;
169
+ }
170
+ /**
171
+ * Run all modularity checks against the repository.
172
+ *
173
+ * Type-aware: vendor-boundary, shared-index and folder-naming checks are
174
+ * frontend-specific and run only for web/mobile repos; NestJS layout
175
+ * checks run only for backend repos.
176
+ */
177
+ function runModularityChecks(ctx) {
178
+ const findings = [];
179
+ if (ctx.repoType === 'backend') {
180
+ findings.push(...checkBackendModuleStructure(ctx));
181
+ findings.push(...checkBackendCommonDirs(ctx));
182
+ return findings;
183
+ }
184
+ if (ctx.repoType !== 'web' && ctx.repoType !== 'mobile')
185
+ return findings;
186
+ const files = ctx.listFiles('**/*.{ts,tsx}');
187
+ for (const rel of files) {
188
+ if (/node_modules|dist|generated/.test(rel))
189
+ continue;
190
+ const content = ctx.readFile(rel);
191
+ if (!content)
192
+ continue;
193
+ findings.push(...checkVendorBoundary(content, rel));
194
+ findings.push(...checkLucideBoundary(content, rel));
195
+ }
196
+ findings.push(...checkModuleFolderNames(files));
197
+ findings.push(...checkSharedIndex(ctx));
198
+ return findings;
199
+ }
200
+ //# sourceMappingURL=modularity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modularity.js","sourceRoot":"","sources":["../../../src/lib/audit/modularity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Code quality checker — flags eslint-disable comments, TypeScript
3
+ * suppressions, TODO/FIXME markers, and excessively long lines.
4
+ */
5
+ import type { Finding, CheckerContext } from './types';
6
+ /**
7
+ * Run all code quality checks against the repository.
8
+ */
9
+ export declare function runQualityChecks(ctx: CheckerContext): Finding[];
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ /**
3
+ * Code quality checker — flags eslint-disable comments, TypeScript
4
+ * suppressions, TODO/FIXME markers, and excessively long lines.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runQualityChecks = runQualityChecks;
8
+ const types_1 = require("./types");
9
+ const ESLINT_DISABLE = /(\/\/\s*eslint-disable|\/\*\s*eslint-disable)/;
10
+ const ESLINT_DISABLE_RULE = /eslint-disable(?:-next-line|-once)?\s*(?:\(([^)]+)\))?/;
11
+ const TS_IGNORE = /(@ts-ignore|@ts-expect-error)/;
12
+ const TODO_FIXME = /(TODO|FIXME)\b\s*[:\-]?\s*(.*)/;
13
+ const SKIP_PATHS = /node_modules|dist|generated|\.d\.ts/;
14
+ /**
15
+ * Check for eslint-disable comments and extract the rule being disabled.
16
+ */
17
+ function checkESLintDisables(content, rel) {
18
+ const findings = [];
19
+ const lines = content.split('\n');
20
+ for (let i = 0; i < lines.length; i++) {
21
+ if (!ESLINT_DISABLE.test(lines[i]))
22
+ continue;
23
+ const ruleMatch = lines[i].match(ESLINT_DISABLE_RULE);
24
+ const rule = ruleMatch?.[1] || 'all rules';
25
+ findings.push({
26
+ severity: types_1.Severity.Medium,
27
+ category: types_1.Category.Quality,
28
+ file: rel,
29
+ line: i + 1,
30
+ message: `eslint-disable used — suppressing ${rule}`,
31
+ evidence: lines[i].trim(),
32
+ suggestedFix: 'Fix the underlying issue instead of disabling the lint rule.',
33
+ rule: 'QUA-001',
34
+ });
35
+ }
36
+ return findings;
37
+ }
38
+ /**
39
+ * Check for TypeScript error suppressions.
40
+ */
41
+ function checkTSSuppressions(content, rel) {
42
+ const findings = [];
43
+ const lines = content.split('\n');
44
+ for (let i = 0; i < lines.length; i++) {
45
+ const match = lines[i].match(TS_IGNORE);
46
+ if (!match)
47
+ continue;
48
+ findings.push({
49
+ severity: types_1.Severity.Medium,
50
+ category: types_1.Category.Quality,
51
+ file: rel,
52
+ line: i + 1,
53
+ message: `TypeScript error suppressed with ${match[1]}`,
54
+ evidence: lines[i].trim(),
55
+ suggestedFix: 'Fix the underlying type error instead of suppressing it.',
56
+ rule: 'QUA-002',
57
+ });
58
+ }
59
+ return findings;
60
+ }
61
+ /**
62
+ * Check for TODO and FIXME comments and extract the note text.
63
+ */
64
+ function checkTodoFixme(content, rel) {
65
+ const findings = [];
66
+ const lines = content.split('\n');
67
+ for (let i = 0; i < lines.length; i++) {
68
+ const match = lines[i].match(TODO_FIXME);
69
+ if (!match)
70
+ continue;
71
+ const marker = match[1];
72
+ const note = match[2]?.trim() || '(no description)';
73
+ findings.push({
74
+ severity: types_1.Severity.Low,
75
+ category: types_1.Category.Quality,
76
+ file: rel,
77
+ line: i + 1,
78
+ message: `${marker}: ${note}`,
79
+ evidence: lines[i].trim(),
80
+ rule: 'QUA-003',
81
+ });
82
+ }
83
+ return findings;
84
+ }
85
+ /**
86
+ * Count lines exceeding 120 characters in a file.
87
+ */
88
+ function checkLongLines(content, rel) {
89
+ const findings = [];
90
+ const lines = content.split('\n');
91
+ let longCount = 0;
92
+ for (let i = 0; i < lines.length; i++) {
93
+ if (lines[i].length > 120) {
94
+ longCount++;
95
+ }
96
+ }
97
+ if (longCount > 10) {
98
+ findings.push({
99
+ severity: types_1.Severity.Low,
100
+ category: types_1.Category.Quality,
101
+ file: rel,
102
+ message: `${longCount} lines exceed 120 characters`,
103
+ suggestedFix: 'Break long lines for readability. Consider extracting long strings or arguments.',
104
+ rule: 'QUA-004',
105
+ });
106
+ }
107
+ return findings;
108
+ }
109
+ /**
110
+ * Run all code quality checks against the repository.
111
+ */
112
+ function runQualityChecks(ctx) {
113
+ const findings = [];
114
+ const files = ctx.listFiles('**/*.{ts,tsx}');
115
+ for (const rel of files) {
116
+ if (SKIP_PATHS.test(rel))
117
+ continue;
118
+ const content = ctx.readFile(rel);
119
+ if (!content)
120
+ continue;
121
+ findings.push(...checkESLintDisables(content, rel));
122
+ findings.push(...checkTSSuppressions(content, rel));
123
+ findings.push(...checkTodoFixme(content, rel));
124
+ findings.push(...checkLongLines(content, rel));
125
+ }
126
+ return findings;
127
+ }
128
+ //# sourceMappingURL=quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../../src/lib/audit/quality.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * RBAC checker — verifies that backend controllers have proper access
3
+ * metadata on every method, that auth guards exist and are registered
4
+ * globally, and that the RBAC constants file is present.
5
+ */
6
+ import type { Finding, CheckerContext } from './types';
7
+ /**
8
+ * Run all RBAC checks against the repository.
9
+ *
10
+ * Type-aware: all checks are NestJS-backend-specific, so they run only
11
+ * when the repo is a backend. Generic repos (repoType "unknown") are not
12
+ * flagged for missing guards/rbac constants they never promised to have.
13
+ */
14
+ export declare function runRBACChecks(ctx: CheckerContext): Finding[];