kodu 2.2.0 → 3.0.1

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 (233) hide show
  1. package/README.md +24 -3
  2. package/bin/kodu.js +23 -0
  3. package/package.json +11 -67
  4. package/scripts/postinstall.js +69 -0
  5. package/AGENTS.md +0 -214
  6. package/__tests__/core/fs/fs.service.test.ts +0 -72
  7. package/__tests__/core/registry/registry.service.test.ts +0 -82
  8. package/__tests__/shared/cleaner/cleaner.service.test.ts +0 -102
  9. package/__tests__/shared/git/git.service.test.ts +0 -84
  10. package/__tests__/shared/runbook/runbook.service.test.ts +0 -104
  11. package/__tests__/shared/tokenizer/tokenizer.service.test.ts +0 -45
  12. package/biome.json +0 -50
  13. package/dist/package.json +0 -96
  14. package/dist/src/app.module.d.ts +0 -2
  15. package/dist/src/app.module.js +0 -42
  16. package/dist/src/app.module.js.map +0 -1
  17. package/dist/src/commands/clean/clean.command.d.ts +0 -37
  18. package/dist/src/commands/clean/clean.command.js +0 -240
  19. package/dist/src/commands/clean/clean.command.js.map +0 -1
  20. package/dist/src/commands/clean/clean.module.d.ts +0 -2
  21. package/dist/src/commands/clean/clean.module.js +0 -26
  22. package/dist/src/commands/clean/clean.module.js.map +0 -1
  23. package/dist/src/commands/init/init.command.d.ts +0 -10
  24. package/dist/src/commands/init/init.command.js +0 -96
  25. package/dist/src/commands/init/init.command.js.map +0 -1
  26. package/dist/src/commands/init/init.module.d.ts +0 -2
  27. package/dist/src/commands/init/init.module.js +0 -22
  28. package/dist/src/commands/init/init.module.js.map +0 -1
  29. package/dist/src/commands/ops/ops-add.command.d.ts +0 -18
  30. package/dist/src/commands/ops/ops-add.command.js +0 -102
  31. package/dist/src/commands/ops/ops-add.command.js.map +0 -1
  32. package/dist/src/commands/ops/ops-init.command.d.ts +0 -22
  33. package/dist/src/commands/ops/ops-init.command.js +0 -130
  34. package/dist/src/commands/ops/ops-init.command.js.map +0 -1
  35. package/dist/src/commands/ops/ops-list.command.d.ts +0 -12
  36. package/dist/src/commands/ops/ops-list.command.js +0 -73
  37. package/dist/src/commands/ops/ops-list.command.js.map +0 -1
  38. package/dist/src/commands/ops/ops-path.command.d.ts +0 -9
  39. package/dist/src/commands/ops/ops-path.command.js +0 -52
  40. package/dist/src/commands/ops/ops-path.command.js.map +0 -1
  41. package/dist/src/commands/ops/ops-runbook.command.d.ts +0 -12
  42. package/dist/src/commands/ops/ops-runbook.command.js +0 -81
  43. package/dist/src/commands/ops/ops-runbook.command.js.map +0 -1
  44. package/dist/src/commands/ops/ops-status.command.d.ts +0 -11
  45. package/dist/src/commands/ops/ops-status.command.js +0 -62
  46. package/dist/src/commands/ops/ops-status.command.js.map +0 -1
  47. package/dist/src/commands/ops/ops-use.command.d.ts +0 -12
  48. package/dist/src/commands/ops/ops-use.command.js +0 -76
  49. package/dist/src/commands/ops/ops-use.command.js.map +0 -1
  50. package/dist/src/commands/ops/ops.command.d.ts +0 -7
  51. package/dist/src/commands/ops/ops.command.js +0 -56
  52. package/dist/src/commands/ops/ops.command.js.map +0 -1
  53. package/dist/src/commands/ops/ops.helpers.d.ts +0 -2
  54. package/dist/src/commands/ops/ops.helpers.js +0 -11
  55. package/dist/src/commands/ops/ops.helpers.js.map +0 -1
  56. package/dist/src/commands/ops/ops.module.d.ts +0 -2
  57. package/dist/src/commands/ops/ops.module.js +0 -36
  58. package/dist/src/commands/ops/ops.module.js.map +0 -1
  59. package/dist/src/commands/pack/pack.command.d.ts +0 -51
  60. package/dist/src/commands/pack/pack.command.js +0 -355
  61. package/dist/src/commands/pack/pack.command.js.map +0 -1
  62. package/dist/src/commands/pack/pack.module.d.ts +0 -2
  63. package/dist/src/commands/pack/pack.module.js +0 -27
  64. package/dist/src/commands/pack/pack.module.js.map +0 -1
  65. package/dist/src/core/config/config.module.d.ts +0 -2
  66. package/dist/src/core/config/config.module.js +0 -23
  67. package/dist/src/core/config/config.module.js.map +0 -1
  68. package/dist/src/core/config/config.schema.d.ts +0 -19
  69. package/dist/src/core/config/config.schema.js +0 -56
  70. package/dist/src/core/config/config.schema.js.map +0 -1
  71. package/dist/src/core/config/config.service.d.ts +0 -7
  72. package/dist/src/core/config/config.service.js +0 -49
  73. package/dist/src/core/config/config.service.js.map +0 -1
  74. package/dist/src/core/config/prompt.service.d.ts +0 -10
  75. package/dist/src/core/config/prompt.service.js +0 -80
  76. package/dist/src/core/config/prompt.service.js.map +0 -1
  77. package/dist/src/core/file-system/fs.module.d.ts +0 -2
  78. package/dist/src/core/file-system/fs.module.js +0 -21
  79. package/dist/src/core/file-system/fs.module.js.map +0 -1
  80. package/dist/src/core/file-system/fs.service.d.ts +0 -27
  81. package/dist/src/core/file-system/fs.service.js +0 -203
  82. package/dist/src/core/file-system/fs.service.js.map +0 -1
  83. package/dist/src/core/registry/registry.module.d.ts +0 -2
  84. package/dist/src/core/registry/registry.module.js +0 -22
  85. package/dist/src/core/registry/registry.module.js.map +0 -1
  86. package/dist/src/core/registry/registry.schema.d.ts +0 -24
  87. package/dist/src/core/registry/registry.schema.js +0 -21
  88. package/dist/src/core/registry/registry.schema.js.map +0 -1
  89. package/dist/src/core/registry/registry.service.d.ts +0 -16
  90. package/dist/src/core/registry/registry.service.js +0 -91
  91. package/dist/src/core/registry/registry.service.js.map +0 -1
  92. package/dist/src/core/ui/ui.module.d.ts +0 -2
  93. package/dist/src/core/ui/ui.module.js +0 -22
  94. package/dist/src/core/ui/ui.module.js.map +0 -1
  95. package/dist/src/core/ui/ui.service.d.ts +0 -22
  96. package/dist/src/core/ui/ui.service.js +0 -43
  97. package/dist/src/core/ui/ui.service.js.map +0 -1
  98. package/dist/src/main.d.ts +0 -2
  99. package/dist/src/main.js +0 -16
  100. package/dist/src/main.js.map +0 -1
  101. package/dist/src/shared/cleaner/cleaner.service.d.ts +0 -23
  102. package/dist/src/shared/cleaner/cleaner.service.js +0 -223
  103. package/dist/src/shared/cleaner/cleaner.service.js.map +0 -1
  104. package/dist/src/shared/cleaner/cleaner.types.d.ts +0 -21
  105. package/dist/src/shared/cleaner/cleaner.types.js +0 -3
  106. package/dist/src/shared/cleaner/cleaner.types.js.map +0 -1
  107. package/dist/src/shared/constants.d.ts +0 -4
  108. package/dist/src/shared/constants.js +0 -113
  109. package/dist/src/shared/constants.js.map +0 -1
  110. package/dist/src/shared/deps/deps.module.d.ts +0 -2
  111. package/dist/src/shared/deps/deps.module.js +0 -21
  112. package/dist/src/shared/deps/deps.module.js.map +0 -1
  113. package/dist/src/shared/deps/deps.service.d.ts +0 -15
  114. package/dist/src/shared/deps/deps.service.js +0 -114
  115. package/dist/src/shared/deps/deps.service.js.map +0 -1
  116. package/dist/src/shared/git/git.module.d.ts +0 -2
  117. package/dist/src/shared/git/git.module.js +0 -21
  118. package/dist/src/shared/git/git.module.js.map +0 -1
  119. package/dist/src/shared/git/git.service.d.ts +0 -5
  120. package/dist/src/shared/git/git.service.js +0 -56
  121. package/dist/src/shared/git/git.service.js.map +0 -1
  122. package/dist/src/shared/runbook/runbook.module.d.ts +0 -2
  123. package/dist/src/shared/runbook/runbook.module.js +0 -22
  124. package/dist/src/shared/runbook/runbook.module.js.map +0 -1
  125. package/dist/src/shared/runbook/runbook.service.d.ts +0 -20
  126. package/dist/src/shared/runbook/runbook.service.js +0 -118
  127. package/dist/src/shared/runbook/runbook.service.js.map +0 -1
  128. package/dist/src/shared/runbook/runbook.templates.d.ts +0 -6
  129. package/dist/src/shared/runbook/runbook.templates.js +0 -49
  130. package/dist/src/shared/runbook/runbook.templates.js.map +0 -1
  131. package/dist/src/shared/tokenizer/tokenizer.module.d.ts +0 -2
  132. package/dist/src/shared/tokenizer/tokenizer.module.js +0 -21
  133. package/dist/src/shared/tokenizer/tokenizer.module.js.map +0 -1
  134. package/dist/src/shared/tokenizer/tokenizer.service.d.ts +0 -10
  135. package/dist/src/shared/tokenizer/tokenizer.service.js +0 -36
  136. package/dist/src/shared/tokenizer/tokenizer.service.js.map +0 -1
  137. package/dist/tsconfig.build.tsbuildinfo +0 -1
  138. package/docs/todo.md +0 -7
  139. package/knip.json +0 -10
  140. package/kodu.json +0 -63
  141. package/kodu.schema.json +0 -100
  142. package/lefthook.yml +0 -11
  143. package/nest-cli.json +0 -8
  144. package/registry.schema.json +0 -39
  145. package/scripts/generate-json-schema.ts +0 -27
  146. package/skills/ac/SKILL.md +0 -239
  147. package/skills/al/SKILL.md +0 -98
  148. package/skills/audit/SKILL.md +0 -205
  149. package/skills/audit/audit-baseline-template.yml +0 -188
  150. package/skills/audit/runtime-detect.md +0 -64
  151. package/skills/audit/stacks/_generic.md +0 -41
  152. package/skills/audit/stacks/_registry.md +0 -47
  153. package/skills/audit/stacks/go.md +0 -66
  154. package/skills/audit/stacks/java.md +0 -44
  155. package/skills/audit/stacks/node.md +0 -57
  156. package/skills/audit/stacks/python.md +0 -45
  157. package/skills/audit/stacks/rust.md +0 -44
  158. package/skills/audit-api-contracts/SKILL.md +0 -201
  159. package/skills/audit-architecture/SKILL.md +0 -200
  160. package/skills/audit-bugs/SKILL.md +0 -226
  161. package/skills/audit-concurrency/SKILL.md +0 -197
  162. package/skills/audit-deployment/SKILL.md +0 -218
  163. package/skills/audit-docs/SKILL.md +0 -209
  164. package/skills/audit-errors/SKILL.md +0 -216
  165. package/skills/audit-logging/SKILL.md +0 -197
  166. package/skills/audit-matrix/SKILL.md +0 -245
  167. package/skills/audit-meta/SKILL.md +0 -120
  168. package/skills/audit-naming/SKILL.md +0 -200
  169. package/skills/audit-owasp/SKILL.md +0 -223
  170. package/skills/audit-performance/SKILL.md +0 -199
  171. package/skills/audit-reinvention/SKILL.md +0 -214
  172. package/skills/audit-secrets/SKILL.md +0 -198
  173. package/skills/audit-tests/SKILL.md +0 -210
  174. package/skills/audit-validation/SKILL.md +0 -206
  175. package/skills/audit-verify/SKILL.md +0 -139
  176. package/skills/audit-yagni/SKILL.md +0 -188
  177. package/skills/doc-gen/SKILL.md +0 -490
  178. package/skills/doc-gen/scripts/doc_gen.py +0 -911
  179. package/skills/generate-project-docs/SKILL.md +0 -380
  180. package/skills/implement-project/SKILL.md +0 -409
  181. package/skills/liteend-init/SKILL.md +0 -84
  182. package/skills/litefront-init/SKILL.md +0 -96
  183. package/skills/litefront-prototype/SKILL.md +0 -484
  184. package/skills/ops/SKILL.md +0 -94
  185. package/skills/post-call-task-builder/SKILL.md +0 -419
  186. package/skills/project-setup-standardizer/SKILL.md +0 -285
  187. package/skills/skills-best-practices/SKILL.md +0 -415
  188. package/skills/start/SKILL.md +0 -319
  189. package/skills/tech-blueprint/SKILL.md +0 -890
  190. package/skills/tech-blueprint/scripts/blueprint_validator.py +0 -417
  191. package/src/app.module.ts +0 -29
  192. package/src/commands/clean/clean.command.ts +0 -235
  193. package/src/commands/clean/clean.module.ts +0 -13
  194. package/src/commands/init/init.command.ts +0 -92
  195. package/src/commands/init/init.module.ts +0 -9
  196. package/src/commands/ops/ops-add.command.ts +0 -83
  197. package/src/commands/ops/ops-init.command.ts +0 -125
  198. package/src/commands/ops/ops-list.command.ts +0 -57
  199. package/src/commands/ops/ops-path.command.ts +0 -38
  200. package/src/commands/ops/ops-runbook.command.ts +0 -74
  201. package/src/commands/ops/ops-status.command.ts +0 -47
  202. package/src/commands/ops/ops-use.command.ts +0 -76
  203. package/src/commands/ops/ops.command.ts +0 -42
  204. package/src/commands/ops/ops.helpers.ts +0 -20
  205. package/src/commands/ops/ops.module.ts +0 -23
  206. package/src/commands/pack/pack.command.ts +0 -347
  207. package/src/commands/pack/pack.module.ts +0 -14
  208. package/src/core/config/config.module.ts +0 -10
  209. package/src/core/config/config.schema.ts +0 -58
  210. package/src/core/config/config.service.ts +0 -43
  211. package/src/core/config/prompt.service.ts +0 -80
  212. package/src/core/file-system/fs.module.ts +0 -8
  213. package/src/core/file-system/fs.service.ts +0 -248
  214. package/src/core/registry/registry.module.ts +0 -9
  215. package/src/core/registry/registry.schema.ts +0 -46
  216. package/src/core/registry/registry.service.ts +0 -128
  217. package/src/core/ui/ui.module.ts +0 -9
  218. package/src/core/ui/ui.service.ts +0 -39
  219. package/src/main.ts +0 -12
  220. package/src/shared/cleaner/cleaner.service.ts +0 -289
  221. package/src/shared/cleaner/cleaner.types.ts +0 -23
  222. package/src/shared/constants.ts +0 -118
  223. package/src/shared/deps/deps.module.ts +0 -8
  224. package/src/shared/deps/deps.service.ts +0 -175
  225. package/src/shared/git/git.module.ts +0 -8
  226. package/src/shared/git/git.service.ts +0 -47
  227. package/src/shared/runbook/runbook.module.ts +0 -9
  228. package/src/shared/runbook/runbook.service.ts +0 -164
  229. package/src/shared/runbook/runbook.templates.ts +0 -66
  230. package/src/shared/tokenizer/tokenizer.module.ts +0 -8
  231. package/src/shared/tokenizer/tokenizer.service.ts +0 -30
  232. package/tsconfig.build.json +0 -7
  233. package/tsconfig.json +0 -28
