kodu 2.2.0 → 3.0.2

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 (234) hide show
  1. package/README.md +24 -3
  2. package/bin/kodu.js +40 -0
  3. package/package.json +12 -67
  4. package/scripts/install.js +68 -0
  5. package/scripts/postinstall.js +22 -0
  6. package/AGENTS.md +0 -214
  7. package/__tests__/core/fs/fs.service.test.ts +0 -72
  8. package/__tests__/core/registry/registry.service.test.ts +0 -82
  9. package/__tests__/shared/cleaner/cleaner.service.test.ts +0 -102
  10. package/__tests__/shared/git/git.service.test.ts +0 -84
  11. package/__tests__/shared/runbook/runbook.service.test.ts +0 -104
  12. package/__tests__/shared/tokenizer/tokenizer.service.test.ts +0 -45
  13. package/biome.json +0 -50
  14. package/dist/package.json +0 -96
  15. package/dist/src/app.module.d.ts +0 -2
  16. package/dist/src/app.module.js +0 -42
  17. package/dist/src/app.module.js.map +0 -1
  18. package/dist/src/commands/clean/clean.command.d.ts +0 -37
  19. package/dist/src/commands/clean/clean.command.js +0 -240
  20. package/dist/src/commands/clean/clean.command.js.map +0 -1
  21. package/dist/src/commands/clean/clean.module.d.ts +0 -2
  22. package/dist/src/commands/clean/clean.module.js +0 -26
  23. package/dist/src/commands/clean/clean.module.js.map +0 -1
  24. package/dist/src/commands/init/init.command.d.ts +0 -10
  25. package/dist/src/commands/init/init.command.js +0 -96
  26. package/dist/src/commands/init/init.command.js.map +0 -1
  27. package/dist/src/commands/init/init.module.d.ts +0 -2
  28. package/dist/src/commands/init/init.module.js +0 -22
  29. package/dist/src/commands/init/init.module.js.map +0 -1
  30. package/dist/src/commands/ops/ops-add.command.d.ts +0 -18
  31. package/dist/src/commands/ops/ops-add.command.js +0 -102
  32. package/dist/src/commands/ops/ops-add.command.js.map +0 -1
  33. package/dist/src/commands/ops/ops-init.command.d.ts +0 -22
  34. package/dist/src/commands/ops/ops-init.command.js +0 -130
  35. package/dist/src/commands/ops/ops-init.command.js.map +0 -1
  36. package/dist/src/commands/ops/ops-list.command.d.ts +0 -12
  37. package/dist/src/commands/ops/ops-list.command.js +0 -73
  38. package/dist/src/commands/ops/ops-list.command.js.map +0 -1
  39. package/dist/src/commands/ops/ops-path.command.d.ts +0 -9
  40. package/dist/src/commands/ops/ops-path.command.js +0 -52
  41. package/dist/src/commands/ops/ops-path.command.js.map +0 -1
  42. package/dist/src/commands/ops/ops-runbook.command.d.ts +0 -12
  43. package/dist/src/commands/ops/ops-runbook.command.js +0 -81
  44. package/dist/src/commands/ops/ops-runbook.command.js.map +0 -1
  45. package/dist/src/commands/ops/ops-status.command.d.ts +0 -11
  46. package/dist/src/commands/ops/ops-status.command.js +0 -62
  47. package/dist/src/commands/ops/ops-status.command.js.map +0 -1
  48. package/dist/src/commands/ops/ops-use.command.d.ts +0 -12
  49. package/dist/src/commands/ops/ops-use.command.js +0 -76
  50. package/dist/src/commands/ops/ops-use.command.js.map +0 -1
  51. package/dist/src/commands/ops/ops.command.d.ts +0 -7
  52. package/dist/src/commands/ops/ops.command.js +0 -56
  53. package/dist/src/commands/ops/ops.command.js.map +0 -1
  54. package/dist/src/commands/ops/ops.helpers.d.ts +0 -2
  55. package/dist/src/commands/ops/ops.helpers.js +0 -11
  56. package/dist/src/commands/ops/ops.helpers.js.map +0 -1
  57. package/dist/src/commands/ops/ops.module.d.ts +0 -2
  58. package/dist/src/commands/ops/ops.module.js +0 -36
  59. package/dist/src/commands/ops/ops.module.js.map +0 -1
  60. package/dist/src/commands/pack/pack.command.d.ts +0 -51
  61. package/dist/src/commands/pack/pack.command.js +0 -355
  62. package/dist/src/commands/pack/pack.command.js.map +0 -1
  63. package/dist/src/commands/pack/pack.module.d.ts +0 -2
  64. package/dist/src/commands/pack/pack.module.js +0 -27
  65. package/dist/src/commands/pack/pack.module.js.map +0 -1
  66. package/dist/src/core/config/config.module.d.ts +0 -2
  67. package/dist/src/core/config/config.module.js +0 -23
  68. package/dist/src/core/config/config.module.js.map +0 -1
  69. package/dist/src/core/config/config.schema.d.ts +0 -19
  70. package/dist/src/core/config/config.schema.js +0 -56
  71. package/dist/src/core/config/config.schema.js.map +0 -1
  72. package/dist/src/core/config/config.service.d.ts +0 -7
  73. package/dist/src/core/config/config.service.js +0 -49
  74. package/dist/src/core/config/config.service.js.map +0 -1
  75. package/dist/src/core/config/prompt.service.d.ts +0 -10
  76. package/dist/src/core/config/prompt.service.js +0 -80
  77. package/dist/src/core/config/prompt.service.js.map +0 -1
  78. package/dist/src/core/file-system/fs.module.d.ts +0 -2
  79. package/dist/src/core/file-system/fs.module.js +0 -21
  80. package/dist/src/core/file-system/fs.module.js.map +0 -1
  81. package/dist/src/core/file-system/fs.service.d.ts +0 -27
  82. package/dist/src/core/file-system/fs.service.js +0 -203
  83. package/dist/src/core/file-system/fs.service.js.map +0 -1
  84. package/dist/src/core/registry/registry.module.d.ts +0 -2
  85. package/dist/src/core/registry/registry.module.js +0 -22
  86. package/dist/src/core/registry/registry.module.js.map +0 -1
  87. package/dist/src/core/registry/registry.schema.d.ts +0 -24
  88. package/dist/src/core/registry/registry.schema.js +0 -21
  89. package/dist/src/core/registry/registry.schema.js.map +0 -1
  90. package/dist/src/core/registry/registry.service.d.ts +0 -16
  91. package/dist/src/core/registry/registry.service.js +0 -91
  92. package/dist/src/core/registry/registry.service.js.map +0 -1
  93. package/dist/src/core/ui/ui.module.d.ts +0 -2
  94. package/dist/src/core/ui/ui.module.js +0 -22
  95. package/dist/src/core/ui/ui.module.js.map +0 -1
  96. package/dist/src/core/ui/ui.service.d.ts +0 -22
  97. package/dist/src/core/ui/ui.service.js +0 -43
  98. package/dist/src/core/ui/ui.service.js.map +0 -1
  99. package/dist/src/main.d.ts +0 -2
  100. package/dist/src/main.js +0 -16
  101. package/dist/src/main.js.map +0 -1
  102. package/dist/src/shared/cleaner/cleaner.service.d.ts +0 -23
  103. package/dist/src/shared/cleaner/cleaner.service.js +0 -223
  104. package/dist/src/shared/cleaner/cleaner.service.js.map +0 -1
  105. package/dist/src/shared/cleaner/cleaner.types.d.ts +0 -21
  106. package/dist/src/shared/cleaner/cleaner.types.js +0 -3
  107. package/dist/src/shared/cleaner/cleaner.types.js.map +0 -1
  108. package/dist/src/shared/constants.d.ts +0 -4
  109. package/dist/src/shared/constants.js +0 -113
  110. package/dist/src/shared/constants.js.map +0 -1
  111. package/dist/src/shared/deps/deps.module.d.ts +0 -2
  112. package/dist/src/shared/deps/deps.module.js +0 -21
  113. package/dist/src/shared/deps/deps.module.js.map +0 -1
  114. package/dist/src/shared/deps/deps.service.d.ts +0 -15
  115. package/dist/src/shared/deps/deps.service.js +0 -114
  116. package/dist/src/shared/deps/deps.service.js.map +0 -1
  117. package/dist/src/shared/git/git.module.d.ts +0 -2
  118. package/dist/src/shared/git/git.module.js +0 -21
  119. package/dist/src/shared/git/git.module.js.map +0 -1
  120. package/dist/src/shared/git/git.service.d.ts +0 -5
  121. package/dist/src/shared/git/git.service.js +0 -56
  122. package/dist/src/shared/git/git.service.js.map +0 -1
  123. package/dist/src/shared/runbook/runbook.module.d.ts +0 -2
  124. package/dist/src/shared/runbook/runbook.module.js +0 -22
  125. package/dist/src/shared/runbook/runbook.module.js.map +0 -1
  126. package/dist/src/shared/runbook/runbook.service.d.ts +0 -20
  127. package/dist/src/shared/runbook/runbook.service.js +0 -118
  128. package/dist/src/shared/runbook/runbook.service.js.map +0 -1
  129. package/dist/src/shared/runbook/runbook.templates.d.ts +0 -6
  130. package/dist/src/shared/runbook/runbook.templates.js +0 -49
  131. package/dist/src/shared/runbook/runbook.templates.js.map +0 -1
  132. package/dist/src/shared/tokenizer/tokenizer.module.d.ts +0 -2
  133. package/dist/src/shared/tokenizer/tokenizer.module.js +0 -21
  134. package/dist/src/shared/tokenizer/tokenizer.module.js.map +0 -1
  135. package/dist/src/shared/tokenizer/tokenizer.service.d.ts +0 -10
  136. package/dist/src/shared/tokenizer/tokenizer.service.js +0 -36
  137. package/dist/src/shared/tokenizer/tokenizer.service.js.map +0 -1
  138. package/dist/tsconfig.build.tsbuildinfo +0 -1
  139. package/docs/todo.md +0 -7
  140. package/knip.json +0 -10
  141. package/kodu.json +0 -63
  142. package/kodu.schema.json +0 -100
  143. package/lefthook.yml +0 -11
  144. package/nest-cli.json +0 -8
  145. package/registry.schema.json +0 -39
  146. package/scripts/generate-json-schema.ts +0 -27
  147. package/skills/ac/SKILL.md +0 -239
  148. package/skills/al/SKILL.md +0 -98
  149. package/skills/audit/SKILL.md +0 -205
  150. package/skills/audit/audit-baseline-template.yml +0 -188
  151. package/skills/audit/runtime-detect.md +0 -64
  152. package/skills/audit/stacks/_generic.md +0 -41
  153. package/skills/audit/stacks/_registry.md +0 -47
  154. package/skills/audit/stacks/go.md +0 -66
  155. package/skills/audit/stacks/java.md +0 -44
  156. package/skills/audit/stacks/node.md +0 -57
  157. package/skills/audit/stacks/python.md +0 -45
  158. package/skills/audit/stacks/rust.md +0 -44
  159. package/skills/audit-api-contracts/SKILL.md +0 -201
  160. package/skills/audit-architecture/SKILL.md +0 -200
  161. package/skills/audit-bugs/SKILL.md +0 -226
  162. package/skills/audit-concurrency/SKILL.md +0 -197
  163. package/skills/audit-deployment/SKILL.md +0 -218
  164. package/skills/audit-docs/SKILL.md +0 -209
  165. package/skills/audit-errors/SKILL.md +0 -216
  166. package/skills/audit-logging/SKILL.md +0 -197
  167. package/skills/audit-matrix/SKILL.md +0 -245
  168. package/skills/audit-meta/SKILL.md +0 -120
  169. package/skills/audit-naming/SKILL.md +0 -200
  170. package/skills/audit-owasp/SKILL.md +0 -223
  171. package/skills/audit-performance/SKILL.md +0 -199
  172. package/skills/audit-reinvention/SKILL.md +0 -214
  173. package/skills/audit-secrets/SKILL.md +0 -198
  174. package/skills/audit-tests/SKILL.md +0 -210
  175. package/skills/audit-validation/SKILL.md +0 -206
  176. package/skills/audit-verify/SKILL.md +0 -139
  177. package/skills/audit-yagni/SKILL.md +0 -188
  178. package/skills/doc-gen/SKILL.md +0 -490
  179. package/skills/doc-gen/scripts/doc_gen.py +0 -911
  180. package/skills/generate-project-docs/SKILL.md +0 -380
  181. package/skills/implement-project/SKILL.md +0 -409
  182. package/skills/liteend-init/SKILL.md +0 -84
  183. package/skills/litefront-init/SKILL.md +0 -96
  184. package/skills/litefront-prototype/SKILL.md +0 -484
  185. package/skills/ops/SKILL.md +0 -94
  186. package/skills/post-call-task-builder/SKILL.md +0 -419
  187. package/skills/project-setup-standardizer/SKILL.md +0 -285
  188. package/skills/skills-best-practices/SKILL.md +0 -415
  189. package/skills/start/SKILL.md +0 -319
  190. package/skills/tech-blueprint/SKILL.md +0 -890
  191. package/skills/tech-blueprint/scripts/blueprint_validator.py +0 -417
  192. package/src/app.module.ts +0 -29
  193. package/src/commands/clean/clean.command.ts +0 -235
  194. package/src/commands/clean/clean.module.ts +0 -13
  195. package/src/commands/init/init.command.ts +0 -92
  196. package/src/commands/init/init.module.ts +0 -9
  197. package/src/commands/ops/ops-add.command.ts +0 -83
  198. package/src/commands/ops/ops-init.command.ts +0 -125
  199. package/src/commands/ops/ops-list.command.ts +0 -57
  200. package/src/commands/ops/ops-path.command.ts +0 -38
  201. package/src/commands/ops/ops-runbook.command.ts +0 -74
  202. package/src/commands/ops/ops-status.command.ts +0 -47
  203. package/src/commands/ops/ops-use.command.ts +0 -76
  204. package/src/commands/ops/ops.command.ts +0 -42
  205. package/src/commands/ops/ops.helpers.ts +0 -20
  206. package/src/commands/ops/ops.module.ts +0 -23
  207. package/src/commands/pack/pack.command.ts +0 -347
  208. package/src/commands/pack/pack.module.ts +0 -14
  209. package/src/core/config/config.module.ts +0 -10
  210. package/src/core/config/config.schema.ts +0 -58
  211. package/src/core/config/config.service.ts +0 -43
  212. package/src/core/config/prompt.service.ts +0 -80
  213. package/src/core/file-system/fs.module.ts +0 -8
  214. package/src/core/file-system/fs.service.ts +0 -248
  215. package/src/core/registry/registry.module.ts +0 -9
  216. package/src/core/registry/registry.schema.ts +0 -46
  217. package/src/core/registry/registry.service.ts +0 -128
  218. package/src/core/ui/ui.module.ts +0 -9
  219. package/src/core/ui/ui.service.ts +0 -39
  220. package/src/main.ts +0 -12
  221. package/src/shared/cleaner/cleaner.service.ts +0 -289
  222. package/src/shared/cleaner/cleaner.types.ts +0 -23
  223. package/src/shared/constants.ts +0 -118
  224. package/src/shared/deps/deps.module.ts +0 -8
  225. package/src/shared/deps/deps.service.ts +0 -175
  226. package/src/shared/git/git.module.ts +0 -8
  227. package/src/shared/git/git.service.ts +0 -47
  228. package/src/shared/runbook/runbook.module.ts +0 -9
  229. package/src/shared/runbook/runbook.service.ts +0 -164
  230. package/src/shared/runbook/runbook.templates.ts +0 -66
  231. package/src/shared/tokenizer/tokenizer.module.ts +0 -8
  232. package/src/shared/tokenizer/tokenizer.service.ts +0 -30
  233. package/tsconfig.build.json +0 -7
  234. 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 {}