@massu/core 1.10.8 → 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 (178) hide show
  1. package/CHANGELOG.md +1303 -0
  2. package/dist/adapter.js +6 -4
  3. package/dist/cli.js +517 -397
  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/framework-supports.ts +0 -85
  110. package/src/lib/gitToplevel.ts +0 -22
  111. package/src/lib/hook-registry.ts +0 -43
  112. package/src/lib/installLock.ts +0 -66
  113. package/src/lib/memory-path.ts +0 -49
  114. package/src/lib/pidLiveness.ts +0 -67
  115. package/src/lib/settings-local.ts +0 -110
  116. package/src/lib/sql-table-names.ts +0 -71
  117. package/src/license.ts +0 -547
  118. package/src/lsp/auto-detect.ts +0 -98
  119. package/src/lsp/client.ts +0 -776
  120. package/src/lsp/enrich.ts +0 -127
  121. package/src/lsp/types.ts +0 -221
  122. package/src/memory-db.ts +0 -1614
  123. package/src/memory-file-ingest.ts +0 -128
  124. package/src/memory-tools.ts +0 -424
  125. package/src/middleware-tree.ts +0 -71
  126. package/src/observability-tools.ts +0 -343
  127. package/src/observation-extractor.ts +0 -418
  128. package/src/page-deps.ts +0 -285
  129. package/src/permissions.ts +0 -422
  130. package/src/prompt-analyzer.ts +0 -332
  131. package/src/python/coupling-detector.ts +0 -125
  132. package/src/python/domain-enforcer.ts +0 -84
  133. package/src/python/impact-analyzer.ts +0 -96
  134. package/src/python/import-parser.ts +0 -244
  135. package/src/python/import-resolver.ts +0 -136
  136. package/src/python/migration-indexer.ts +0 -116
  137. package/src/python/migration-parser.ts +0 -332
  138. package/src/python/model-indexer.ts +0 -71
  139. package/src/python/model-parser.ts +0 -279
  140. package/src/python/route-indexer.ts +0 -59
  141. package/src/python/route-parser.ts +0 -317
  142. package/src/python-tools.ts +0 -630
  143. package/src/regression-detector.ts +0 -319
  144. package/src/rules.ts +0 -57
  145. package/src/schema-mapper.ts +0 -232
  146. package/src/security/adapter-origin.ts +0 -130
  147. package/src/security/adapter-verifier.ts +0 -319
  148. package/src/security/atomic-write.ts +0 -164
  149. package/src/security/fetcher.ts +0 -200
  150. package/src/security/install-tracking.ts +0 -319
  151. package/src/security/license-pubkey.generated.ts +0 -30
  152. package/src/security/license-response-verifier.ts +0 -149
  153. package/src/security/local-fingerprint.ts +0 -225
  154. package/src/security/manifest-cache.ts +0 -333
  155. package/src/security/manifest-schema.ts +0 -129
  156. package/src/security/registry-pubkey.generated.ts +0 -35
  157. package/src/security/telemetry.ts +0 -320
  158. package/src/security-scorer.ts +0 -405
  159. package/src/security-utils.ts +0 -133
  160. package/src/sentinel-db.ts +0 -580
  161. package/src/sentinel-scanner.ts +0 -406
  162. package/src/sentinel-tools.ts +0 -513
  163. package/src/sentinel-types.ts +0 -140
  164. package/src/server-dispatch.ts +0 -225
  165. package/src/server.ts +0 -107
  166. package/src/session-archiver.ts +0 -111
  167. package/src/session-state-generator.ts +0 -174
  168. package/src/team-knowledge.ts +0 -407
  169. package/src/tool-db-needs.ts +0 -232
  170. package/src/tools.ts +0 -1206
  171. package/src/transcript-parser.ts +0 -458
  172. package/src/trpc-index.ts +0 -215
  173. package/src/validate-features-runner.ts +0 -107
  174. package/src/validation-engine.ts +0 -358
  175. package/src/watch/daemon.ts +0 -385
  176. package/src/watch/lockfile-detector.ts +0 -65
  177. package/src/watch/paths.ts +0 -279
  178. package/src/watch/state.ts +0 -178
