@massu/core 0.1.0 → 0.1.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.
- package/LICENSE +71 -0
- package/README.md +2 -2
- package/dist/hooks/cost-tracker.js +149 -11527
- package/dist/hooks/post-edit-context.js +127 -11493
- package/dist/hooks/post-tool-use.js +169 -11550
- package/dist/hooks/pre-compact.js +149 -11530
- package/dist/hooks/pre-delete-check.js +144 -11523
- package/dist/hooks/quality-event.js +149 -11527
- package/dist/hooks/session-end.js +188 -11570
- package/dist/hooks/session-start.js +159 -11534
- package/dist/hooks/user-prompt.js +149 -11530
- package/package.json +14 -19
- package/src/adr-generator.ts +292 -0
- package/src/analytics.ts +373 -0
- package/src/audit-trail.ts +450 -0
- package/src/backfill-sessions.ts +180 -0
- package/src/cli.ts +105 -0
- package/src/cloud-sync.ts +190 -0
- package/src/commands/doctor.ts +300 -0
- package/src/commands/init.ts +395 -0
- package/src/commands/install-hooks.ts +26 -0
- package/src/config.ts +357 -0
- package/src/cost-tracker.ts +355 -0
- package/src/db.ts +233 -0
- package/src/dependency-scorer.ts +337 -0
- package/src/docs-map.json +100 -0
- package/src/docs-tools.ts +517 -0
- package/src/domains.ts +181 -0
- package/src/hooks/cost-tracker.ts +66 -0
- package/src/hooks/intent-suggester.ts +131 -0
- package/src/hooks/post-edit-context.ts +91 -0
- package/src/hooks/post-tool-use.ts +175 -0
- package/src/hooks/pre-compact.ts +146 -0
- package/src/hooks/pre-delete-check.ts +153 -0
- package/src/hooks/quality-event.ts +127 -0
- package/src/hooks/security-gate.ts +121 -0
- package/src/hooks/session-end.ts +467 -0
- package/src/hooks/session-start.ts +210 -0
- package/src/hooks/user-prompt.ts +91 -0
- package/src/import-resolver.ts +224 -0
- package/src/memory-db.ts +1376 -0
- package/src/memory-tools.ts +391 -0
- package/src/middleware-tree.ts +70 -0
- package/src/observability-tools.ts +343 -0
- package/src/observation-extractor.ts +411 -0
- package/src/page-deps.ts +283 -0
- package/src/prompt-analyzer.ts +332 -0
- package/src/regression-detector.ts +319 -0
- package/src/rules.ts +57 -0
- package/src/schema-mapper.ts +232 -0
- package/src/security-scorer.ts +405 -0
- package/src/security-utils.ts +133 -0
- package/src/sentinel-db.ts +578 -0
- package/src/sentinel-scanner.ts +405 -0
- package/src/sentinel-tools.ts +512 -0
- package/src/sentinel-types.ts +140 -0
- package/src/server.ts +189 -0
- package/src/session-archiver.ts +112 -0
- package/src/session-state-generator.ts +174 -0
- package/src/team-knowledge.ts +407 -0
- package/src/tools.ts +847 -0
- package/src/transcript-parser.ts +458 -0
- package/src/trpc-index.ts +214 -0
- package/src/validate-features-runner.ts +106 -0
- package/src/validation-engine.ts +358 -0
- package/dist/cli.js +0 -7890
- package/dist/server.js +0 -7008
|
@@ -0,0 +1,337 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"description": "Maps app code (routes, routers, components) to help site pages. Used by massu_docs_audit to detect which docs need updating when code changes.",
|
|
4
|
+
"mappings": [
|
|
5
|
+
{
|
|
6
|
+
"id": "dashboard",
|
|
7
|
+
"helpPage": "pages/dashboard.mdx",
|
|
8
|
+
"appRoutes": ["src/app/dashboard/**"],
|
|
9
|
+
"routers": ["dashboard.ts", "analytics.ts"],
|
|
10
|
+
"components": ["src/components/dashboard/**", "src/components/analytics/**"],
|
|
11
|
+
"keywords": ["dashboard", "home", "overview", "analytics", "KPI"]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "auth",
|
|
15
|
+
"helpPage": "pages/auth.mdx",
|
|
16
|
+
"appRoutes": ["src/app/auth/**", "src/app/login/**"],
|
|
17
|
+
"routers": ["auth.ts", "sessions.ts", "oauth.ts"],
|
|
18
|
+
"components": ["src/components/auth/**"],
|
|
19
|
+
"keywords": ["login", "signup", "authentication", "password", "SSO", "OAuth"]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "users",
|
|
23
|
+
"helpPage": "pages/users.mdx",
|
|
24
|
+
"appRoutes": ["src/app/users/**", "src/app/profile/**"],
|
|
25
|
+
"routers": ["users.ts", "user-profiles.ts", "user-preferences.ts"],
|
|
26
|
+
"components": ["src/components/users/**", "src/components/profile/**"],
|
|
27
|
+
"keywords": ["user", "profile", "account", "preferences"]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "teams",
|
|
31
|
+
"helpPage": "pages/teams.mdx",
|
|
32
|
+
"appRoutes": ["src/app/teams/**", "src/app/organizations/**"],
|
|
33
|
+
"routers": ["teams.ts", "team-members.ts", "organizations.ts", "invitations.ts"],
|
|
34
|
+
"components": ["src/components/teams/**", "src/components/organizations/**"],
|
|
35
|
+
"keywords": ["team", "organization", "member", "invite", "role"]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "billing",
|
|
39
|
+
"helpPage": "pages/billing.mdx",
|
|
40
|
+
"appRoutes": ["src/app/billing/**", "src/app/subscriptions/**"],
|
|
41
|
+
"routers": ["billing.ts", "subscriptions.ts", "invoices.ts", "payment-methods.ts"],
|
|
42
|
+
"components": ["src/components/billing/**", "src/components/subscriptions/**"],
|
|
43
|
+
"keywords": ["billing", "subscription", "invoice", "payment", "plan", "pricing"]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "settings",
|
|
47
|
+
"helpPage": "pages/settings.mdx",
|
|
48
|
+
"appRoutes": ["src/app/settings/**", "src/app/admin/**"],
|
|
49
|
+
"routers": ["settings.ts", "admin.ts", "feature-flags.ts"],
|
|
50
|
+
"components": ["src/components/settings/**", "src/components/admin/**"],
|
|
51
|
+
"keywords": ["settings", "configuration", "admin", "preferences", "feature flag"]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "notifications",
|
|
55
|
+
"helpPage": "pages/notifications.mdx",
|
|
56
|
+
"appRoutes": ["src/app/notifications/**"],
|
|
57
|
+
"routers": ["notifications.ts", "notification-preferences.ts", "push-notifications.ts"],
|
|
58
|
+
"components": ["src/components/notifications/**"],
|
|
59
|
+
"keywords": ["notification", "alert", "email", "push", "webhook"]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "projects",
|
|
63
|
+
"helpPage": "pages/projects.mdx",
|
|
64
|
+
"appRoutes": ["src/app/projects/**"],
|
|
65
|
+
"routers": ["projects.ts", "project-members.ts", "project-settings.ts"],
|
|
66
|
+
"components": ["src/components/projects/**"],
|
|
67
|
+
"keywords": ["project", "workspace", "task", "milestone"]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "api-docs",
|
|
71
|
+
"helpPage": "pages/api-docs.mdx",
|
|
72
|
+
"appRoutes": ["src/app/api-docs/**"],
|
|
73
|
+
"routers": ["api-keys.ts", "webhooks.ts"],
|
|
74
|
+
"components": ["src/components/api-docs/**"],
|
|
75
|
+
"keywords": ["API", "key", "webhook", "endpoint", "documentation"]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": "integrations",
|
|
79
|
+
"helpPage": "pages/integrations.mdx",
|
|
80
|
+
"appRoutes": ["src/app/integrations/**"],
|
|
81
|
+
"routers": ["integrations.ts", "oauth-connections.ts", "sync.ts"],
|
|
82
|
+
"components": ["src/components/integrations/**"],
|
|
83
|
+
"keywords": ["integration", "connect", "sync", "OAuth", "third-party"]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"userGuideInheritance": {
|
|
87
|
+
"description": "User guide pages inherit their parent feature's mapping. The guide name contains the feature keyword. For example, billing-guide inherits from the 'billing' mapping.",
|
|
88
|
+
"pattern": "pages/user-guides/{feature}-guide/**",
|
|
89
|
+
"examples": {
|
|
90
|
+
"dashboard-guide": "dashboard",
|
|
91
|
+
"billing-guide": "billing",
|
|
92
|
+
"team-management-guide": "teams",
|
|
93
|
+
"user-management-guide": "users",
|
|
94
|
+
"notifications-guide": "notifications",
|
|
95
|
+
"analytics-guide": "dashboard",
|
|
96
|
+
"project-setup-guide": "projects",
|
|
97
|
+
"api-integration-guide": "integrations"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|