@collage-dam/mcp-server 0.1.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.
- package/.env.example +56 -0
- package/CHANGELOG.md +90 -0
- package/LICENSE +21 -0
- package/README.md +512 -0
- package/dist/client.d.ts +497 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1162 -0
- package/dist/client.js.map +1 -0
- package/dist/conventions/confirmation.d.ts +89 -0
- package/dist/conventions/confirmation.d.ts.map +1 -0
- package/dist/conventions/confirmation.js +132 -0
- package/dist/conventions/confirmation.js.map +1 -0
- package/dist/conventions/dry-run/batch-executor.d.ts +36 -0
- package/dist/conventions/dry-run/batch-executor.d.ts.map +1 -0
- package/dist/conventions/dry-run/batch-executor.js +89 -0
- package/dist/conventions/dry-run/batch-executor.js.map +1 -0
- package/dist/conventions/dry-run/diff-renderer.d.ts +34 -0
- package/dist/conventions/dry-run/diff-renderer.d.ts.map +1 -0
- package/dist/conventions/dry-run/diff-renderer.js +158 -0
- package/dist/conventions/dry-run/diff-renderer.js.map +1 -0
- package/dist/conventions/dry-run/index.d.ts +13 -0
- package/dist/conventions/dry-run/index.d.ts.map +1 -0
- package/dist/conventions/dry-run/index.js +10 -0
- package/dist/conventions/dry-run/index.js.map +1 -0
- package/dist/conventions/dry-run/mutating-tool.d.ts +64 -0
- package/dist/conventions/dry-run/mutating-tool.d.ts.map +1 -0
- package/dist/conventions/dry-run/mutating-tool.js +88 -0
- package/dist/conventions/dry-run/mutating-tool.js.map +1 -0
- package/dist/conventions/dry-run/summary.d.ts +66 -0
- package/dist/conventions/dry-run/summary.d.ts.map +1 -0
- package/dist/conventions/dry-run/summary.js +185 -0
- package/dist/conventions/dry-run/summary.js.map +1 -0
- package/dist/conventions/dry-run/types.d.ts +597 -0
- package/dist/conventions/dry-run/types.d.ts.map +1 -0
- package/dist/conventions/dry-run/types.js +108 -0
- package/dist/conventions/dry-run/types.js.map +1 -0
- package/dist/conventions/dry-run/with-dry-run.d.ts +66 -0
- package/dist/conventions/dry-run/with-dry-run.d.ts.map +1 -0
- package/dist/conventions/dry-run/with-dry-run.js +219 -0
- package/dist/conventions/dry-run/with-dry-run.js.map +1 -0
- package/dist/conventions/env.d.ts +49 -0
- package/dist/conventions/env.d.ts.map +1 -0
- package/dist/conventions/env.js +84 -0
- package/dist/conventions/env.js.map +1 -0
- package/dist/conventions/errors.d.ts +68 -0
- package/dist/conventions/errors.d.ts.map +1 -0
- package/dist/conventions/errors.js +81 -0
- package/dist/conventions/errors.js.map +1 -0
- package/dist/conventions/logger.d.ts +28 -0
- package/dist/conventions/logger.d.ts.map +1 -0
- package/dist/conventions/logger.js +105 -0
- package/dist/conventions/logger.js.map +1 -0
- package/dist/conventions/pagination.d.ts +37 -0
- package/dist/conventions/pagination.d.ts.map +1 -0
- package/dist/conventions/pagination.js +53 -0
- package/dist/conventions/pagination.js.map +1 -0
- package/dist/conventions/rate-limiter.d.ts +54 -0
- package/dist/conventions/rate-limiter.d.ts.map +1 -0
- package/dist/conventions/rate-limiter.js +143 -0
- package/dist/conventions/rate-limiter.js.map +1 -0
- package/dist/conventions/response-budget.d.ts +66 -0
- package/dist/conventions/response-budget.d.ts.map +1 -0
- package/dist/conventions/response-budget.js +89 -0
- package/dist/conventions/response-budget.js.map +1 -0
- package/dist/conventions/schema-version.d.ts +27 -0
- package/dist/conventions/schema-version.d.ts.map +1 -0
- package/dist/conventions/schema-version.js +29 -0
- package/dist/conventions/schema-version.js.map +1 -0
- package/dist/conventions/state-store-redis.d.ts +32 -0
- package/dist/conventions/state-store-redis.d.ts.map +1 -0
- package/dist/conventions/state-store-redis.js +77 -0
- package/dist/conventions/state-store-redis.js.map +1 -0
- package/dist/conventions/state-store.d.ts +46 -0
- package/dist/conventions/state-store.d.ts.map +1 -0
- package/dist/conventions/state-store.js +105 -0
- package/dist/conventions/state-store.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +421 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/collection-audit.d.ts +13 -0
- package/dist/prompts/collection-audit.d.ts.map +1 -0
- package/dist/prompts/collection-audit.js +168 -0
- package/dist/prompts/collection-audit.js.map +1 -0
- package/dist/prompts/create-distribution.d.ts +15 -0
- package/dist/prompts/create-distribution.d.ts.map +1 -0
- package/dist/prompts/create-distribution.js +111 -0
- package/dist/prompts/create-distribution.js.map +1 -0
- package/dist/prompts/helpers.d.ts +20 -0
- package/dist/prompts/helpers.d.ts.map +1 -0
- package/dist/prompts/helpers.js +53 -0
- package/dist/prompts/helpers.js.map +1 -0
- package/dist/prompts/library-health-audit.d.ts +13 -0
- package/dist/prompts/library-health-audit.d.ts.map +1 -0
- package/dist/prompts/library-health-audit.js +131 -0
- package/dist/prompts/library-health-audit.js.map +1 -0
- package/dist/prompts/usage-insights.d.ts +13 -0
- package/dist/prompts/usage-insights.d.ts.map +1 -0
- package/dist/prompts/usage-insights.js +98 -0
- package/dist/prompts/usage-insights.js.map +1 -0
- package/dist/prompts/wrap-prompt-as-tool.d.ts +48 -0
- package/dist/prompts/wrap-prompt-as-tool.d.ts.map +1 -0
- package/dist/prompts/wrap-prompt-as-tool.js +61 -0
- package/dist/prompts/wrap-prompt-as-tool.js.map +1 -0
- package/dist/resources/asset-by-id.d.ts +4 -0
- package/dist/resources/asset-by-id.d.ts.map +1 -0
- package/dist/resources/asset-by-id.js +27 -0
- package/dist/resources/asset-by-id.js.map +1 -0
- package/dist/resources/collections.d.ts +5 -0
- package/dist/resources/collections.d.ts.map +1 -0
- package/dist/resources/collections.js +48 -0
- package/dist/resources/collections.js.map +1 -0
- package/dist/resources/custom-fields.d.ts +4 -0
- package/dist/resources/custom-fields.d.ts.map +1 -0
- package/dist/resources/custom-fields.js +30 -0
- package/dist/resources/custom-fields.js.map +1 -0
- package/dist/resources/folders.d.ts +5 -0
- package/dist/resources/folders.d.ts.map +1 -0
- package/dist/resources/folders.js +73 -0
- package/dist/resources/folders.js.map +1 -0
- package/dist/resources/helpers.d.ts +17 -0
- package/dist/resources/helpers.d.ts.map +1 -0
- package/dist/resources/helpers.js +59 -0
- package/dist/resources/helpers.js.map +1 -0
- package/dist/resources/portals.d.ts +5 -0
- package/dist/resources/portals.d.ts.map +1 -0
- package/dist/resources/portals.js +81 -0
- package/dist/resources/portals.js.map +1 -0
- package/dist/resources/recent-and-dashboard.d.ts +5 -0
- package/dist/resources/recent-and-dashboard.d.ts.map +1 -0
- package/dist/resources/recent-and-dashboard.js +42 -0
- package/dist/resources/recent-and-dashboard.js.map +1 -0
- package/dist/tools/asset-selection.d.ts +102 -0
- package/dist/tools/asset-selection.d.ts.map +1 -0
- package/dist/tools/asset-selection.js +133 -0
- package/dist/tools/asset-selection.js.map +1 -0
- package/dist/tools/audit/audit-folder-structure.d.ts +108 -0
- package/dist/tools/audit/audit-folder-structure.d.ts.map +1 -0
- package/dist/tools/audit/audit-folder-structure.js +260 -0
- package/dist/tools/audit/audit-folder-structure.js.map +1 -0
- package/dist/tools/audit/audit-naming-conventions.d.ts +83 -0
- package/dist/tools/audit/audit-naming-conventions.d.ts.map +1 -0
- package/dist/tools/audit/audit-naming-conventions.js +238 -0
- package/dist/tools/audit/audit-naming-conventions.js.map +1 -0
- package/dist/tools/audit/audit-tagging-hygiene.d.ts +77 -0
- package/dist/tools/audit/audit-tagging-hygiene.d.ts.map +1 -0
- package/dist/tools/audit/audit-tagging-hygiene.js +402 -0
- package/dist/tools/audit/audit-tagging-hygiene.js.map +1 -0
- package/dist/tools/audit/detect-duplicates.d.ts +62 -0
- package/dist/tools/audit/detect-duplicates.d.ts.map +1 -0
- package/dist/tools/audit/detect-duplicates.js +0 -0
- package/dist/tools/audit/detect-duplicates.js.map +1 -0
- package/dist/tools/audit/types.d.ts +526 -0
- package/dist/tools/audit/types.d.ts.map +1 -0
- package/dist/tools/audit/types.js +188 -0
- package/dist/tools/audit/types.js.map +1 -0
- package/dist/tools/bulk-move-assets.d.ts +78 -0
- package/dist/tools/bulk-move-assets.d.ts.map +1 -0
- package/dist/tools/bulk-move-assets.js +122 -0
- package/dist/tools/bulk-move-assets.js.map +1 -0
- package/dist/tools/bulk-normalize-filenames.d.ts +62 -0
- package/dist/tools/bulk-normalize-filenames.d.ts.map +1 -0
- package/dist/tools/bulk-normalize-filenames.js +237 -0
- package/dist/tools/bulk-normalize-filenames.js.map +1 -0
- package/dist/tools/bulk-rename-assets.d.ts +79 -0
- package/dist/tools/bulk-rename-assets.d.ts.map +1 -0
- package/dist/tools/bulk-rename-assets.js +139 -0
- package/dist/tools/bulk-rename-assets.js.map +1 -0
- package/dist/tools/bulk-tags.d.ts +107 -0
- package/dist/tools/bulk-tags.d.ts.map +1 -0
- package/dist/tools/bulk-tags.js +220 -0
- package/dist/tools/bulk-tags.js.map +1 -0
- package/dist/tools/client-adapters.d.ts +76 -0
- package/dist/tools/client-adapters.d.ts.map +1 -0
- package/dist/tools/client-adapters.js +648 -0
- package/dist/tools/client-adapters.js.map +1 -0
- package/dist/tools/collection-membership.d.ts +90 -0
- package/dist/tools/collection-membership.d.ts.map +1 -0
- package/dist/tools/collection-membership.js +195 -0
- package/dist/tools/collection-membership.js.map +1 -0
- package/dist/tools/create-collection.d.ts +63 -0
- package/dist/tools/create-collection.d.ts.map +1 -0
- package/dist/tools/create-collection.js +151 -0
- package/dist/tools/create-collection.js.map +1 -0
- package/dist/tools/create-folder.d.ts +46 -0
- package/dist/tools/create-folder.d.ts.map +1 -0
- package/dist/tools/create-folder.js +83 -0
- package/dist/tools/create-folder.js.map +1 -0
- package/dist/tools/create-share-link.d.ts +107 -0
- package/dist/tools/create-share-link.d.ts.map +1 -0
- package/dist/tools/create-share-link.js +239 -0
- package/dist/tools/create-share-link.js.map +1 -0
- package/dist/tools/get-asset-details.d.ts +401 -0
- package/dist/tools/get-asset-details.d.ts.map +1 -0
- package/dist/tools/get-asset-details.js +56 -0
- package/dist/tools/get-asset-details.js.map +1 -0
- package/dist/tools/get-collection.d.ts +126 -0
- package/dist/tools/get-collection.d.ts.map +1 -0
- package/dist/tools/get-collection.js +52 -0
- package/dist/tools/get-collection.js.map +1 -0
- package/dist/tools/get-embed-code.d.ts +195 -0
- package/dist/tools/get-embed-code.d.ts.map +1 -0
- package/dist/tools/get-embed-code.js +214 -0
- package/dist/tools/get-embed-code.js.map +1 -0
- package/dist/tools/insights/analyze-share-links.d.ts +159 -0
- package/dist/tools/insights/analyze-share-links.d.ts.map +1 -0
- package/dist/tools/insights/analyze-share-links.js +314 -0
- package/dist/tools/insights/analyze-share-links.js.map +1 -0
- package/dist/tools/insights/insight-cache.d.ts +36 -0
- package/dist/tools/insights/insight-cache.d.ts.map +1 -0
- package/dist/tools/insights/insight-cache.js +98 -0
- package/dist/tools/insights/insight-cache.js.map +1 -0
- package/dist/tools/insights/report-asset-activation.d.ts +149 -0
- package/dist/tools/insights/report-asset-activation.d.ts.map +1 -0
- package/dist/tools/insights/report-asset-activation.js +380 -0
- package/dist/tools/insights/report-asset-activation.js.map +1 -0
- package/dist/tools/insights/report-stale-assets.d.ts +120 -0
- package/dist/tools/insights/report-stale-assets.d.ts.map +1 -0
- package/dist/tools/insights/report-stale-assets.js +281 -0
- package/dist/tools/insights/report-stale-assets.js.map +1 -0
- package/dist/tools/insights/report-top-assets.d.ts +139 -0
- package/dist/tools/insights/report-top-assets.d.ts.map +1 -0
- package/dist/tools/insights/report-top-assets.js +407 -0
- package/dist/tools/insights/report-top-assets.js.map +1 -0
- package/dist/tools/list-categories.d.ts +127 -0
- package/dist/tools/list-categories.d.ts.map +1 -0
- package/dist/tools/list-categories.js +68 -0
- package/dist/tools/list-categories.js.map +1 -0
- package/dist/tools/list-collections.d.ts +127 -0
- package/dist/tools/list-collections.d.ts.map +1 -0
- package/dist/tools/list-collections.js +53 -0
- package/dist/tools/list-collections.js.map +1 -0
- package/dist/tools/list-custom-fields.d.ts +125 -0
- package/dist/tools/list-custom-fields.d.ts.map +1 -0
- package/dist/tools/list-custom-fields.js +51 -0
- package/dist/tools/list-custom-fields.js.map +1 -0
- package/dist/tools/list-share-links.d.ts +192 -0
- package/dist/tools/list-share-links.d.ts.map +1 -0
- package/dist/tools/list-share-links.js +92 -0
- package/dist/tools/list-share-links.js.map +1 -0
- package/dist/tools/list-workspaces.d.ts +88 -0
- package/dist/tools/list-workspaces.d.ts.map +1 -0
- package/dist/tools/list-workspaces.js +71 -0
- package/dist/tools/list-workspaces.js.map +1 -0
- package/dist/tools/move-asset.d.ts +48 -0
- package/dist/tools/move-asset.d.ts.map +1 -0
- package/dist/tools/move-asset.js +85 -0
- package/dist/tools/move-asset.js.map +1 -0
- package/dist/tools/rename-asset.d.ts +88 -0
- package/dist/tools/rename-asset.d.ts.map +1 -0
- package/dist/tools/rename-asset.js +100 -0
- package/dist/tools/rename-asset.js.map +1 -0
- package/dist/tools/rename-folder.d.ts +55 -0
- package/dist/tools/rename-folder.d.ts.map +1 -0
- package/dist/tools/rename-folder.js +101 -0
- package/dist/tools/rename-folder.js.map +1 -0
- package/dist/tools/revoke-share-link.d.ts +55 -0
- package/dist/tools/revoke-share-link.d.ts.map +1 -0
- package/dist/tools/revoke-share-link.js +77 -0
- package/dist/tools/revoke-share-link.js.map +1 -0
- package/dist/tools/search/facets.d.ts +34 -0
- package/dist/tools/search/facets.d.ts.map +1 -0
- package/dist/tools/search/facets.js +147 -0
- package/dist/tools/search/facets.js.map +1 -0
- package/dist/tools/search/filter-builder.d.ts +33 -0
- package/dist/tools/search/filter-builder.d.ts.map +1 -0
- package/dist/tools/search/filter-builder.js +111 -0
- package/dist/tools/search/filter-builder.js.map +1 -0
- package/dist/tools/search/search-assets.d.ts +41 -0
- package/dist/tools/search/search-assets.d.ts.map +1 -0
- package/dist/tools/search/search-assets.js +162 -0
- package/dist/tools/search/search-assets.js.map +1 -0
- package/dist/tools/search/search-collections.d.ts +35 -0
- package/dist/tools/search/search-collections.d.ts.map +1 -0
- package/dist/tools/search/search-collections.js +103 -0
- package/dist/tools/search/search-collections.js.map +1 -0
- package/dist/tools/search/types.d.ts +1047 -0
- package/dist/tools/search/types.d.ts.map +1 -0
- package/dist/tools/search/types.js +216 -0
- package/dist/tools/search/types.js.map +1 -0
- package/dist/tools/update-asset-metadata.d.ts +78 -0
- package/dist/tools/update-asset-metadata.d.ts.map +1 -0
- package/dist/tools/update-asset-metadata.js +203 -0
- package/dist/tools/update-asset-metadata.js.map +1 -0
- package/dist/tools/update-collection.d.ts +69 -0
- package/dist/tools/update-collection.d.ts.map +1 -0
- package/dist/tools/update-collection.js +142 -0
- package/dist/tools/update-collection.js.map +1 -0
- package/dist/tools/view-category-contents.d.ts +231 -0
- package/dist/tools/view-category-contents.d.ts.map +1 -0
- package/dist/tools/view-category-contents.js +97 -0
- package/dist/tools/view-category-contents.js.map +1 -0
- package/dist/types.d.ts +1326 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +288 -0
- package/dist/types.js.map +1 -0
- package/dist/typesense.d.ts +84 -0
- package/dist/typesense.d.ts.map +1 -0
- package/dist/typesense.js +243 -0
- package/dist/typesense.js.map +1 -0
- package/docs/api-field-verification.md +244 -0
- package/docs/deployment-runbook.md +446 -0
- package/docs/security-review.md +195 -0
- package/docs/typesense-filter-schema.md +262 -0
- package/docs/verified-endpoints.md +38 -0
- package/package.json +72 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// ── audit_folder_structure (T2, Phase 1.5) ───────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Read-only audit tool. Walks the workspace folder tree plus the workspace
|
|
4
|
+
// asset list and reports three classes of structural problem:
|
|
5
|
+
//
|
|
6
|
+
// - folder_depth_anomaly — folders nested deeper than `max_depth`
|
|
7
|
+
// - orphaned_assets — assets that live outside any folder
|
|
8
|
+
// (`category_id === null`)
|
|
9
|
+
// - low_asset_collections — collections holding fewer than `min_assets`
|
|
10
|
+
// members (user-supplied threshold, NOT hard-coded)
|
|
11
|
+
//
|
|
12
|
+
// IMPORTANT: this tool is read-only. It emits structured next-step hints
|
|
13
|
+
// that point at the existing `bulk_move_assets` mutating tool (Phase 1.5)
|
|
14
|
+
// for re-homing orphaned assets, but it never mutates anything itself.
|
|
15
|
+
//
|
|
16
|
+
// Scoring + response-budget enforcement reuse the shared helpers in
|
|
17
|
+
// `./types.ts` so the report shape stays uniform across audits.
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
import { createToolError } from '../../conventions/errors.js';
|
|
20
|
+
import { estimateTokens, HARD_CAP_TOKENS } from '../../conventions/response-budget.js';
|
|
21
|
+
import { computeAuditScore, summarizeFindings, } from './types.js';
|
|
22
|
+
// ── Tool description ─────────────────────────────────────────────────
|
|
23
|
+
export const AUDIT_FOLDER_STRUCTURE_DESCRIPTION = 'Read-only audit of folder + collection structure. Detects folders ' +
|
|
24
|
+
'nested deeper than `max_depth`, orphaned assets (no parent folder), ' +
|
|
25
|
+
'and collections with fewer than `min_assets` members. Returns a ' +
|
|
26
|
+
'0-100 score, structured findings, and next-step hints. Does not ' +
|
|
27
|
+
'mutate anything.';
|
|
28
|
+
// ── Input schema ─────────────────────────────────────────────────────
|
|
29
|
+
const DEFAULT_MAX_DEPTH = 5;
|
|
30
|
+
const DEFAULT_MIN_ASSETS = 3;
|
|
31
|
+
const DEFAULT_SAMPLE_LIMIT = 10;
|
|
32
|
+
const REDUCED_SAMPLE_LIMIT = 3;
|
|
33
|
+
export const AuditFolderStructureInputSchema = z.object({
|
|
34
|
+
/**
|
|
35
|
+
* Folders deeper than this value (root = depth 0) are flagged as a
|
|
36
|
+
* `folder_depth_anomaly` finding. Must be >= 0. Defaults to 5.
|
|
37
|
+
*/
|
|
38
|
+
max_depth: z.number().int().min(0).max(64).default(DEFAULT_MAX_DEPTH),
|
|
39
|
+
/**
|
|
40
|
+
* Collections holding fewer than this many assets are flagged as
|
|
41
|
+
* `low_asset_collections`. Required from caller — exposed as a tunable
|
|
42
|
+
* because what counts as "low" varies widely across libraries. Must be
|
|
43
|
+
* >= 1; defaults to 3.
|
|
44
|
+
*/
|
|
45
|
+
min_assets: z.number().int().min(1).max(10_000).default(DEFAULT_MIN_ASSETS),
|
|
46
|
+
/** Per-finding asset / id sample cap. Defaults to 10. */
|
|
47
|
+
sample_limit: z.number().int().min(1).max(100).default(DEFAULT_SAMPLE_LIMIT),
|
|
48
|
+
});
|
|
49
|
+
export class AuditFolderStructureTool {
|
|
50
|
+
deps;
|
|
51
|
+
name = 'audit_folder_structure';
|
|
52
|
+
description = AUDIT_FOLDER_STRUCTURE_DESCRIPTION;
|
|
53
|
+
constructor(deps) {
|
|
54
|
+
this.deps = deps;
|
|
55
|
+
}
|
|
56
|
+
async run(rawInput = {}) {
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = AuditFolderStructureInputSchema.parse(rawInput);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return {
|
|
63
|
+
ok: false,
|
|
64
|
+
error: createToolError('VALIDATION', err instanceof Error ? err.message : 'invalid input'),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const folders = await this.deps.enumerator.enumerateFolders();
|
|
68
|
+
if (!folders.ok)
|
|
69
|
+
return { ok: false, error: folders.error };
|
|
70
|
+
const assets = await this.deps.enumerator.enumerateAssets();
|
|
71
|
+
if (!assets.ok)
|
|
72
|
+
return { ok: false, error: assets.error };
|
|
73
|
+
const collections = await this.deps.enumerator.enumerateCollections();
|
|
74
|
+
if (!collections.ok)
|
|
75
|
+
return { ok: false, error: collections.error };
|
|
76
|
+
const report = buildReport(folders.folders, assets.assets, collections.collections, parsed);
|
|
77
|
+
return { ok: true, report };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function buildAuditFolderStructureTool(deps) {
|
|
81
|
+
return new AuditFolderStructureTool(deps);
|
|
82
|
+
}
|
|
83
|
+
// ── Detection (pure) ─────────────────────────────────────────────────
|
|
84
|
+
/**
|
|
85
|
+
* Compute the depth of every folder, indexed by id.
|
|
86
|
+
*
|
|
87
|
+
* Roots (parent_id === null) sit at depth 0. Folders whose parent does not
|
|
88
|
+
* appear in the supplied list are still rooted at depth 0 — a missing
|
|
89
|
+
* parent is treated as a graph oddity, not a fatal error, so audit runs
|
|
90
|
+
* never crash on partial workspace snapshots.
|
|
91
|
+
*
|
|
92
|
+
* Cycles (a folder whose parent chain returns to itself) are detected and
|
|
93
|
+
* the offending folder is clamped at depth `maxDepth + 1` so it still
|
|
94
|
+
* surfaces in the anomaly finding without blowing the stack.
|
|
95
|
+
*/
|
|
96
|
+
export function computeFolderDepths(folders, maxDepth) {
|
|
97
|
+
const byId = new Map();
|
|
98
|
+
for (const f of folders)
|
|
99
|
+
byId.set(f.id, f);
|
|
100
|
+
const depths = new Map();
|
|
101
|
+
function depthOf(id, visited) {
|
|
102
|
+
const cached = depths.get(id);
|
|
103
|
+
if (cached !== undefined)
|
|
104
|
+
return cached;
|
|
105
|
+
if (visited.has(id))
|
|
106
|
+
return maxDepth + 1;
|
|
107
|
+
const node = byId.get(id);
|
|
108
|
+
if (node === undefined)
|
|
109
|
+
return 0;
|
|
110
|
+
if (node.parent_id === null) {
|
|
111
|
+
depths.set(id, 0);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
visited.add(id);
|
|
115
|
+
const parentDepth = depthOf(node.parent_id, visited);
|
|
116
|
+
visited.delete(id);
|
|
117
|
+
const d = parentDepth + 1;
|
|
118
|
+
depths.set(id, d);
|
|
119
|
+
return d;
|
|
120
|
+
}
|
|
121
|
+
for (const f of folders)
|
|
122
|
+
depthOf(f.id, new Set());
|
|
123
|
+
return depths;
|
|
124
|
+
}
|
|
125
|
+
export function buildReport(folders, assets, collections, input) {
|
|
126
|
+
const drafts = [];
|
|
127
|
+
// ── Folder depth anomalies ──
|
|
128
|
+
const depths = computeFolderDepths(folders, input.max_depth);
|
|
129
|
+
const deepFolders = folders.filter((f) => (depths.get(f.id) ?? 0) > input.max_depth);
|
|
130
|
+
if (deepFolders.length > 0) {
|
|
131
|
+
const ids = deepFolders.map((f) => f.id);
|
|
132
|
+
drafts.push({
|
|
133
|
+
category: 'folder_depth_anomaly',
|
|
134
|
+
severity: 'warning',
|
|
135
|
+
count: deepFolders.length,
|
|
136
|
+
sample_asset_ids: ids.slice(0, input.sample_limit),
|
|
137
|
+
affected_asset_ids: ids,
|
|
138
|
+
folder_ids: ids,
|
|
139
|
+
message: deepFolders.length === 1
|
|
140
|
+
? `1 folder is nested deeper than max_depth=${input.max_depth}.`
|
|
141
|
+
: `${deepFolders.length} folders are nested deeper than max_depth=${input.max_depth}.`,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
// ── Orphaned assets ──
|
|
145
|
+
const orphans = assets.filter((a) => a.category_id === null);
|
|
146
|
+
if (orphans.length > 0) {
|
|
147
|
+
const ids = orphans.map((a) => a.id);
|
|
148
|
+
drafts.push({
|
|
149
|
+
category: 'orphaned_assets',
|
|
150
|
+
severity: orphans.length >= Math.max(1, Math.ceil(assets.length * 0.25))
|
|
151
|
+
? 'critical'
|
|
152
|
+
: 'warning',
|
|
153
|
+
count: orphans.length,
|
|
154
|
+
sample_asset_ids: ids.slice(0, input.sample_limit),
|
|
155
|
+
affected_asset_ids: ids,
|
|
156
|
+
message: orphans.length === 1
|
|
157
|
+
? '1 asset has no parent folder (orphaned).'
|
|
158
|
+
: `${orphans.length} assets have no parent folder (orphaned).`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// ── Low-asset collections ──
|
|
162
|
+
const lowCollections = collections.filter((c) => c.asset_count < input.min_assets);
|
|
163
|
+
if (lowCollections.length > 0) {
|
|
164
|
+
const ids = lowCollections.map((c) => c.id);
|
|
165
|
+
drafts.push({
|
|
166
|
+
category: 'low_asset_collections',
|
|
167
|
+
severity: 'info',
|
|
168
|
+
count: lowCollections.length,
|
|
169
|
+
sample_asset_ids: ids.slice(0, input.sample_limit),
|
|
170
|
+
affected_asset_ids: ids,
|
|
171
|
+
collection_ids: ids,
|
|
172
|
+
message: `${lowCollections.length} collection${lowCollections.length === 1 ? '' : 's'} hold fewer than ${input.min_assets} assets.`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const findings = drafts.map((d, idx) => {
|
|
176
|
+
const meta = { affected_asset_ids: d.affected_asset_ids };
|
|
177
|
+
if (d.folder_ids !== undefined)
|
|
178
|
+
meta.folder_ids = d.folder_ids;
|
|
179
|
+
if (d.collection_ids !== undefined)
|
|
180
|
+
meta.collection_ids = d.collection_ids;
|
|
181
|
+
return {
|
|
182
|
+
id: `${d.category}:${idx}`,
|
|
183
|
+
category: d.category,
|
|
184
|
+
severity: d.severity,
|
|
185
|
+
count: d.count,
|
|
186
|
+
sample_asset_ids: d.sample_asset_ids,
|
|
187
|
+
message: d.message,
|
|
188
|
+
meta,
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
const nextSteps = buildNextSteps(findings);
|
|
192
|
+
const score = computeAuditScore(findings);
|
|
193
|
+
const summary = summarizeFindings(findings, assets.length);
|
|
194
|
+
const initial = {
|
|
195
|
+
score,
|
|
196
|
+
summary_counts: summary,
|
|
197
|
+
findings,
|
|
198
|
+
next_steps: nextSteps,
|
|
199
|
+
truncated: false,
|
|
200
|
+
};
|
|
201
|
+
return enforceResponseBudget(initial);
|
|
202
|
+
}
|
|
203
|
+
function buildNextSteps(findings) {
|
|
204
|
+
const steps = [];
|
|
205
|
+
for (const finding of findings) {
|
|
206
|
+
if (finding.category !== 'orphaned_assets')
|
|
207
|
+
continue;
|
|
208
|
+
const meta = (finding.meta ?? undefined);
|
|
209
|
+
const targets = meta?.affected_asset_ids ?? [];
|
|
210
|
+
if (targets.length === 0)
|
|
211
|
+
continue;
|
|
212
|
+
steps.push({
|
|
213
|
+
action: 'move_assets',
|
|
214
|
+
tool: 'bulk_move_assets',
|
|
215
|
+
target_asset_ids: targets,
|
|
216
|
+
reason: 'These assets have no parent folder. Move them into a folder via bulk_move_assets.',
|
|
217
|
+
finding_id: finding.id,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return steps;
|
|
221
|
+
}
|
|
222
|
+
// ── Response-budget enforcement ──────────────────────────────────────
|
|
223
|
+
function enforceResponseBudget(report) {
|
|
224
|
+
if (estimateTokens(JSON.stringify(report)) <= HARD_CAP_TOKENS)
|
|
225
|
+
return report;
|
|
226
|
+
let trimmed = {
|
|
227
|
+
...report,
|
|
228
|
+
findings: report.findings.map((f) => ({
|
|
229
|
+
...f,
|
|
230
|
+
sample_asset_ids: f.sample_asset_ids.slice(0, REDUCED_SAMPLE_LIMIT),
|
|
231
|
+
})),
|
|
232
|
+
next_steps: report.next_steps.map((s) => ({
|
|
233
|
+
...s,
|
|
234
|
+
target_asset_ids: s.target_asset_ids.slice(0, REDUCED_SAMPLE_LIMIT),
|
|
235
|
+
})),
|
|
236
|
+
truncated: true,
|
|
237
|
+
truncation_reason: 'Findings sample lists were trimmed to fit the response budget.',
|
|
238
|
+
};
|
|
239
|
+
if (estimateTokens(JSON.stringify(trimmed)) <= HARD_CAP_TOKENS)
|
|
240
|
+
return trimmed;
|
|
241
|
+
for (const dropping of ['info', 'warning']) {
|
|
242
|
+
const keptFindings = trimmed.findings.filter((f) => f.severity !== dropping);
|
|
243
|
+
const keptIds = new Set(keptFindings.map((f) => f.id));
|
|
244
|
+
const keptSteps = trimmed.next_steps.filter((s) => s.finding_id === undefined || keptIds.has(s.finding_id));
|
|
245
|
+
trimmed = {
|
|
246
|
+
...trimmed,
|
|
247
|
+
findings: keptFindings,
|
|
248
|
+
next_steps: keptSteps,
|
|
249
|
+
truncation_reason: `Dropped ${dropping}-severity findings to fit the response budget.`,
|
|
250
|
+
};
|
|
251
|
+
if (estimateTokens(JSON.stringify(trimmed)) <= HARD_CAP_TOKENS) {
|
|
252
|
+
return trimmed;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
...trimmed,
|
|
257
|
+
truncation_reason: 'Report exceeded the response budget even after dropping non-critical findings; consider narrowing scope.',
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=audit-folder-structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-folder-structure.js","sourceRoot":"","sources":["../../../src/tools/audit/audit-folder-structure.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,2EAA2E;AAC3E,8DAA8D;AAC9D,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,wDAAwD;AACxD,2EAA2E;AAC3E,iFAAiF;AACjF,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAC1E,uEAAuE;AACvE,EAAE;AACF,oEAAoE;AACpE,gEAAgE;AAEhE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAqB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAKlB,MAAM,YAAY,CAAC;AAEpB,wEAAwE;AAExE,MAAM,CAAC,MAAM,kCAAkC,GAC7C,oEAAoE;IACpE,sEAAsE;IACtE,kEAAkE;IAClE,kEAAkE;IAClE,kBAAkB,CAAC;AAErB,wEAAwE;AAExE,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAC5B,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAChC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC;IACtD;;;OAGG;IACH,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;IACrE;;;;;OAKG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAC3E,yDAAyD;IACzD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC;CAC7E,CAAC,CAAC;AA8DH,MAAM,OAAO,wBAAwB;IAIN;IAHpB,IAAI,GAAG,wBAAwB,CAAC;IAChC,WAAW,GAAG,kCAAkC,CAAC;IAE1D,YAA6B,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;IAAG,CAAC;IAE/D,KAAK,CAAC,GAAG,CACP,WAAsC,EAAE;QAExC,IAAI,MAAyC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,GAAG,+BAA+B,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,eAAe,CACpB,YAAY,EACZ,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CACrD;aACF,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,CAAC;QAC9D,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC;QAC5D,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QAE1D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC;QACtE,IAAI,CAAC,WAAW,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,CAAC;QAEpE,MAAM,MAAM,GAAG,WAAW,CACxB,OAAO,CAAC,OAAO,EACf,MAAM,CAAC,MAAM,EACb,WAAW,CAAC,WAAW,EACvB,MAAM,CACP,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,UAAU,6BAA6B,CAC3C,IAA8B;IAE9B,OAAO,IAAI,wBAAwB,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,wEAAwE;AAExE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAmC,EACnC,QAAgB;IAEhB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,SAAS,OAAO,CAAC,EAAU,EAAE,OAAoB;QAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO,QAAQ,GAAG,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1B,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAClB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACrD,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnB,MAAM,CAAC,GAAG,WAAW,GAAG,CAAC,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAClB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,OAAmC,EACnC,MAA6C,EAC7C,WAA2C,EAC3C,KAAwC;IAExC,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,+BAA+B;IAC/B,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,SAAS,CACjD,CAAC;IACF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,sBAAsB;YAChC,QAAQ,EAAE,SAAS;YACnB,KAAK,EAAE,WAAW,CAAC,MAAM;YACzB,gBAAgB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;YAClD,kBAAkB,EAAE,GAAG;YACvB,UAAU,EAAE,GAAG;YACf,OAAO,EACL,WAAW,CAAC,MAAM,KAAK,CAAC;gBACtB,CAAC,CAAC,4CAA4C,KAAK,CAAC,SAAS,GAAG;gBAChE,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,6CAA6C,KAAK,CAAC,SAAS,GAAG;SAC3F,CAAC,CAAC;IACL,CAAC;IAED,wBAAwB;IACxB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC;IAC7D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;gBACtE,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,SAAS;YACb,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,gBAAgB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;YAClD,kBAAkB,EAAE,GAAG;YACvB,OAAO,EACL,OAAO,CAAC,MAAM,KAAK,CAAC;gBAClB,CAAC,CAAC,0CAA0C;gBAC5C,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,2CAA2C;SACnE,CAAC,CAAC;IACL,CAAC;IAED,8BAA8B;IAC9B,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,UAAU,CACxC,CAAC;IACF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,uBAAuB;YACjC,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,cAAc,CAAC,MAAM;YAC5B,gBAAgB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;YAClD,kBAAkB,EAAE,GAAG;YACvB,cAAc,EAAE,GAAG;YACnB,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,cAAc,cAAc,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,oBAAoB,KAAK,CAAC,UAAU,UAAU;SACpI,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAmB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QACrD,MAAM,IAAI,GAIN,EAAE,kBAAkB,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS;YAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;QAC/D,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS;YAAE,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,cAAc,CAAC;QAC3E,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,IAAI,GAAG,EAAE;YAC1B,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;YACpC,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,IAAI;SACL,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAE3D,MAAM,OAAO,GAAgB;QAC3B,KAAK;QACL,cAAc,EAAE,OAAO;QACvB,QAAQ;QACR,UAAU,EAAE,SAAS;QACrB,SAAS,EAAE,KAAK;KACjB,CAAC;IACF,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC;AAuBD,SAAS,cAAc,CAAC,QAAqC;IAC3D,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,QAAQ,KAAK,iBAAiB;YAAE,SAAS;QACrD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,SAAS,CAAkC,CAAC;QAC1E,MAAM,OAAO,GAAG,IAAI,EAAE,kBAAkB,IAAI,EAAE,CAAC;QAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACnC,KAAK,CAAC,IAAI,CAAC;YACT,MAAM,EAAE,aAAa;YACrB,IAAI,EAAE,kBAAkB;YACxB,gBAAgB,EAAE,OAAO;YACzB,MAAM,EACJ,mFAAmF;YACrF,UAAU,EAAE,OAAO,CAAC,EAAE;SACvB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wEAAwE;AAExE,SAAS,qBAAqB,CAAC,MAAmB;IAChD,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,eAAe;QAAE,OAAO,MAAM,CAAC;IAE7E,IAAI,OAAO,GAAgB;QACzB,GAAG,MAAM;QACT,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,GAAG,CAAC;YACJ,gBAAgB,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC;SACpE,CAAC,CAAC;QACH,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxC,GAAG,CAAC;YACJ,gBAAgB,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC;SACpE,CAAC,CAAC;QACH,SAAS,EAAE,IAAI;QACf,iBAAiB,EACf,gEAAgE;KACnE,CAAC;IACF,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,eAAe;QAAE,OAAO,OAAO,CAAC;IAE/E,KAAK,MAAM,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,CAAU,EAAE,CAAC;QACpD,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACvD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAC/D,CAAC;QACF,OAAO,GAAG;YACR,GAAG,OAAO;YACV,QAAQ,EAAE,YAAY;YACtB,UAAU,EAAE,SAAS;YACrB,iBAAiB,EAAE,WAAW,QAAQ,gDAAgD;SACvF,CAAC;QACF,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC;YAC/D,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG,OAAO;QACV,iBAAiB,EACf,0GAA0G;KAC7G,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type McpToolError } from '../../conventions/errors.js';
|
|
3
|
+
import { type AuditReport } from './types.js';
|
|
4
|
+
export declare const AUDIT_NAMING_CONVENTIONS_DESCRIPTION: string;
|
|
5
|
+
declare const NL_PATTERNS: {
|
|
6
|
+
readonly 'kebab-case': "^[a-z0-9]+(-[a-z0-9]+)*$";
|
|
7
|
+
readonly snake_case: "^[a-z0-9]+(_[a-z0-9]+)*$";
|
|
8
|
+
readonly camelCase: "^[a-z][a-z0-9]*([A-Z][a-z0-9]*)*$";
|
|
9
|
+
readonly PascalCase: "^[A-Z][a-z0-9]*([A-Z][a-z0-9]*)*$";
|
|
10
|
+
readonly lowercase: "^[a-z0-9._-]+$";
|
|
11
|
+
readonly no_spaces: "^\\S+$";
|
|
12
|
+
readonly with_extension: "^.+\\.[A-Za-z0-9]+$";
|
|
13
|
+
};
|
|
14
|
+
export declare const NL_PATTERN_NAMES: ReadonlyArray<keyof typeof NL_PATTERNS>;
|
|
15
|
+
export declare const AuditNamingConventionsInputSchema: z.ZodObject<{
|
|
16
|
+
/** Which pattern shape `pattern` is using. Defaults to `nl`. */
|
|
17
|
+
pattern_kind: z.ZodDefault<z.ZodEnum<["regex", "nl"]>>;
|
|
18
|
+
/**
|
|
19
|
+
* The pattern itself. When `pattern_kind: 'nl'` must be one of
|
|
20
|
+
* {@link NL_PATTERN_NAMES}. When `pattern_kind: 'regex'` must be a valid
|
|
21
|
+
* JS regex source (no flags).
|
|
22
|
+
*/
|
|
23
|
+
pattern: z.ZodString;
|
|
24
|
+
/** Per-finding asset id sample cap. Defaults to 10. */
|
|
25
|
+
sample_limit: z.ZodDefault<z.ZodNumber>;
|
|
26
|
+
}, "strip", z.ZodTypeAny, {
|
|
27
|
+
sample_limit: number;
|
|
28
|
+
pattern_kind: "regex" | "nl";
|
|
29
|
+
pattern: string;
|
|
30
|
+
}, {
|
|
31
|
+
pattern: string;
|
|
32
|
+
sample_limit?: number | undefined;
|
|
33
|
+
pattern_kind?: "regex" | "nl" | undefined;
|
|
34
|
+
}>;
|
|
35
|
+
export type AuditNamingConventionsInput = z.input<typeof AuditNamingConventionsInputSchema>;
|
|
36
|
+
export type AuditNamingConventionsInputResolved = z.output<typeof AuditNamingConventionsInputSchema>;
|
|
37
|
+
export interface NamingAuditAsset {
|
|
38
|
+
id: string;
|
|
39
|
+
display_file_name: string;
|
|
40
|
+
}
|
|
41
|
+
export interface NamingAuditEnumerator {
|
|
42
|
+
enumerateAssets(): Promise<{
|
|
43
|
+
ok: true;
|
|
44
|
+
assets: NamingAuditAsset[];
|
|
45
|
+
} | {
|
|
46
|
+
ok: false;
|
|
47
|
+
error: McpToolError;
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
export interface AuditNamingConventionsDeps {
|
|
51
|
+
enumerator: NamingAuditEnumerator;
|
|
52
|
+
}
|
|
53
|
+
export type AuditNamingConventionsOutcome = {
|
|
54
|
+
ok: true;
|
|
55
|
+
report: AuditReport;
|
|
56
|
+
} | {
|
|
57
|
+
ok: false;
|
|
58
|
+
error: McpToolError;
|
|
59
|
+
};
|
|
60
|
+
export declare class AuditNamingConventionsTool {
|
|
61
|
+
private readonly deps;
|
|
62
|
+
readonly name = "audit_naming_conventions";
|
|
63
|
+
readonly description: string;
|
|
64
|
+
constructor(deps: AuditNamingConventionsDeps);
|
|
65
|
+
run(rawInput: AuditNamingConventionsInput): Promise<AuditNamingConventionsOutcome>;
|
|
66
|
+
}
|
|
67
|
+
export declare function buildAuditNamingConventionsTool(deps: AuditNamingConventionsDeps): AuditNamingConventionsTool;
|
|
68
|
+
export interface CompiledPattern {
|
|
69
|
+
ok: true;
|
|
70
|
+
regex: RegExp;
|
|
71
|
+
/** Display source for the message field. */
|
|
72
|
+
source: string;
|
|
73
|
+
/** Whether to strip the file extension before matching. */
|
|
74
|
+
strip_extension: boolean;
|
|
75
|
+
}
|
|
76
|
+
export type CompilePatternResult = CompiledPattern | {
|
|
77
|
+
ok: false;
|
|
78
|
+
error: McpToolError;
|
|
79
|
+
};
|
|
80
|
+
export declare function compilePattern(input: AuditNamingConventionsInputResolved): CompilePatternResult;
|
|
81
|
+
export declare function buildReport(assets: ReadonlyArray<NamingAuditAsset>, input: AuditNamingConventionsInputResolved, compiled: CompiledPattern): AuditReport;
|
|
82
|
+
export {};
|
|
83
|
+
//# sourceMappingURL=audit-naming-conventions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-naming-conventions.d.ts","sourceRoot":"","sources":["../../../src/tools/audit/audit-naming-conventions.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEjF,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAIpB,eAAO,MAAM,oCAAoC,QAOM,CAAC;AAIxD,QAAA,MAAM,WAAW;;;;;;;;CAQP,CAAC;AAEX,eAAO,MAAM,gBAAgB,EAA+B,aAAa,CACvE,MAAM,OAAO,WAAW,CACzB,CAAC;AAqBF,eAAO,MAAM,iCAAiC;IAC5C,gEAAgE;;IAEhE;;;;OAIG;;IAEH,uDAAuD;;;;;;;;;;EAEvD,CAAC;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAC/C,OAAO,iCAAiC,CACzC,CAAC;AACF,MAAM,MAAM,mCAAmC,GAAG,CAAC,CAAC,MAAM,CACxD,OAAO,iCAAiC,CACzC,CAAC;AAIF,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,eAAe,IAAI,OAAO,CACtB;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;KAAE,GACxC;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,CACrC,CAAC;CACH;AAID,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,qBAAqB,CAAC;CACnC;AAED,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACjC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAEvC,qBAAa,0BAA0B;IAIzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,QAAQ,CAAC,IAAI,8BAA8B;IAC3C,QAAQ,CAAC,WAAW,SAAwC;gBAE/B,IAAI,EAAE,0BAA0B;IAEvD,GAAG,CACP,QAAQ,EAAE,2BAA2B,GACpC,OAAO,CAAC,6BAA6B,CAAC;CAuB1C;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,0BAA0B,GAC/B,0BAA0B,CAE5B;AAID,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,eAAe,EAAE,OAAO,CAAC;CAC1B;AACD,MAAM,MAAM,oBAAoB,GAC5B,eAAe,GACf;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAEvC,wBAAgB,cAAc,CAC5B,KAAK,EAAE,mCAAmC,GACzC,oBAAoB,CAwCtB;AAID,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,CAAC,gBAAgB,CAAC,EACvC,KAAK,EAAE,mCAAmC,EAC1C,QAAQ,EAAE,eAAe,GACxB,WAAW,CA+Cb"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// ── audit_naming_conventions (T4, Phase 1.5) ─────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Read-only audit tool. Compares every asset's `display_file_name` against
|
|
4
|
+
// a caller-supplied target naming pattern and reports the violators.
|
|
5
|
+
//
|
|
6
|
+
// Two pattern modes are supported:
|
|
7
|
+
//
|
|
8
|
+
// 1. `regex` — raw JavaScript RegExp source (no flags). The caller is
|
|
9
|
+
// expected to anchor with `^` / `$` if a full-match is desired; the
|
|
10
|
+
// audit anchors automatically when the pattern lacks both anchors
|
|
11
|
+
// (matching the friendlier "does the whole filename look right?"
|
|
12
|
+
// mental model that most callers want).
|
|
13
|
+
//
|
|
14
|
+
// 2. `nl` — a small natural-language vocabulary that maps to canonical
|
|
15
|
+
// regex. Useful for prompts where the caller doesn't think in regex:
|
|
16
|
+
//
|
|
17
|
+
// - `kebab-case` → `^[a-z0-9]+(-[a-z0-9]+)*$`
|
|
18
|
+
// - `snake_case` → `^[a-z0-9]+(_[a-z0-9]+)*$`
|
|
19
|
+
// - `camelCase` → `^[a-z][a-z0-9]*([A-Z][a-z0-9]*)*$`
|
|
20
|
+
// - `PascalCase` → `^[A-Z][a-z0-9]*([A-Z][a-z0-9]*)*$`
|
|
21
|
+
// - `lowercase` → `^[a-z0-9._-]+$`
|
|
22
|
+
// - `no_spaces` → `^\S+$`
|
|
23
|
+
// - `with_extension` → `^.+\.[A-Za-z0-9]+$`
|
|
24
|
+
//
|
|
25
|
+
// File extensions are stripped from the candidate before regex
|
|
26
|
+
// matching for every NL pattern EXCEPT `with_extension` (where the
|
|
27
|
+
// extension itself is part of the contract).
|
|
28
|
+
//
|
|
29
|
+
// Read-only. Emits a single `naming_violation` finding plus a
|
|
30
|
+
// `bulk_normalize_filenames` next-step hint pointing at the violating asset
|
|
31
|
+
// ids so the caller can route the fix through the dry-run framework.
|
|
32
|
+
import { z } from 'zod';
|
|
33
|
+
import { createToolError } from '../../conventions/errors.js';
|
|
34
|
+
import { estimateTokens, HARD_CAP_TOKENS } from '../../conventions/response-budget.js';
|
|
35
|
+
import { computeAuditScore, summarizeFindings, } from './types.js';
|
|
36
|
+
// ── Tool description ─────────────────────────────────────────────────
|
|
37
|
+
export const AUDIT_NAMING_CONVENTIONS_DESCRIPTION = 'Read-only audit of asset filename hygiene. Accepts a target pattern ' +
|
|
38
|
+
'(`pattern_kind: regex` for a raw JS regex, or `pattern_kind: nl` for ' +
|
|
39
|
+
'a friendly preset like kebab-case / snake_case / camelCase / ' +
|
|
40
|
+
'PascalCase / lowercase / no_spaces / with_extension) and reports ' +
|
|
41
|
+
'every asset whose `display_file_name` does not conform. Returns a ' +
|
|
42
|
+
'0-100 score, structured findings, and a next-step hint pointing at ' +
|
|
43
|
+
'bulk_normalize_filenames. Does not mutate anything.';
|
|
44
|
+
// ── NL → regex catalogue ─────────────────────────────────────────────
|
|
45
|
+
const NL_PATTERNS = {
|
|
46
|
+
'kebab-case': '^[a-z0-9]+(-[a-z0-9]+)*$',
|
|
47
|
+
snake_case: '^[a-z0-9]+(_[a-z0-9]+)*$',
|
|
48
|
+
camelCase: '^[a-z][a-z0-9]*([A-Z][a-z0-9]*)*$',
|
|
49
|
+
PascalCase: '^[A-Z][a-z0-9]*([A-Z][a-z0-9]*)*$',
|
|
50
|
+
lowercase: '^[a-z0-9._-]+$',
|
|
51
|
+
no_spaces: '^\\S+$',
|
|
52
|
+
with_extension: '^.+\\.[A-Za-z0-9]+$',
|
|
53
|
+
};
|
|
54
|
+
export const NL_PATTERN_NAMES = Object.keys(NL_PATTERNS);
|
|
55
|
+
/**
|
|
56
|
+
* NL preset names that compare against the filename SANS extension. Only
|
|
57
|
+
* `with_extension` compares against the full filename because the extension
|
|
58
|
+
* is part of its contract.
|
|
59
|
+
*/
|
|
60
|
+
const NL_PATTERNS_WITHOUT_EXTENSION = new Set([
|
|
61
|
+
'kebab-case',
|
|
62
|
+
'snake_case',
|
|
63
|
+
'camelCase',
|
|
64
|
+
'PascalCase',
|
|
65
|
+
'lowercase',
|
|
66
|
+
'no_spaces',
|
|
67
|
+
]);
|
|
68
|
+
// ── Input schema ─────────────────────────────────────────────────────
|
|
69
|
+
const DEFAULT_SAMPLE_LIMIT = 10;
|
|
70
|
+
const REDUCED_SAMPLE_LIMIT = 3;
|
|
71
|
+
export const AuditNamingConventionsInputSchema = z.object({
|
|
72
|
+
/** Which pattern shape `pattern` is using. Defaults to `nl`. */
|
|
73
|
+
pattern_kind: z.enum(['regex', 'nl']).default('nl'),
|
|
74
|
+
/**
|
|
75
|
+
* The pattern itself. When `pattern_kind: 'nl'` must be one of
|
|
76
|
+
* {@link NL_PATTERN_NAMES}. When `pattern_kind: 'regex'` must be a valid
|
|
77
|
+
* JS regex source (no flags).
|
|
78
|
+
*/
|
|
79
|
+
pattern: z.string().min(1),
|
|
80
|
+
/** Per-finding asset id sample cap. Defaults to 10. */
|
|
81
|
+
sample_limit: z.number().int().min(1).max(100).default(DEFAULT_SAMPLE_LIMIT),
|
|
82
|
+
});
|
|
83
|
+
export class AuditNamingConventionsTool {
|
|
84
|
+
deps;
|
|
85
|
+
name = 'audit_naming_conventions';
|
|
86
|
+
description = AUDIT_NAMING_CONVENTIONS_DESCRIPTION;
|
|
87
|
+
constructor(deps) {
|
|
88
|
+
this.deps = deps;
|
|
89
|
+
}
|
|
90
|
+
async run(rawInput) {
|
|
91
|
+
let parsed;
|
|
92
|
+
try {
|
|
93
|
+
parsed = AuditNamingConventionsInputSchema.parse(rawInput);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
error: createToolError('VALIDATION', err instanceof Error ? err.message : 'invalid input'),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const compiled = compilePattern(parsed);
|
|
102
|
+
if (!compiled.ok)
|
|
103
|
+
return { ok: false, error: compiled.error };
|
|
104
|
+
const enumerated = await this.deps.enumerator.enumerateAssets();
|
|
105
|
+
if (!enumerated.ok)
|
|
106
|
+
return { ok: false, error: enumerated.error };
|
|
107
|
+
const report = buildReport(enumerated.assets, parsed, compiled);
|
|
108
|
+
return { ok: true, report };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
export function buildAuditNamingConventionsTool(deps) {
|
|
112
|
+
return new AuditNamingConventionsTool(deps);
|
|
113
|
+
}
|
|
114
|
+
export function compilePattern(input) {
|
|
115
|
+
if (input.pattern_kind === 'nl') {
|
|
116
|
+
const key = input.pattern;
|
|
117
|
+
if (!(key in NL_PATTERNS)) {
|
|
118
|
+
return {
|
|
119
|
+
ok: false,
|
|
120
|
+
error: createToolError('VALIDATION', `Unknown NL pattern '${input.pattern}'. Supported: ${NL_PATTERN_NAMES.join(', ')}.`),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
regex: new RegExp(NL_PATTERNS[key]),
|
|
126
|
+
source: key,
|
|
127
|
+
strip_extension: NL_PATTERNS_WITHOUT_EXTENSION.has(key),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
let source = input.pattern;
|
|
131
|
+
if (!source.startsWith('^') && !source.endsWith('$')) {
|
|
132
|
+
source = `^${source}$`;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
return {
|
|
136
|
+
ok: true,
|
|
137
|
+
regex: new RegExp(source),
|
|
138
|
+
source: input.pattern,
|
|
139
|
+
strip_extension: false,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
error: createToolError('VALIDATION', `Invalid regex '${input.pattern}': ${err instanceof Error ? err.message : String(err)}`),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// ── Detection (pure) ─────────────────────────────────────────────────
|
|
150
|
+
export function buildReport(assets, input, compiled) {
|
|
151
|
+
const violations = [];
|
|
152
|
+
for (const asset of assets) {
|
|
153
|
+
const candidate = compiled.strip_extension
|
|
154
|
+
? stripExtension(asset.display_file_name)
|
|
155
|
+
: asset.display_file_name;
|
|
156
|
+
if (!compiled.regex.test(candidate))
|
|
157
|
+
violations.push(asset);
|
|
158
|
+
}
|
|
159
|
+
const findings = [];
|
|
160
|
+
if (violations.length > 0) {
|
|
161
|
+
const ids = violations.map((a) => a.id);
|
|
162
|
+
const severity = violations.length >=
|
|
163
|
+
Math.max(1, Math.ceil(assets.length * 0.25))
|
|
164
|
+
? 'critical'
|
|
165
|
+
: 'warning';
|
|
166
|
+
findings.push({
|
|
167
|
+
id: 'naming_violation:0',
|
|
168
|
+
category: 'naming_violation',
|
|
169
|
+
severity,
|
|
170
|
+
count: violations.length,
|
|
171
|
+
sample_asset_ids: ids.slice(0, input.sample_limit),
|
|
172
|
+
message: `${violations.length} asset${violations.length === 1 ? '' : 's'} do not match the target naming pattern (${input.pattern_kind === 'nl' ? compiled.source : 'regex'}: ${compiled.source}).`,
|
|
173
|
+
meta: {
|
|
174
|
+
affected_asset_ids: ids,
|
|
175
|
+
sample_violations: violations.slice(0, input.sample_limit).map((a) => ({
|
|
176
|
+
id: a.id,
|
|
177
|
+
name: a.display_file_name,
|
|
178
|
+
})),
|
|
179
|
+
pattern_source: compiled.source,
|
|
180
|
+
pattern_kind: input.pattern_kind,
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const nextSteps = buildNextSteps(findings, compiled.source, input.pattern_kind);
|
|
185
|
+
const score = computeAuditScore(findings);
|
|
186
|
+
const summary = summarizeFindings(findings, assets.length);
|
|
187
|
+
const initial = {
|
|
188
|
+
score,
|
|
189
|
+
summary_counts: summary,
|
|
190
|
+
findings,
|
|
191
|
+
next_steps: nextSteps,
|
|
192
|
+
truncated: false,
|
|
193
|
+
};
|
|
194
|
+
return enforceResponseBudget(initial);
|
|
195
|
+
}
|
|
196
|
+
function stripExtension(name) {
|
|
197
|
+
const dot = name.lastIndexOf('.');
|
|
198
|
+
if (dot <= 0 || dot === name.length - 1)
|
|
199
|
+
return name;
|
|
200
|
+
return name.slice(0, dot);
|
|
201
|
+
}
|
|
202
|
+
function buildNextSteps(findings, patternSource, patternKind) {
|
|
203
|
+
const steps = [];
|
|
204
|
+
for (const finding of findings) {
|
|
205
|
+
const meta = (finding.meta ?? undefined);
|
|
206
|
+
const targets = meta?.affected_asset_ids ?? [];
|
|
207
|
+
if (targets.length === 0)
|
|
208
|
+
continue;
|
|
209
|
+
steps.push({
|
|
210
|
+
action: 'normalize_filenames',
|
|
211
|
+
tool: 'bulk_normalize_filenames',
|
|
212
|
+
target_asset_ids: targets,
|
|
213
|
+
reason: `These assets violate the target naming pattern (${patternKind}: ${patternSource}). Normalise them via bulk_normalize_filenames.`,
|
|
214
|
+
finding_id: finding.id,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return steps;
|
|
218
|
+
}
|
|
219
|
+
// ── Response-budget enforcement ──────────────────────────────────────
|
|
220
|
+
function enforceResponseBudget(report) {
|
|
221
|
+
if (estimateTokens(JSON.stringify(report)) <= HARD_CAP_TOKENS)
|
|
222
|
+
return report;
|
|
223
|
+
const trimmed = {
|
|
224
|
+
...report,
|
|
225
|
+
findings: report.findings.map((f) => ({
|
|
226
|
+
...f,
|
|
227
|
+
sample_asset_ids: f.sample_asset_ids.slice(0, REDUCED_SAMPLE_LIMIT),
|
|
228
|
+
})),
|
|
229
|
+
next_steps: report.next_steps.map((s) => ({
|
|
230
|
+
...s,
|
|
231
|
+
target_asset_ids: s.target_asset_ids.slice(0, REDUCED_SAMPLE_LIMIT),
|
|
232
|
+
})),
|
|
233
|
+
truncated: true,
|
|
234
|
+
truncation_reason: 'Findings sample lists and next-step target lists were trimmed to fit the response budget.',
|
|
235
|
+
};
|
|
236
|
+
return trimmed;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=audit-naming-conventions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-naming-conventions.js","sourceRoot":"","sources":["../../../src/tools/audit/audit-naming-conventions.ts"],"names":[],"mappings":"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"}
|