@@ -1,337 +0,0 @@
1
- // Copyright (c) 2026 Massu. All rights reserved.
2
- // Licensed under BSL 1.1 - see LICENSE file for details.
3
-
4
- import type Database from 'better-sqlite3';
5
- import type { ToolDefinition, ToolResult } from './tools.ts';
6
- import { getConfig } from './config.ts';
7
- import { existsSync, readFileSync } from 'fs';
8
- import { resolve } from 'path';
9
-
10
- // ============================================================
11
- // Dependency Risk Scoring
12
- // ============================================================
13
-
14
- /** Prefix a base tool name with the configured tool prefix. */
15
- function p(baseName: string): string {
16
- return `${getConfig().toolPrefix}_${baseName}`;
17
- }
18
-
19
- export interface DepRiskFactors {
20
- vulnerabilities: number;
21
- lastPublishDays: number | null;
22
- weeklyDownloads: number | null;
23
- license: string | null;
24
- bundleSizeKb: number | null;
25
- previousRemovals: number;
26
- }
27
-
28
- /** Default restrictive licenses. Configurable via security.restrictive_licenses */
29
- const DEFAULT_RESTRICTIVE_LICENSES = ['GPL', 'AGPL', 'SSPL'];
30
-
31
- /**
32
- * Get restrictive license list from config or defaults.
33
- */
34
- function getRestrictiveLicenses(): string[] {
35
- return getConfig().security?.restrictive_licenses ?? DEFAULT_RESTRICTIVE_LICENSES;
36
- }
37
-
38
- /**
39
- * Calculate risk score for a dependency.
40
- * 0 = safe, 100 = critical risk.
41
- */
42
- export function calculateDepRisk(factors: DepRiskFactors): number {
43
- let risk = 0;
44
- const restrictiveLicenses = getRestrictiveLicenses();
45
-
46
- // Vulnerabilities (heaviest weight)
47
- risk += Math.min(40, factors.vulnerabilities * 15);
48
-
49
- // Staleness (no publish in 2+ years is risky)
50
- if (factors.lastPublishDays !== null) {
51
- if (factors.lastPublishDays > 730) risk += 20;
52
- else if (factors.lastPublishDays > 365) risk += 10;
53
- else if (factors.lastPublishDays > 180) risk += 5;
54
- }
55
-
56
- // Low popularity
57
- if (factors.weeklyDownloads !== null) {
58
- if (factors.weeklyDownloads < 100) risk += 15;
59
- else if (factors.weeklyDownloads < 1000) risk += 8;
60
- else if (factors.weeklyDownloads < 10000) risk += 3;
61
- }
62
-
63
- // License issues
64
- if (factors.license) {
65
- if (restrictiveLicenses.some(l => factors.license!.toUpperCase().includes(l))) {
66
- risk += 10;
67
- }
68
- } else {
69
- risk += 5; // Unknown license
70
- }
71
-
72
- // Historical churn (AI added then removed)
73
- risk += Math.min(15, factors.previousRemovals * 5);
74
-
75
- return Math.min(100, risk);
76
- }
77
-
78
- /**
79
- * Get installed packages from package.json.
80
- */
81
- export function getInstalledPackages(projectRoot: string): Map<string, string> {
82
- const pkgPath = resolve(projectRoot, 'package.json');
83
- if (!existsSync(pkgPath)) return new Map();
84
-
85
- try {
86
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
87
- const packages = new Map<string, string>();
88
- for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
89
- packages.set(name, version as string);
90
- }
91
- for (const [name, version] of Object.entries(pkg.devDependencies ?? {})) {
92
- packages.set(name, version as string);
93
- }
94
- return packages;
95
- } catch {
96
- return new Map();
97
- }
98
- }
99
-
100
- /**
101
- * Store a dependency assessment.
102
- */
103
- export function storeAssessment(
104
- db: Database.Database,
105
- packageName: string,
106
- version: string | null,
107
- riskScore: number,
108
- factors: DepRiskFactors
109
- ): void {
110
- db.prepare(`
111
- INSERT INTO dependency_assessments
112
- (package_name, version, risk_score, vulnerabilities, last_publish_days,
113
- weekly_downloads, license, bundle_size_kb, previous_removals)
114
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
115
- `).run(
116
- packageName, version, riskScore,
117
- factors.vulnerabilities, factors.lastPublishDays,
118
- factors.weeklyDownloads, factors.license,
119
- factors.bundleSizeKb, factors.previousRemovals
120
- );
121
- }
122
-
123
- /**
124
- * Get historical removal count for a package.
125
- */
126
- export function getPreviousRemovals(db: Database.Database, packageName: string): number {
127
- const row = db.prepare(`
128
- SELECT MAX(previous_removals) as removals
129
- FROM dependency_assessments WHERE package_name = ?
130
- `).get(packageName) as { removals: number | null } | undefined;
131
- return row?.removals ?? 0;
132
- }
133
-
134
- /** Default alternative mappings. Configurable via security.dep_alternatives */
135
- const DEFAULT_ALTERNATIVES: Record<string, string[]> = {
136
- 'moment': ['date-fns', 'dayjs', 'luxon'],
137
- 'lodash': ['lodash-es', 'radash', 'remeda'],
138
- 'axios': ['ky', 'got', 'undici'],
139
- 'express': ['fastify', 'hono', 'elysia'],
140
- 'chalk': ['picocolors', 'kleur', 'colorette'],
141
- 'uuid': ['nanoid', 'cuid2', 'ulid'],
142
- 'request': ['got', 'node-fetch', 'undici'],
143
- 'underscore': ['lodash-es', 'radash'],
144
- };
145
-
146
- /**
147
- * Get alternative mappings from config or defaults.
148
- */
149
- function getAlternatives(): Record<string, string[]> {
150
- return getConfig().security?.dep_alternatives ?? DEFAULT_ALTERNATIVES;
151
- }
152
-
153
- // ============================================================
154
- // MCP Tool Definitions & Handlers
155
- // ============================================================
156
-
157
- export function getDependencyToolDefinitions(): ToolDefinition[] {
158
- return [
159
- {
160
- name: p('dep_score'),
161
- description: 'Assess a dependency before adding it. Returns risk score, factors, and recommendation.',
162
- inputSchema: {
163
- type: 'object',
164
- properties: {
165
- package_name: { type: 'string', description: 'npm package name' },
166
- version: { type: 'string', description: 'Specific version to assess' },
167
- },
168
- required: ['package_name'],
169
- },
170
- },
171
- {
172
- name: p('dep_alternatives'),
173
- description: 'Suggest alternatives to a package. Checks already-installed packages first.',
174
- inputSchema: {
175
- type: 'object',
176
- properties: {
177
- package_name: { type: 'string', description: 'Package to find alternatives for' },
178
- purpose: { type: 'string', description: 'What you need the package for' },
179
- },
180
- required: ['package_name'],
181
- },
182
- },
183
- ];
184
- }
185
-
186
- const DEPENDENCY_BASE_NAMES = new Set(['dep_score', 'dep_alternatives']);
187
-
188
- export function isDependencyTool(name: string): boolean {
189
- const pfx = getConfig().toolPrefix + '_';
190
- const baseName = name.startsWith(pfx) ? name.slice(pfx.length) : name;
191
- return DEPENDENCY_BASE_NAMES.has(baseName);
192
- }
193
-
194
- export function handleDependencyToolCall(
195
- name: string,
196
- args: Record<string, unknown>,
197
- memoryDb: Database.Database
198
- ): ToolResult {
199
- try {
200
- const pfx = getConfig().toolPrefix + '_';
201
- const baseName = name.startsWith(pfx) ? name.slice(pfx.length) : name;
202
-
203
- switch (baseName) {
204
- case 'dep_score':
205
- return handleDepCheck(args, memoryDb);
206
- case 'dep_alternatives':
207
- return handleDepAlternatives(args, memoryDb);
208
- default:
209
- return text(`Unknown dependency tool: ${name}`);
210
- }
211
- } catch (error) {
212
- return text(`Error in ${name}: ${error instanceof Error ? error.message : String(error)}\n\nUsage: ${p('dep_score')} { package_name: "express" }, ${p('dep_alternatives')} { package_name: "moment" }`);
213
- }
214
- }
215
-
216
- function handleDepCheck(args: Record<string, unknown>, db: Database.Database): ToolResult {
217
- const packageName = args.package_name as string;
218
- if (!packageName) return text(`Usage: ${p('dep_score')} { package_name: "express", version: "4.18.0" } - Assess risk of adding/updating a dependency.`);
219
- const version = args.version as string | undefined;
220
-
221
- // Check if already installed
222
- const config = getConfig();
223
- const installed = getInstalledPackages(config.project.root);
224
- const isInstalled = installed.has(packageName);
225
-
226
- // Check historical assessments
227
- const previous = db.prepare(`
228
- SELECT * FROM dependency_assessments
229
- WHERE package_name = ?
230
- ORDER BY assessed_at DESC LIMIT 1
231
- `).get(packageName) as Record<string, unknown> | undefined;
232
-
233
- const previousRemovals = getPreviousRemovals(db, packageName);
234
-
235
- // Build factors from available data
236
- const factors: DepRiskFactors = {
237
- vulnerabilities: previous ? (previous.vulnerabilities as number) : 0,
238
- lastPublishDays: previous ? (previous.last_publish_days as number | null) : null,
239
- weeklyDownloads: previous ? (previous.weekly_downloads as number | null) : null,
240
- license: previous ? (previous.license as string | null) : null,
241
- bundleSizeKb: previous ? (previous.bundle_size_kb as number | null) : null,
242
- previousRemovals,
243
- };
244
-
245
- const riskScore = calculateDepRisk(factors);
246
-
247
- const recommendation = riskScore >= 60 ? 'AVOID'
248
- : riskScore >= 30 ? 'CAUTION'
249
- : 'OK';
250
-
251
- const lines = [
252
- `## Dependency Check: ${packageName}${version ? `@${version}` : ''}`,
253
- `Risk Score: **${riskScore}/100** [${recommendation}]`,
254
- `Currently installed: ${isInstalled ? `Yes (${installed.get(packageName)})` : 'No'}`,
255
- '',
256
- '### Risk Factors',
257
- `| Factor | Value | Risk |`,
258
- `|--------|-------|------|`,
259
- ];
260
-
261
- if (factors.vulnerabilities > 0) {
262
- lines.push(`| Vulnerabilities | ${factors.vulnerabilities} | +${Math.min(40, factors.vulnerabilities * 15)} |`);
263
- }
264
- if (factors.lastPublishDays !== null) {
265
- lines.push(`| Last Published | ${factors.lastPublishDays} days ago | ${factors.lastPublishDays > 365 ? '+10' : '0'} |`);
266
- }
267
- if (factors.weeklyDownloads !== null) {
268
- lines.push(`| Weekly Downloads | ${factors.weeklyDownloads.toLocaleString()} | ${factors.weeklyDownloads < 1000 ? '+8' : '0'} |`);
269
- }
270
- if (factors.license) {
271
- lines.push(`| License | ${factors.license} | 0 |`);
272
- }
273
- if (previousRemovals > 0) {
274
- lines.push(`| Previous Removals | ${previousRemovals}x | +${Math.min(15, previousRemovals * 5)} |`);
275
- }
276
-
277
- if (!previous) {
278
- lines.push('');
279
- lines.push(`*Note: No previous assessment data. Run \`npm audit\` for vulnerability data, then re-run ${p('dep_score')} for a more accurate score.*`);
280
- }
281
-
282
- // Store assessment
283
- storeAssessment(db, packageName, version ?? null, riskScore, factors);
284
-
285
- return text(lines.join('\n'));
286
- }
287
-
288
- function handleDepAlternatives(args: Record<string, unknown>, db: Database.Database): ToolResult {
289
- const packageName = args.package_name as string;
290
- const purpose = args.purpose as string | undefined;
291
- if (!packageName) return text(`Usage: ${p('dep_alternatives')} { package_name: "lodash", purpose: "utility functions" } - Find safer/lighter alternatives.`);
292
-
293
- const config = getConfig();
294
- const installed = getInstalledPackages(config.project.root);
295
- const alternativeMappings = getAlternatives();
296
-
297
- const lines = [
298
- `## Alternatives to: ${packageName}`,
299
- purpose ? `Purpose: ${purpose}` : '',
300
- '',
301
- ];
302
-
303
- // Check if any alternatives are already installed
304
- const alts = alternativeMappings[packageName] ?? [];
305
- const installedAlts = alts.filter(a => installed.has(a));
306
-
307
- if (installedAlts.length > 0) {
308
- lines.push('### Already Installed');
309
- for (const alt of installedAlts) {
310
- lines.push(`- **${alt}** (${installed.get(alt)}) - already in your dependencies`);
311
- }
312
- lines.push('');
313
- }
314
-
315
- if (alts.length > 0) {
316
- const notInstalled = alts.filter(a => !installed.has(a));
317
- if (notInstalled.length > 0) {
318
- lines.push('### Known Alternatives');
319
- for (const alt of notInstalled) {
320
- // Check previous assessments
321
- const prev = db.prepare(
322
- 'SELECT risk_score FROM dependency_assessments WHERE package_name = ? ORDER BY assessed_at DESC LIMIT 1'
323
- ).get(alt) as { risk_score: number } | undefined;
324
- const riskInfo = prev ? ` (risk: ${prev.risk_score})` : '';
325
- lines.push(`- ${alt}${riskInfo}`);
326
- }
327
- }
328
- } else {
329
- lines.push(`No known alternative mappings for "${packageName}". Consider searching npm for packages that serve: ${purpose ?? packageName}. You can add custom alternative mappings via the \`security.dep_alternatives\` config key.`);
330
- }
331
-
332
- return text(lines.filter(Boolean).join('\n'));
333
- }
334
-
335
- function text(content: string): ToolResult {
336
- return { content: [{ type: 'text', text: content }] };
337
- }
@@ -1,4 +0,0 @@
1
- // Plan 3c Phase 9b P-A-005: re-export shim. Source-of-truth lives at
2
- // `packages/adapter-aspnet/src/index.ts` (workspace package). This shim
3
- // preserves the legacy import path used by codebase-introspector + tests.
4
- export { aspnetAdapter } from '@massu/adapter-aspnet';