@massu/core 1.10.7 → 1.12.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 (177) hide show
  1. package/CHANGELOG.md +1303 -0
  2. package/dist/adapter.js +6 -4
  3. package/dist/cli.js +559 -400
  4. package/dist/detect/adapters/.bundle-shasums.json +4 -7
  5. package/dist/detect/adapters/rails.js +6 -4
  6. package/dist/detect/adapters/spring.js +6 -4
  7. package/dist/detect/adapters/tree-sitter-loader.js +6 -4
  8. package/dist/hooks/auto-learning-pipeline.js +24 -1
  9. package/dist/hooks/classify-failure.js +32 -3
  10. package/dist/hooks/cost-tracker.js +24 -0
  11. package/dist/hooks/fix-detector.js +97 -1
  12. package/dist/hooks/incident-pipeline.js +30 -1
  13. package/dist/hooks/intent-suggester.js +6 -3
  14. package/dist/hooks/post-edit-context.js +24 -1
  15. package/dist/hooks/post-tool-use.js +66 -18
  16. package/dist/hooks/pre-compact.js +27 -2
  17. package/dist/hooks/pre-delete-check.js +48 -22
  18. package/dist/hooks/pre-tool-use-gate.js +962 -0
  19. package/dist/hooks/quality-event.js +24 -0
  20. package/dist/hooks/rule-enforcement-pipeline.js +24 -1
  21. package/dist/hooks/security-gate.js +29 -16
  22. package/dist/hooks/session-end.js +24 -0
  23. package/dist/hooks/session-start.js +8710 -8460
  24. package/dist/hooks/user-prompt.js +24 -0
  25. package/package.json +15 -18
  26. package/commands/README.md +0 -134
  27. package/src/adapter.ts +0 -121
  28. package/src/adr-generator.ts +0 -292
  29. package/src/analytics.ts +0 -373
  30. package/src/audit-trail.ts +0 -450
  31. package/src/backfill-sessions.ts +0 -182
  32. package/src/changelog-generator.ts +0 -178
  33. package/src/cli.ts +0 -246
  34. package/src/cloud-sync.ts +0 -234
  35. package/src/commands/adapters.ts +0 -824
  36. package/src/commands/changelog.ts +0 -165
  37. package/src/commands/config-check-drift.ts +0 -133
  38. package/src/commands/config-refresh.ts +0 -396
  39. package/src/commands/config-upgrade.ts +0 -127
  40. package/src/commands/doctor.ts +0 -485
  41. package/src/commands/hook-runner.ts +0 -145
  42. package/src/commands/init.ts +0 -1823
  43. package/src/commands/install-commands.ts +0 -692
  44. package/src/commands/install-hooks.ts +0 -27
  45. package/src/commands/permissions.ts +0 -150
  46. package/src/commands/refresh-log.ts +0 -37
  47. package/src/commands/show-template.ts +0 -65
  48. package/src/commands/template-engine.ts +0 -301
  49. package/src/commands/watch.ts +0 -430
  50. package/src/config.ts +0 -765
  51. package/src/cost-tracker.ts +0 -355
  52. package/src/db.ts +0 -370
  53. package/src/dependency-scorer.ts +0 -337
  54. package/src/detect/adapters/aspnet.ts +0 -4
  55. package/src/detect/adapters/discover.ts +0 -469
  56. package/src/detect/adapters/file-sampler.ts +0 -225
  57. package/src/detect/adapters/go-chi.ts +0 -4
  58. package/src/detect/adapters/index.ts +0 -51
  59. package/src/detect/adapters/nextjs-trpc.ts +0 -166
  60. package/src/detect/adapters/parse-guard.ts +0 -133
  61. package/src/detect/adapters/phoenix.ts +0 -4
  62. package/src/detect/adapters/python-django.ts +0 -208
  63. package/src/detect/adapters/python-fastapi.ts +0 -223
  64. package/src/detect/adapters/python-flask.ts +0 -235
  65. package/src/detect/adapters/query-helpers.ts +0 -170
  66. package/src/detect/adapters/rails.ts +0 -4
  67. package/src/detect/adapters/runner.ts +0 -284
  68. package/src/detect/adapters/spring.ts +0 -4
  69. package/src/detect/adapters/swift-swiftui.ts +0 -171
  70. package/src/detect/adapters/tree-sitter-loader.ts +0 -517
  71. package/src/detect/adapters/types.ts +0 -191
  72. package/src/detect/codebase-introspector.ts +0 -210
  73. package/src/detect/domain-inferrer.ts +0 -197
  74. package/src/detect/drift.ts +0 -199
  75. package/src/detect/framework-detector.ts +0 -307
  76. package/src/detect/index.ts +0 -209
  77. package/src/detect/manifest-registry.ts +0 -261
  78. package/src/detect/migrate.ts +0 -362
  79. package/src/detect/monorepo-detector.ts +0 -348
  80. package/src/detect/package-detector.ts +0 -828
  81. package/src/detect/passthrough.ts +0 -108
  82. package/src/detect/regex-fallback.ts +0 -449
  83. package/src/detect/source-dir-detector.ts +0 -297
  84. package/src/detect/vr-command-map.ts +0 -167
  85. package/src/docs-map.json +0 -100
  86. package/src/docs-tools.ts +0 -519
  87. package/src/domains.ts +0 -182
  88. package/src/hooks/auto-learning-pipeline.ts +0 -228
  89. package/src/hooks/classify-failure.ts +0 -259
  90. package/src/hooks/cost-tracker.ts +0 -66
  91. package/src/hooks/fix-detector.ts +0 -186
  92. package/src/hooks/incident-pipeline.ts +0 -190
  93. package/src/hooks/intent-suggester.ts +0 -131
  94. package/src/hooks/post-edit-context.ts +0 -91
  95. package/src/hooks/post-tool-use.ts +0 -413
  96. package/src/hooks/pre-compact.ts +0 -168
  97. package/src/hooks/pre-delete-check.ts +0 -243
  98. package/src/hooks/quality-event.ts +0 -127
  99. package/src/hooks/rule-enforcement-pipeline.ts +0 -159
  100. package/src/hooks/security-gate.ts +0 -153
  101. package/src/hooks/session-end.ts +0 -467
  102. package/src/hooks/session-start.ts +0 -436
  103. package/src/hooks/user-prompt.ts +0 -157
  104. package/src/import-resolver.ts +0 -226
  105. package/src/knowledge-db.ts +0 -176
  106. package/src/knowledge-indexer.ts +0 -708
  107. package/src/knowledge-tools.ts +0 -1414
  108. package/src/lib/fileLock.ts +0 -203
  109. package/src/lib/gitToplevel.ts +0 -22
  110. package/src/lib/hook-registry.ts +0 -43
  111. package/src/lib/installLock.ts +0 -66
  112. package/src/lib/memory-path.ts +0 -49
  113. package/src/lib/pidLiveness.ts +0 -67
  114. package/src/lib/settings-local.ts +0 -110
  115. package/src/lib/sql-table-names.ts +0 -71
  116. package/src/license.ts +0 -547
  117. package/src/lsp/auto-detect.ts +0 -98
  118. package/src/lsp/client.ts +0 -776
  119. package/src/lsp/enrich.ts +0 -127
  120. package/src/lsp/types.ts +0 -221
  121. package/src/memory-db.ts +0 -1614
  122. package/src/memory-file-ingest.ts +0 -128
  123. package/src/memory-tools.ts +0 -424
  124. package/src/middleware-tree.ts +0 -71
  125. package/src/observability-tools.ts +0 -343
  126. package/src/observation-extractor.ts +0 -418
  127. package/src/page-deps.ts +0 -285
  128. package/src/permissions.ts +0 -422
  129. package/src/prompt-analyzer.ts +0 -332
  130. package/src/python/coupling-detector.ts +0 -125
  131. package/src/python/domain-enforcer.ts +0 -84
  132. package/src/python/impact-analyzer.ts +0 -96
  133. package/src/python/import-parser.ts +0 -244
  134. package/src/python/import-resolver.ts +0 -136
  135. package/src/python/migration-indexer.ts +0 -116
  136. package/src/python/migration-parser.ts +0 -332
  137. package/src/python/model-indexer.ts +0 -71
  138. package/src/python/model-parser.ts +0 -279
  139. package/src/python/route-indexer.ts +0 -59
  140. package/src/python/route-parser.ts +0 -317
  141. package/src/python-tools.ts +0 -630
  142. package/src/regression-detector.ts +0 -319
  143. package/src/rules.ts +0 -57
  144. package/src/schema-mapper.ts +0 -232
  145. package/src/security/adapter-origin.ts +0 -130
  146. package/src/security/adapter-verifier.ts +0 -319
  147. package/src/security/atomic-write.ts +0 -164
  148. package/src/security/fetcher.ts +0 -200
  149. package/src/security/install-tracking.ts +0 -319
  150. package/src/security/license-pubkey.generated.ts +0 -30
  151. package/src/security/license-response-verifier.ts +0 -149
  152. package/src/security/local-fingerprint.ts +0 -225
  153. package/src/security/manifest-cache.ts +0 -333
  154. package/src/security/manifest-schema.ts +0 -129
  155. package/src/security/registry-pubkey.generated.ts +0 -35
  156. package/src/security/telemetry.ts +0 -320
  157. package/src/security-scorer.ts +0 -405
  158. package/src/security-utils.ts +0 -133
  159. package/src/sentinel-db.ts +0 -580
  160. package/src/sentinel-scanner.ts +0 -406
  161. package/src/sentinel-tools.ts +0 -513
  162. package/src/sentinel-types.ts +0 -140
  163. package/src/server-dispatch.ts +0 -225
  164. package/src/server.ts +0 -107
  165. package/src/session-archiver.ts +0 -111
  166. package/src/session-state-generator.ts +0 -174
  167. package/src/team-knowledge.ts +0 -407
  168. package/src/tool-db-needs.ts +0 -232
  169. package/src/tools.ts +0 -1205
  170. package/src/transcript-parser.ts +0 -458
  171. package/src/trpc-index.ts +0 -215
  172. package/src/validate-features-runner.ts +0 -107
  173. package/src/validation-engine.ts +0 -358
  174. package/src/watch/daemon.ts +0 -385
  175. package/src/watch/lockfile-detector.ts +0 -65
  176. package/src/watch/paths.ts +0 -279
  177. package/src/watch/state.ts +0 -178