@@ -1,289 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { Injectable } from '@nestjs/common';
4
- import { Project, type SourceFile, SyntaxKind, ts } from 'ts-morph';
5
- import { ConfigService } from '../../core/config/config.service';
6
- import { FsService } from '../../core/file-system/fs.service';
7
- import {
8
- type CleanOptions,
9
- type CleanSummary,
10
- type FileCleanReport,
11
- } from './cleaner.types';
12
-
13
- type RemovalRange = {
14
- start: number;
15
- end: number;
16
- text: string;
17
- kind: 'comment' | 'jsx';
18
- };
19
-
20
- @Injectable()
21
- export class CleanerService {
22
- private readonly project = new Project({
23
- useInMemoryFileSystem: false,
24
- skipFileDependencyResolution: true,
25
- compilerOptions: {
26
- allowJs: true,
27
- jsx: ts.JsxEmit.Preserve,
28
- },
29
- });
30
-
31
- private readonly systemWhitelist = [
32
- '@ts-ignore',
33
- '@ts-expect-error',
34
- 'eslint-disable',
35
- 'prettier-ignore',
36
- 'biome-ignore',
37
- 'todo',
38
- 'fixme',
39
- ];
40
-
41
- constructor(
42
- private readonly configService: ConfigService,
43
- private readonly fsService: FsService,
44
- ) {}
45
-
46
- cleanContent(filename: string, content: string, keepJSDoc?: boolean): string {
47
- const config = this.configService.getConfig();
48
- const whitelist = this.buildWhitelist(config.cleaner.whitelist);
49
- const shouldKeepJSDoc = keepJSDoc ?? config.cleaner.keepJSDoc;
50
- const result = this.cleanSource(
51
- filename,
52
- content,
53
- whitelist,
54
- shouldKeepJSDoc,
55
- );
56
- return result.nextContent;
57
- }
58
-
59
- async cleanFiles(
60
- files: string[],
61
- options: CleanOptions = {},
62
- ): Promise<CleanSummary> {
63
- const config = this.configService.getConfig();
64
- const whitelist = this.buildWhitelist(config.cleaner.whitelist);
65
- const keepJSDoc = options.keepJSDoc ?? config.cleaner.keepJSDoc;
66
- let commentsRemoved = 0;
67
- let filesChanged = 0;
68
- let bytesBefore = 0;
69
- let bytesAfter = 0;
70
- const reports: FileCleanReport[] = [];
71
-
72
- for (let i = 0; i < files.length; i++) {
73
- const file = files[i] as string;
74
- options.onProgress?.(i + 1, files.length);
75
-
76
- const original = await this.fsService.readFileRelative(file);
77
- bytesBefore += Buffer.byteLength(original, 'utf8');
78
-
79
- const result = this.cleanSource(file, original, whitelist, keepJSDoc);
80
- bytesAfter += Buffer.byteLength(result.nextContent, 'utf8');
81
-
82
- if (result.removed > 0) {
83
- filesChanged += 1;
84
- commentsRemoved += result.removed;
85
-
86
- if (!options.dryRun) {
87
- if (options.backup) {
88
- await this.backupFile(file, original);
89
- }
90
- await this.writeFile(file, result.nextContent);
91
- }
92
- }
93
-
94
- reports.push({
95
- file,
96
- removed: result.removed,
97
- previews: result.previews,
98
- bytesBefore: Buffer.byteLength(original, 'utf8'),
99
- bytesAfter: Buffer.byteLength(result.nextContent, 'utf8'),
100
- });
101
- }
102
-
103
- return {
104
- filesProcessed: files.length,
105
- filesChanged,
106
- commentsRemoved,
107
- bytesBefore,
108
- bytesAfter,
109
- reports,
110
- };
111
- }
112
-
113
- private cleanSource(
114
- file: string,
115
- content: string,
116
- whitelist: Set<string>,
117
- keepJSDoc: boolean,
118
- ): { nextContent: string; removed: number; previews: string[] } {
119
- const sourceFile = this.project.createSourceFile(file, content, {
120
- overwrite: true,
121
- });
122
- const fullText = sourceFile.getFullText();
123
-
124
- const ranges = this.collectCommentRanges(sourceFile, file);
125
- const candidates = ranges.filter((range) =>
126
- this.shouldRemove(range, whitelist, keepJSDoc),
127
- );
128
-
129
- if (candidates.length === 0) {
130
- return { nextContent: content, removed: 0, previews: [] };
131
- }
132
-
133
- const previews = candidates.map((range) =>
134
- this.normalizePreview(range.text),
135
- );
136
-
137
- const sorted = [...candidates].sort((a, b) => b.start - a.start);
138
- let nextContent = fullText;
139
-
140
- for (const range of sorted) {
141
- const replacement = this.getReplacement(fullText, range);
142
- nextContent = `${nextContent.slice(0, range.start)}${replacement}${nextContent.slice(range.end)}`;
143
- }
144
-
145
- return { nextContent, removed: candidates.length, previews };
146
- }
147
-
148
- private collectCommentRanges(
149
- sourceFile: SourceFile,
150
- file: string,
151
- ): RemovalRange[] {
152
- const fullText = sourceFile.getFullText();
153
- const ranges = new Map<string, RemovalRange>();
154
-
155
- const addRanges = (items: readonly ts.CommentRange[] | undefined) => {
156
- if (!items) return;
157
-
158
- for (const item of items) {
159
- this.addRange(
160
- ranges,
161
- item.pos,
162
- item.end,
163
- fullText.slice(item.pos, item.end),
164
- );
165
- }
166
- };
167
-
168
- const visit = (node: ts.Node): void => {
169
- addRanges(ts.getLeadingCommentRanges(fullText, node.getFullStart()));
170
- addRanges(ts.getTrailingCommentRanges(fullText, node.getEnd()));
171
- ts.forEachChild(node, visit);
172
- };
173
-
174
- visit(sourceFile.compilerNode);
175
-
176
- const jsxExpressions = sourceFile.getDescendantsOfKind(
177
- SyntaxKind.JsxExpression,
178
- );
179
- for (const jsx of jsxExpressions) {
180
- if (jsx.getExpression()) continue;
181
- const text = jsx.getText();
182
- if (!text.includes('/*')) continue;
183
-
184
- const start = jsx.getPos();
185
- const end = jsx.getEnd();
186
- this.addRange(ranges, start, end, fullText.slice(start, end), 'jsx');
187
- }
188
-
189
- if (this.shouldCollectHtmlComments(file)) {
190
- this.collectHtmlCommentRanges(fullText, ranges);
191
- }
192
-
193
- return [...ranges.values()];
194
- }
195
-
196
- private shouldRemove(
197
- range: RemovalRange,
198
- whitelist: Set<string>,
199
- keepJSDoc: boolean,
200
- ): boolean {
201
- const trimmed = range.text.trimStart();
202
- if (keepJSDoc && trimmed.startsWith('/**')) {
203
- return false;
204
- }
205
-
206
- const lower = range.text.toLowerCase();
207
- for (const token of whitelist) {
208
- if (lower.includes(token)) {
209
- return false;
210
- }
211
- }
212
-
213
- return true;
214
- }
215
-
216
- private normalizePreview(text: string): string {
217
- const singleLine = text.replace(/\s+/g, ' ').trim();
218
- if (singleLine.length <= 60) return singleLine;
219
- return `${singleLine.slice(0, 57)}...`;
220
- }
221
-
222
- private getReplacement(original: string, range: RemovalRange): string {
223
- if (range.kind === 'jsx') {
224
- return '';
225
- }
226
-
227
- const before = range.start > 0 ? original[range.start - 1] : '';
228
- const after = range.end < original.length ? original[range.end] : '';
229
- const isIdentifier = (ch: string): boolean => /[A-Za-z0-9_$]/.test(ch);
230
-
231
- if (isIdentifier(before) && isIdentifier(after)) {
232
- return ' ';
233
- }
234
-
235
- return '';
236
- }
237
-
238
- private buildWhitelist(userList: string[]): Set<string> {
239
- const normalized = userList.map((item) => item.toLowerCase());
240
- return new Set([...this.systemWhitelist, ...normalized]);
241
- }
242
-
243
- private async writeFile(file: string, content: string): Promise<void> {
244
- const absolute = path.resolve(process.cwd(), file);
245
- await fs.writeFile(absolute, content, 'utf8');
246
- }
247
-
248
- private async backupFile(file: string, content: string): Promise<void> {
249
- const backupDir = path.join(process.cwd(), '.kodu', 'backup');
250
- const target = path.join(backupDir, file);
251
- await fs.mkdir(path.dirname(target), { recursive: true });
252
- await fs.writeFile(target, content, 'utf8');
253
- }
254
-
255
- private addRange(
256
- ranges: Map<string, RemovalRange>,
257
- start: number,
258
- end: number,
259
- text: string,
260
- kind: RemovalRange['kind'] = 'comment',
261
- ): void {
262
- const key = `${start}:${end}`;
263
- if (ranges.has(key)) return;
264
- ranges.set(key, { start, end, text, kind });
265
- }
266
-
267
- private collectHtmlCommentRanges(
268
- fullText: string,
269
- ranges: Map<string, RemovalRange>,
270
- ): void {
271
- const htmlCommentRegex = /<!--[\s\S]*?-->/g;
272
- let match: RegExpExecArray | null;
273
-
274
- while (true) {
275
- match = htmlCommentRegex.exec(fullText);
276
- if (!match) {
277
- break;
278
- }
279
- const [text] = match;
280
- if (!text) continue;
281
- this.addRange(ranges, match.index, match.index + text.length, text);
282
- }
283
- }
284
-
285
- private shouldCollectHtmlComments(file: string): boolean {
286
- const extension = path.extname(file).toLowerCase();
287
- return extension === '.html' || extension === '.htm';
288
- }
289
- }
@@ -1,23 +0,0 @@
1
- export type CleanOptions = {
2
- dryRun?: boolean;
3
- backup?: boolean;
4
- keepJSDoc?: boolean;
5
- onProgress?: (current: number, total: number) => void;
6
- };
7
-
8
- export type FileCleanReport = {
9
- file: string;
10
- removed: number;
11
- previews: string[];
12
- bytesBefore: number;
13
- bytesAfter: number;
14
- };
15
-
16
- export type CleanSummary = {
17
- filesProcessed: number;
18
- filesChanged: number;
19
- commentsRemoved: number;
20
- bytesBefore: number;
21
- bytesAfter: number;
22
- reports: FileCleanReport[];
23
- };
@@ -1,118 +0,0 @@
1
- export const MAX_FILE_SIZE_BYTES = 1024 * 1024; // 1 MB
2
- export const DEFAULT_PRICE_PER_MILLION = 5;
3
-
4
- const BINARY_EXTENSION_LIST = [
5
- '.png',
6
- '.jpg',
7
- '.jpeg',
8
- '.webp',
9
- '.gif',
10
- '.bmp',
11
- '.ico',
12
- '.tif',
13
- '.tiff',
14
- '.psd',
15
- '.ai',
16
- '.sketch',
17
- '.heic',
18
- '.heif',
19
- '.mp3',
20
- '.wav',
21
- '.flac',
22
- '.ogg',
23
- '.m4a',
24
- '.mp4',
25
- '.mkv',
26
- '.mov',
27
- '.avi',
28
- '.webm',
29
- '.wmv',
30
- '.flv',
31
- '.mpg',
32
- '.mpeg',
33
- '.ogv',
34
- '.zip',
35
- '.gz',
36
- '.tgz',
37
- '.bz2',
38
- '.xz',
39
- '.rar',
40
- '.7z',
41
- '.tar',
42
- '.pdf',
43
- '.exe',
44
- '.dll',
45
- '.so',
46
- '.dylib',
47
- '.class',
48
- '.jar',
49
- '.war',
50
- '.ear',
51
- '.ttf',
52
- '.otf',
53
- '.woff',
54
- '.woff2',
55
- '.eot',
56
- '.bin',
57
- '.pak',
58
- '.dat',
59
- ];
60
-
61
- const KNOWN_TEXT_LIST = [
62
- // Web / JS
63
- '.js',
64
- '.jsx',
65
- '.ts',
66
- '.tsx',
67
- '.mjs',
68
- '.cjs',
69
- '.json',
70
- '.html',
71
- '.css',
72
- '.scss',
73
- '.less',
74
- '.vue',
75
- '.svelte',
76
- // Backend / System
77
- '.java',
78
- '.py',
79
- '.c',
80
- '.cpp',
81
- '.h',
82
- '.hpp',
83
- '.cs',
84
- '.go',
85
- '.rs',
86
- '.php',
87
- '.rb',
88
- '.swift',
89
- '.kt',
90
- '.dart',
91
- '.scala',
92
- '.pl',
93
- '.lua',
94
- '.sh',
95
- '.bat',
96
- // Data / Docs
97
- '.md',
98
- '.txt',
99
- '.xml',
100
- '.yaml',
101
- '.yml',
102
- '.sql',
103
- '.graphql',
104
- '.toml',
105
- '.ini',
106
- '.env',
107
- // Config
108
- '.gitignore',
109
- '.dockerignore',
110
- 'dockerfile',
111
- '.editorconfig',
112
- ];
113
-
114
- const createLowercaseSet = (values: string[]): ReadonlySet<string> =>
115
- new Set(values.map((value) => value.toLowerCase()));
116
-
117
- export const BINARY_EXTENSIONS = createLowercaseSet(BINARY_EXTENSION_LIST);
118
- export const KNOWN_TEXT_EXTENSIONS = createLowercaseSet(KNOWN_TEXT_LIST);
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { DepsService } from './deps.service';
3
-
4
- @Module({
5
- providers: [DepsService],
6
- exports: [DepsService],
7
- })
8
- export class DepsModule {}
@@ -1,175 +0,0 @@
1
- import path from 'node:path';
2
- import { Injectable } from '@nestjs/common';
3
- import { Project } from 'ts-morph';
4
-
5
- export type DepsResult = {
6
- files: string[];
7
- explain: Map<string, string>;
8
- };
9
-
10
- type CollectOptions = {
11
- maxDepth?: number;
12
- includeTypes?: boolean;
13
- includeDynamic?: boolean;
14
- };
15
-
16
- @Injectable()
17
- export class DepsService {
18
- collectDependencies(
19
- entryFiles: string[],
20
- projectRoot: string,
21
- options: CollectOptions = {},
22
- ): DepsResult {
23
- const {
24
- maxDepth = Infinity,
25
- includeTypes = true,
26
- includeDynamic = false,
27
- } = options;
28
-
29
- const tsConfigPath = this.findTsConfig(projectRoot);
30
- const project = tsConfigPath
31
- ? new Project({
32
- tsConfigFilePath: tsConfigPath,
33
- skipAddingFilesFromTsConfig: true,
34
- })
35
- : new Project({
36
- compilerOptions: {
37
- allowJs: true,
38
- resolveJsonModule: true,
39
- moduleResolution: 2, // NodeJs
40
- },
41
- });
42
-
43
- const visited = new Set<string>();
44
- const explain = new Map<string, string>();
45
-
46
- const absEntries = entryFiles.map((f) =>
47
- path.isAbsolute(f) ? f : path.resolve(projectRoot, f),
48
- );
49
-
50
- for (const entry of absEntries) {
51
- explain.set(entry, 'entry point');
52
- this.collect(
53
- project,
54
- entry,
55
- projectRoot,
56
- visited,
57
- explain,
58
- 0,
59
- maxDepth,
60
- includeTypes,
61
- includeDynamic,
62
- );
63
- }
64
-
65
- const files = [...visited].map((abs) =>
66
- path.relative(projectRoot, abs).split(path.sep).join(path.posix.sep),
67
- );
68
-
69
- return { files, explain };
70
- }
71
-
72
- private collect(
73
- project: Project,
74
- absFile: string,
75
- projectRoot: string,
76
- visited: Set<string>,
77
- explain: Map<string, string>,
78
- depth: number,
79
- maxDepth: number,
80
- includeTypes: boolean,
81
- includeDynamic: boolean,
82
- ): void {
83
- if (visited.has(absFile)) return;
84
- visited.add(absFile);
85
-
86
- if (depth >= maxDepth) return;
87
-
88
- let sourceFile = project.getSourceFile(absFile);
89
- if (!sourceFile) {
90
- try {
91
- sourceFile = project.addSourceFileAtPath(absFile);
92
- } catch {
93
- return;
94
- }
95
- }
96
-
97
- const relFrom = path
98
- .relative(projectRoot, absFile)
99
- .split(path.sep)
100
- .join(path.posix.sep);
101
-
102
- for (const importDecl of sourceFile.getImportDeclarations()) {
103
- if (!includeTypes && importDecl.isTypeOnly()) continue;
104
-
105
- const resolved = importDecl.getModuleSpecifierSourceFile();
106
- if (!resolved) continue;
107
-
108
- const absResolved = resolved.getFilePath();
109
- if (absResolved.includes('node_modules')) continue;
110
-
111
- if (!explain.has(absResolved)) {
112
- const what = importDecl.isTypeOnly() ? 'type import' : 'import';
113
- explain.set(absResolved, `${what} from ${relFrom}`);
114
- }
115
-
116
- this.collect(
117
- project,
118
- absResolved,
119
- projectRoot,
120
- visited,
121
- explain,
122
- depth + 1,
123
- maxDepth,
124
- includeTypes,
125
- includeDynamic,
126
- );
127
- }
128
-
129
- void includeDynamic;
130
-
131
- for (const exportDecl of sourceFile.getExportDeclarations()) {
132
- const resolved = exportDecl.getModuleSpecifierSourceFile();
133
- if (!resolved) continue;
134
-
135
- const absResolved = resolved.getFilePath();
136
- if (absResolved.includes('node_modules')) continue;
137
-
138
- if (!explain.has(absResolved)) {
139
- const relFrom2 = path
140
- .relative(projectRoot, absFile)
141
- .split(path.sep)
142
- .join(path.posix.sep);
143
- explain.set(absResolved, `re-export from ${relFrom2}`);
144
- }
145
-
146
- this.collect(
147
- project,
148
- absResolved,
149
- projectRoot,
150
- visited,
151
- explain,
152
- depth + 1,
153
- maxDepth,
154
- includeTypes,
155
- includeDynamic,
156
- );
157
- }
158
- }
159
-
160
- private findTsConfig(projectRoot: string): string | undefined {
161
- const candidates = [
162
- path.join(projectRoot, 'tsconfig.json'),
163
- path.join(projectRoot, 'tsconfig.base.json'),
164
- ];
165
- for (const c of candidates) {
166
- try {
167
- require('node:fs').accessSync(c);
168
- return c;
169
- } catch {
170
- // not found
171
- }
172
- }
173
- return undefined;
174
- }
175
- }
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { GitService } from './git.service';
3
-
4
- @Module({
5
- providers: [GitService],
6
- exports: [GitService],
7
- })
8
- export class GitModule {}
@@ -1,47 +0,0 @@
1
- import { Injectable } from '@nestjs/common';
2
- import { execa } from 'execa';
3
-
4
- @Injectable()
5
- export class GitService {
6
- async ensureRepo(): Promise<void> {
7
- try {
8
- await execa('git', ['rev-parse', '--is-inside-work-tree']);
9
- } catch (error) {
10
- const message =
11
- error instanceof Error && 'stderr' in error
12
- ? String((error as { stderr?: string }).stderr ?? error.message)
13
- : 'Git repository not found. Initialize git before running the command.';
14
- throw new Error(message);
15
- }
16
- }
17
-
18
- async getChangedFiles(): Promise<string[]> {
19
- await this.ensureRepo();
20
- const changed = new Set<string>();
21
- const load = async (args: string[]) => {
22
- const { stdout } = await execa('git', args);
23
- stdout
24
- .split('\n')
25
- .map((entry) => entry.trim())
26
- .filter((entry) => entry.length > 0)
27
- .forEach((entry) => {
28
- changed.add(entry);
29
- });
30
- };
31
-
32
- await load(['diff', '--name-only']);
33
- await load(['diff', '--name-only', '--staged']);
34
- await load(['ls-files', '--others', '--exclude-standard']);
35
- return [...changed].sort();
36
- }
37
-
38
- async getStagedFiles(): Promise<string[]> {
39
- await this.ensureRepo();
40
- const { stdout } = await execa('git', ['diff', '--name-only', '--staged']);
41
- return stdout
42
- .split('\n')
43
- .map((entry) => entry.trim())
44
- .filter((entry) => entry.length > 0)
45
- .sort();
46
- }
47
- }
@@ -1,9 +0,0 @@
1
- import { Global, Module } from '@nestjs/common';
2
- import { RunbookService } from './runbook.service';
3
-
4
- @Global()
5
- @Module({
6
- providers: [RunbookService],
7
- exports: [RunbookService],
8
- })
9
- export class RunbookModule {}