@@ -1,59 +0,0 @@
1
- // Copyright (c) 2026 Massu. All rights reserved.
2
- // Licensed under BSL 1.1 - see LICENSE file for details.
3
-
4
- import { readFileSync, readdirSync } from 'fs';
5
- import { join, relative } from 'path';
6
- import type Database from 'better-sqlite3';
7
- import { parsePythonRoutes } from './route-parser.ts';
8
- import { getProjectRoot } from '../config.ts';
9
- import { t } from '../lib/sql-table-names.ts';
10
-
11
- function walkPyFiles(dir: string, excludeDirs: string[]): string[] {
12
- const files: string[] = [];
13
- try {
14
- const entries = readdirSync(dir, { withFileTypes: true });
15
- for (const entry of entries) {
16
- if (entry.isDirectory()) {
17
- if (excludeDirs.includes(entry.name)) continue;
18
- files.push(...walkPyFiles(join(dir, entry.name), excludeDirs));
19
- } else if (entry.name.endsWith('.py')) {
20
- files.push(join(dir, entry.name));
21
- }
22
- }
23
- } catch { /* dir not readable, skip */ }
24
- return files;
25
- }
26
-
27
- export function buildPythonRouteIndex(dataDb: Database.Database, pythonRoot: string, excludeDirs: string[] = ['__pycache__', '.venv', 'venv', '.mypy_cache', '.pytest_cache']): number {
28
- const projectRoot = getProjectRoot();
29
- const absRoot = join(projectRoot, pythonRoot);
30
- dataDb.exec(`DELETE FROM ${t('py_routes')}`);
31
- dataDb.exec(`DELETE FROM ${t('py_route_callers')}`);
32
-
33
- const insertStmt = dataDb.prepare(
34
- `INSERT INTO ${t('py_routes')} (file, method, path, function_name, dependencies, request_model, response_model, is_authenticated, line) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
35
- );
36
-
37
- const files = walkPyFiles(absRoot, excludeDirs);
38
- let count = 0;
39
-
40
- dataDb.transaction(() => {
41
- for (const absFile of files) {
42
- const relFile = relative(projectRoot, absFile);
43
- let source: string;
44
- try { source = readFileSync(absFile, 'utf-8'); } catch { continue; }
45
-
46
- const routes = parsePythonRoutes(source);
47
- for (const route of routes) {
48
- insertStmt.run(
49
- relFile, route.method, route.path, route.functionName,
50
- JSON.stringify(route.dependencies), route.requestModel, route.responseModel,
51
- route.isAuthenticated ? 1 : 0, route.line
52
- );
53
- count++;
54
- }
55
- }
56
- })();
57
-
58
- return count;
59
- }
@@ -1,317 +0,0 @@
1
- // Copyright (c) 2026 Massu. All rights reserved.
2
- // Licensed under BSL 1.1 - see LICENSE file for details.
3
-
4
- export interface ParsedRoute {
5
- method: string;
6
- path: string;
7
- functionName: string;
8
- dependencies: string[];
9
- requestModel: string | null;
10
- responseModel: string | null;
11
- isAuthenticated: boolean;
12
- line: number;
13
- }
14
-
15
- const HTTP_METHODS = new Set([
16
- 'get',
17
- 'post',
18
- 'put',
19
- 'delete',
20
- 'patch',
21
- 'options',
22
- 'head',
23
- ]);
24
-
25
- const BASIC_TYPES = new Set([
26
- 'str',
27
- 'int',
28
- 'float',
29
- 'bool',
30
- 'bytes',
31
- 'list',
32
- 'dict',
33
- 'set',
34
- 'tuple',
35
- 'Any',
36
- 'None',
37
- 'Optional',
38
- 'Request',
39
- 'Response',
40
- 'Query',
41
- 'Path',
42
- 'Header',
43
- 'Cookie',
44
- 'Body',
45
- 'Form',
46
- 'File',
47
- 'UploadFile',
48
- 'BackgroundTasks',
49
- 'HTTPException',
50
- 'Depends',
51
- 'Session',
52
- 'AsyncSession',
53
- ]);
54
-
55
- /**
56
- * Join logical lines that are split across multiple physical lines.
57
- * Handles backslash continuations and unclosed parentheses/brackets.
58
- */
59
- function joinLogicalLines(source: string): { text: string; startLine: number }[] {
60
- const physicalLines = source.split('\n');
61
- const logical: { text: string; startLine: number }[] = [];
62
- let current = '';
63
- let startLine = 0;
64
- let openParens = 0;
65
- let openBrackets = 0;
66
-
67
- for (let i = 0; i < physicalLines.length; i++) {
68
- const raw = physicalLines[i];
69
- if (current === '') {
70
- startLine = i + 1; // 1-based
71
- }
72
-
73
- // Strip trailing backslash continuation
74
- const continued = raw.trimEnd().endsWith('\\');
75
- const line = continued ? raw.trimEnd().slice(0, -1) : raw;
76
-
77
- current += (current ? ' ' : '') + line;
78
-
79
- // Count parens/brackets (ignoring those inside strings for simplicity)
80
- for (const ch of line) {
81
- if (ch === '(') openParens++;
82
- else if (ch === ')') openParens = Math.max(0, openParens - 1);
83
- else if (ch === '[') openBrackets++;
84
- else if (ch === ']') openBrackets = Math.max(0, openBrackets - 1);
85
- }
86
-
87
- if (!continued && openParens === 0 && openBrackets === 0) {
88
- logical.push({ text: current, startLine });
89
- current = '';
90
- }
91
- }
92
-
93
- if (current) {
94
- logical.push({ text: current, startLine });
95
- }
96
-
97
- return logical;
98
- }
99
-
100
- /**
101
- * Extract the first quoted string from a text segment.
102
- */
103
- function extractQuotedString(text: string): string | null {
104
- const m = text.match(/(['"])(.*?)\1/);
105
- return m ? m[2] : null;
106
- }
107
-
108
- /**
109
- * Extract response_model value from a decorator argument string.
110
- */
111
- function extractResponseModel(argStr: string): string | null {
112
- const m = argStr.match(/response_model\s*=\s*([A-Za-z_][A-Za-z0-9_.\[\]]*)/);
113
- return m ? m[1] : null;
114
- }
115
-
116
- /**
117
- * Extract methods list from api_route decorator.
118
- */
119
- function extractApiRouteMethods(argStr: string): string[] {
120
- const m = argStr.match(/methods\s*=\s*\[([^\]]*)\]/);
121
- if (!m) return [];
122
- const inner = m[1];
123
- const methods: string[] = [];
124
- const re = /['"](\w+)['"]/g;
125
- let match;
126
- while ((match = re.exec(inner)) !== null) {
127
- methods.push(match[1].toUpperCase());
128
- }
129
- return methods;
130
- }
131
-
132
- /**
133
- * Parse Depends() calls from function parameters.
134
- */
135
- function extractDependencies(paramStr: string): string[] {
136
- const deps: string[] = [];
137
- const re = /Depends\(\s*([A-Za-z_][A-Za-z0-9_.]*)\s*\)/g;
138
- let match;
139
- while ((match = re.exec(paramStr)) !== null) {
140
- deps.push(match[1]);
141
- }
142
- return deps;
143
- }
144
-
145
- /**
146
- * Parse function parameters for request body models.
147
- * A request body parameter is a type-annotated param whose type is not
148
- * a basic/framework type and not assigned via Depends/Query/Path/etc.
149
- */
150
- function extractRequestModel(paramStr: string): string | null {
151
- // Split params by comma, respecting nested parens
152
- const params = splitParams(paramStr);
153
-
154
- for (const param of params) {
155
- const trimmed = param.trim();
156
- // Skip self, cls, *args, **kwargs
157
- if (/^(self|cls|\*\*?\w*)$/.test(trimmed.split(/[\s:=]/)[0].trim())) continue;
158
- // Skip if has Depends, Query, Path, Header, Cookie, Form, File, Body assignment
159
- if (/=\s*(Depends|Query|Path|Header|Cookie|Form|File|Body)\s*\(/.test(trimmed)) continue;
160
-
161
- // Look for type annotation: name: Type
162
- const annotationMatch = trimmed.match(/^\s*(\w+)\s*:\s*([A-Za-z_][A-Za-z0-9_.\[\]|]*)/);
163
- if (annotationMatch) {
164
- const typeName = annotationMatch[2].replace(/\s/g, '');
165
- // Strip Optional[], List[], etc wrappers to get base type
166
- const baseType = typeName.replace(/^(Optional|List|Set|Tuple|Dict)\[/, '').replace(/\]$/, '').split('[')[0].split('|')[0];
167
- if (!BASIC_TYPES.has(baseType) && /^[A-Z]/.test(baseType)) {
168
- return baseType;
169
- }
170
- }
171
- }
172
- return null;
173
- }
174
-
175
- /**
176
- * Split parameter string by top-level commas (not inside parens/brackets).
177
- */
178
- function splitParams(paramStr: string): string[] {
179
- const parts: string[] = [];
180
- let current = '';
181
- let depth = 0;
182
-
183
- for (const ch of paramStr) {
184
- if (ch === '(' || ch === '[') depth++;
185
- else if (ch === ')' || ch === ']') depth = Math.max(0, depth - 1);
186
- else if (ch === ',' && depth === 0) {
187
- parts.push(current);
188
- current = '';
189
- continue;
190
- }
191
- current += ch;
192
- }
193
- if (current.trim()) parts.push(current);
194
- return parts;
195
- }
196
-
197
- /**
198
- * Parse FastAPI route decorators and their handler functions from Python source code.
199
- */
200
- export function parsePythonRoutes(source: string): ParsedRoute[] {
201
- const routes: ParsedRoute[] = [];
202
- const logicalLines = joinLogicalLines(source);
203
-
204
- // Collect pending decorators, then match them to function defs
205
- interface PendingDecorator {
206
- method: string;
207
- path: string;
208
- responseModel: string | null;
209
- methods: string[]; // for api_route
210
- line: number;
211
- }
212
-
213
- const pendingDecorators: PendingDecorator[] = [];
214
-
215
- for (let i = 0; i < logicalLines.length; i++) {
216
- const { text, startLine } = logicalLines[i];
217
- const trimmed = text.trim();
218
-
219
- // Detect route decorator: @variable.method("path" ...) or @variable.api_route(...)
220
- const decoratorMatch = trimmed.match(
221
- /^@\s*(\w+)\s*\.\s*(\w+)\s*\((.*)\)\s*$/s,
222
- );
223
-
224
- if (decoratorMatch) {
225
- const methodName = decoratorMatch[2].toLowerCase();
226
- const argStr = decoratorMatch[3];
227
-
228
- if (methodName === 'api_route') {
229
- const path = extractQuotedString(argStr);
230
- if (path) {
231
- const methods = extractApiRouteMethods(argStr);
232
- const responseModel = extractResponseModel(argStr);
233
- pendingDecorators.push({
234
- method: 'API_ROUTE',
235
- path,
236
- responseModel,
237
- methods,
238
- line: startLine,
239
- });
240
- }
241
- } else if (HTTP_METHODS.has(methodName)) {
242
- const path = extractQuotedString(argStr);
243
- if (path) {
244
- const responseModel = extractResponseModel(argStr);
245
- pendingDecorators.push({
246
- method: methodName.toUpperCase(),
247
- path,
248
- responseModel,
249
- methods: [],
250
- line: startLine,
251
- });
252
- }
253
- }
254
- continue;
255
- }
256
-
257
- // Detect function definition
258
- const funcMatch = trimmed.match(
259
- /^(?:async\s+)?def\s+(\w+)\s*\((.*)\)\s*(?:->.*)?:\s*$/s,
260
- );
261
-
262
- if (funcMatch && pendingDecorators.length > 0) {
263
- const functionName = funcMatch[1];
264
- const paramStr = funcMatch[2];
265
-
266
- const dependencies = extractDependencies(paramStr);
267
- const requestModel = extractRequestModel(paramStr);
268
-
269
- const isAuthenticated = dependencies.some((dep) =>
270
- /auth|user|current_user/i.test(dep),
271
- );
272
-
273
- for (const dec of pendingDecorators) {
274
- if (dec.method === 'API_ROUTE') {
275
- // Expand api_route into one route per method
276
- const methods = dec.methods.length > 0 ? dec.methods : ['GET'];
277
- for (const m of methods) {
278
- routes.push({
279
- method: m,
280
- path: dec.path,
281
- functionName,
282
- dependencies,
283
- requestModel,
284
- responseModel: dec.responseModel,
285
- isAuthenticated,
286
- line: dec.line,
287
- });
288
- }
289
- } else {
290
- routes.push({
291
- method: dec.method,
292
- path: dec.path,
293
- functionName,
294
- dependencies,
295
- requestModel,
296
- responseModel: dec.responseModel,
297
- isAuthenticated,
298
- line: dec.line,
299
- });
300
- }
301
- }
302
-
303
- pendingDecorators.length = 0;
304
- continue;
305
- }
306
-
307
- // If we hit a non-decorator, non-function line, and there are pending decorators
308
- // that aren't followed by more decorators, clear them (they belong to something else)
309
- if (!trimmed.startsWith('@') && !trimmed.startsWith('def ') && !trimmed.startsWith('async def ')) {
310
- if (pendingDecorators.length > 0 && trimmed !== '') {
311
- pendingDecorators.length = 0;
312
- }
313
- }
314
- }
315
-
316
- return routes;
317
- }