vibecheck-score 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.
Files changed (87) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +217 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/output/confirm.d.ts +3 -0
  6. package/dist/output/confirm.d.ts.map +1 -0
  7. package/dist/output/confirm.js +37 -0
  8. package/dist/output/confirm.js.map +1 -0
  9. package/dist/output/narrative.d.ts +3 -0
  10. package/dist/output/narrative.d.ts.map +1 -0
  11. package/dist/output/narrative.js +94 -0
  12. package/dist/output/narrative.js.map +1 -0
  13. package/dist/output/terminal.d.ts +4 -0
  14. package/dist/output/terminal.d.ts.map +1 -0
  15. package/dist/output/terminal.js +95 -0
  16. package/dist/output/terminal.js.map +1 -0
  17. package/dist/scanners/agents.d.ts +7 -0
  18. package/dist/scanners/agents.d.ts.map +1 -0
  19. package/dist/scanners/agents.js +95 -0
  20. package/dist/scanners/agents.js.map +1 -0
  21. package/dist/scanners/deploy.d.ts +7 -0
  22. package/dist/scanners/deploy.d.ts.map +1 -0
  23. package/dist/scanners/deploy.js +139 -0
  24. package/dist/scanners/deploy.js.map +1 -0
  25. package/dist/scanners/environment.d.ts +7 -0
  26. package/dist/scanners/environment.d.ts.map +1 -0
  27. package/dist/scanners/environment.js +110 -0
  28. package/dist/scanners/environment.js.map +1 -0
  29. package/dist/scanners/index.d.ts +7 -0
  30. package/dist/scanners/index.d.ts.map +1 -0
  31. package/dist/scanners/index.js +23 -0
  32. package/dist/scanners/index.js.map +1 -0
  33. package/dist/scanners/mcp.d.ts +7 -0
  34. package/dist/scanners/mcp.d.ts.map +1 -0
  35. package/dist/scanners/mcp.js +138 -0
  36. package/dist/scanners/mcp.js.map +1 -0
  37. package/dist/scanners/memory.d.ts +7 -0
  38. package/dist/scanners/memory.d.ts.map +1 -0
  39. package/dist/scanners/memory.js +131 -0
  40. package/dist/scanners/memory.js.map +1 -0
  41. package/dist/scanners/orchestration.d.ts +7 -0
  42. package/dist/scanners/orchestration.d.ts.map +1 -0
  43. package/dist/scanners/orchestration.js +99 -0
  44. package/dist/scanners/orchestration.js.map +1 -0
  45. package/dist/scanners/repositories.d.ts +7 -0
  46. package/dist/scanners/repositories.d.ts.map +1 -0
  47. package/dist/scanners/repositories.js +301 -0
  48. package/dist/scanners/repositories.js.map +1 -0
  49. package/dist/scanners/security.d.ts +7 -0
  50. package/dist/scanners/security.d.ts.map +1 -0
  51. package/dist/scanners/security.js +113 -0
  52. package/dist/scanners/security.js.map +1 -0
  53. package/dist/scanners/social.d.ts +7 -0
  54. package/dist/scanners/social.d.ts.map +1 -0
  55. package/dist/scanners/social.js +68 -0
  56. package/dist/scanners/social.js.map +1 -0
  57. package/dist/scanners/universal-file.d.ts +10 -0
  58. package/dist/scanners/universal-file.d.ts.map +1 -0
  59. package/dist/scanners/universal-file.js +526 -0
  60. package/dist/scanners/universal-file.js.map +1 -0
  61. package/dist/scanners/utils.d.ts +6 -0
  62. package/dist/scanners/utils.d.ts.map +1 -0
  63. package/dist/scanners/utils.js +51 -0
  64. package/dist/scanners/utils.js.map +1 -0
  65. package/dist/scanners/workspace.d.ts +3 -0
  66. package/dist/scanners/workspace.d.ts.map +1 -0
  67. package/dist/scanners/workspace.js +59 -0
  68. package/dist/scanners/workspace.js.map +1 -0
  69. package/dist/scoring/engine.d.ts +11 -0
  70. package/dist/scoring/engine.d.ts.map +1 -0
  71. package/dist/scoring/engine.js +85 -0
  72. package/dist/scoring/engine.js.map +1 -0
  73. package/dist/scoring/tiers.d.ts +11 -0
  74. package/dist/scoring/tiers.d.ts.map +1 -0
  75. package/dist/scoring/tiers.js +20 -0
  76. package/dist/scoring/tiers.js.map +1 -0
  77. package/dist/taxonomy/classifier.d.ts +9 -0
  78. package/dist/taxonomy/classifier.d.ts.map +1 -0
  79. package/dist/taxonomy/classifier.js +44 -0
  80. package/dist/taxonomy/classifier.js.map +1 -0
  81. package/dist/taxonomy/registry.json +189 -0
  82. package/dist/types.d.ts +109 -0
  83. package/dist/types.d.ts.map +1 -0
  84. package/dist/types.js +58 -0
  85. package/dist/types.js.map +1 -0
  86. package/package.json +44 -0
  87. package/src/taxonomy/registry.json +189 -0
@@ -0,0 +1,51 @@
1
+ import { exec } from "node:child_process";
2
+ import { access, readFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { constants } from "node:fs";
5
+ export function expandHome(p) {
6
+ if (p.startsWith("~/"))
7
+ return p.replace("~", homedir());
8
+ if (p === "~")
9
+ return homedir();
10
+ return p;
11
+ }
12
+ export async function fileExists(path) {
13
+ try {
14
+ await access(expandHome(path), constants.R_OK);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ export async function readFileIfExists(path) {
22
+ try {
23
+ return await readFile(expandHome(path), "utf-8");
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ export async function readJsonIfExists(path) {
30
+ const content = await readFileIfExists(path);
31
+ if (content === null)
32
+ return null;
33
+ try {
34
+ return JSON.parse(content);
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ export function shellOutput(cmd, timeoutMs = 5000) {
41
+ return new Promise((resolve) => {
42
+ exec(cmd, { timeout: timeoutMs }, (error, stdout) => {
43
+ if (error) {
44
+ resolve(null);
45
+ return;
46
+ }
47
+ resolve(stdout.trim());
48
+ });
49
+ });
50
+ }
51
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/scanners/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,OAAO,EAAE,CAAC;IAChC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAI,IAAY;IACpD,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAM,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAW,EACX,SAAS,GAAG,IAAI;IAEhB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAClD,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO;YACT,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function isMonorepo(root: string): Promise<boolean>;
2
+ export declare function discoverWorkspaces(root: string, cap?: number): Promise<string[]>;
3
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/scanners/workspace.ts"],"names":[],"mappings":"AAqBA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA8BlF"}
@@ -0,0 +1,59 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { fileExists, readJsonIfExists } from "./utils.js";
4
+ const SKIP_DIRS = new Set([
5
+ "node_modules", ".git", "dist", "build", ".next", ".turbo", ".cache",
6
+ ]);
7
+ const MONOREPO_INDICATORS = [
8
+ "pnpm-workspace.yaml",
9
+ "turbo.json",
10
+ "nx.json",
11
+ "lerna.json",
12
+ "rush.json",
13
+ ];
14
+ export async function isMonorepo(root) {
15
+ for (const indicator of MONOREPO_INDICATORS) {
16
+ if (await fileExists(join(root, indicator)))
17
+ return true;
18
+ }
19
+ const pkg = await readJsonIfExists(join(root, "package.json"));
20
+ if (pkg?.workspaces)
21
+ return true;
22
+ return false;
23
+ }
24
+ export async function discoverWorkspaces(root, cap = 20) {
25
+ const mono = await isMonorepo(root);
26
+ if (!mono)
27
+ return [];
28
+ const dirs = [];
29
+ try {
30
+ const level1 = await readdir(root, { withFileTypes: true });
31
+ for (const d of level1) {
32
+ if (!d.isDirectory() || SKIP_DIRS.has(d.name) || d.name.startsWith("."))
33
+ continue;
34
+ const l1 = join(root, d.name);
35
+ if (await fileExists(join(l1, "package.json"))) {
36
+ dirs.push(l1);
37
+ if (dirs.length >= cap)
38
+ return dirs;
39
+ }
40
+ try {
41
+ const level2 = await readdir(l1, { withFileTypes: true });
42
+ for (const d2 of level2) {
43
+ if (!d2.isDirectory() || SKIP_DIRS.has(d2.name) || d2.name.startsWith("."))
44
+ continue;
45
+ const l2 = join(l1, d2.name);
46
+ if (await fileExists(join(l2, "package.json"))) {
47
+ dirs.push(l2);
48
+ if (dirs.length >= cap)
49
+ return dirs;
50
+ }
51
+ }
52
+ }
53
+ catch { /* not readable */ }
54
+ }
55
+ }
56
+ catch { /* root not readable */ }
57
+ return dirs;
58
+ }
59
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/scanners/workspace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type Detection, type CategoryScore, type ScoreResult, type TypeCode, type PioneerStatus, type TierTitle } from "../types.js";
2
+ export declare function computeCategoryScores(detections: Detection[]): CategoryScore[];
3
+ export declare function computeLevel(categories: CategoryScore[]): number;
4
+ export declare function assignTier(level: number): {
5
+ title: TierTitle;
6
+ tagline: string;
7
+ };
8
+ export declare function computeTypeCode(categories: CategoryScore[]): TypeCode;
9
+ export declare function evaluatePioneer(detections: Detection[]): PioneerStatus;
10
+ export declare function computeScore(detections: Detection[]): ScoreResult;
11
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/scoring/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,aAAa,EAElB,KAAK,SAAS,EAKf,MAAM,aAAa,CAAC;AAErB,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,aAAa,EAAE,CAiC9E;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,MAAM,CAQhE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAO/E;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,QAAQ,CAmBrE;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,aAAa,CAWtE;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,WAAW,CAQjE"}
@@ -0,0 +1,85 @@
1
+ import { TAXONOMY_CATEGORIES, CATEGORY_WEIGHTS, TIER_POINTS, TIER_TITLES, } from "../types.js";
2
+ export function computeCategoryScores(detections) {
3
+ return TAXONOMY_CATEGORIES.map((category) => {
4
+ const categoryDetections = detections.filter((d) => d.category === category);
5
+ if (categoryDetections.length === 0) {
6
+ return { category, score: 0, detectionCount: 0, topTier: "basic" };
7
+ }
8
+ let raw = 0;
9
+ let topTier = "basic";
10
+ const tierRank = { basic: 0, intermediate: 1, advanced: 2, elite: 3 };
11
+ for (const d of categoryDetections) {
12
+ raw += d.points ?? TIER_POINTS[d.tier];
13
+ if (tierRank[d.tier] > tierRank[topTier]) {
14
+ topTier = d.tier;
15
+ }
16
+ }
17
+ // Innovation bonus: +3 per high-confidence, +1 per medium-confidence unknown
18
+ for (const d of categoryDetections) {
19
+ if (d.taxonomyMatch === null) {
20
+ if (d.confidence === "high")
21
+ raw += 3;
22
+ else if (d.confidence === "medium")
23
+ raw += 1;
24
+ }
25
+ }
26
+ return {
27
+ category,
28
+ score: Math.min(100, raw),
29
+ detectionCount: categoryDetections.length,
30
+ topTier,
31
+ };
32
+ });
33
+ }
34
+ export function computeLevel(categories) {
35
+ const scoreMap = new Map(categories.map((c) => [c.category, c.score]));
36
+ let level = 0;
37
+ for (const cat of TAXONOMY_CATEGORIES) {
38
+ const score = scoreMap.get(cat) ?? 0;
39
+ level += score * CATEGORY_WEIGHTS[cat];
40
+ }
41
+ return Math.round(Math.min(100, Math.max(0, level)));
42
+ }
43
+ export function assignTier(level) {
44
+ for (const t of TIER_TITLES) {
45
+ if (level >= t.min && level <= t.max) {
46
+ return { title: t.title, tagline: t.tagline };
47
+ }
48
+ }
49
+ return { title: TIER_TITLES[TIER_TITLES.length - 1].title, tagline: TIER_TITLES[TIER_TITLES.length - 1].tagline };
50
+ }
51
+ export function computeTypeCode(categories) {
52
+ const scoreOf = (cat) => categories.find((c) => c.category === cat)?.score ?? 0;
53
+ const intelligence = scoreOf("intelligence") >= 50 ? "M" : "V";
54
+ const autonomy = scoreOf("autonomy") >= 50 ? "A" : "G";
55
+ const ship = scoreOf("ship") >= 50 ? "R" : "C";
56
+ const avgDepth = (scoreOf("tooling") + scoreOf("continuity") + scoreOf("ops")) / 3;
57
+ const depth = avgDepth >= 50 ? "D" : "L";
58
+ return {
59
+ code: `${intelligence}${autonomy}${ship}${depth}`,
60
+ intelligence,
61
+ autonomy,
62
+ ship,
63
+ depth,
64
+ };
65
+ }
66
+ export function evaluatePioneer(detections) {
67
+ const innovations = detections.filter((d) => d.taxonomyMatch === null);
68
+ const highConfidenceCount = innovations.filter((d) => d.confidence === "high").length;
69
+ const mediumConfidenceCount = innovations.filter((d) => d.confidence === "medium").length;
70
+ return {
71
+ isPioneer: highConfidenceCount >= 1 || mediumConfidenceCount >= 3,
72
+ highConfidenceCount,
73
+ mediumConfidenceCount,
74
+ innovations,
75
+ };
76
+ }
77
+ export function computeScore(detections) {
78
+ const categories = computeCategoryScores(detections);
79
+ const level = computeLevel(categories);
80
+ const tier = assignTier(level);
81
+ const typeCode = computeTypeCode(categories);
82
+ const pioneer = evaluatePioneer(detections);
83
+ return { level, categories, tier, typeCode, pioneer };
84
+ }
85
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/scoring/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type TierTitle } from "../types.js";
2
+ export declare function getTierForLevel(level: number): {
3
+ title: TierTitle;
4
+ tagline: string;
5
+ };
6
+ export declare function getNextTier(currentTitle: TierTitle): {
7
+ title: TierTitle;
8
+ tagline: string;
9
+ minLevel: number;
10
+ } | null;
11
+ //# sourceMappingURL=tiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiers.d.ts","sourceRoot":"","sources":["../../src/scoring/tiers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAE1D,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAUpF;AAED,wBAAgB,WAAW,CACzB,YAAY,EAAE,SAAS,GACtB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKhE"}
@@ -0,0 +1,20 @@
1
+ import { TIER_TITLES } from "../types.js";
2
+ export function getTierForLevel(level) {
3
+ for (const t of TIER_TITLES) {
4
+ if (level >= t.min && level <= t.max) {
5
+ return { title: t.title, tagline: t.tagline };
6
+ }
7
+ }
8
+ return {
9
+ title: TIER_TITLES[TIER_TITLES.length - 1].title,
10
+ tagline: TIER_TITLES[TIER_TITLES.length - 1].tagline,
11
+ };
12
+ }
13
+ export function getNextTier(currentTitle) {
14
+ const idx = TIER_TITLES.findIndex((t) => t.title === currentTitle);
15
+ if (idx < 0 || idx >= TIER_TITLES.length - 1)
16
+ return null;
17
+ const next = TIER_TITLES[idx + 1];
18
+ return { title: next.title, tagline: next.tagline, minLevel: next.min };
19
+ }
20
+ //# sourceMappingURL=tiers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiers.js","sourceRoot":"","sources":["../../src/scoring/tiers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,aAAa,CAAC;AAE1D,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;YACrC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QAChD,CAAC;IACH,CAAC;IACD,OAAO;QACL,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK;QAChD,OAAO,EAAE,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,YAAuB;IAEvB,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC;IACnE,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAClC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Detection } from "../types.js";
2
+ export interface RawFinding {
3
+ id: string;
4
+ source: string;
5
+ confidence?: "high" | "medium" | "low";
6
+ details?: Record<string, unknown>;
7
+ }
8
+ export declare function classify(findings: RawFinding[]): Detection[];
9
+ //# sourceMappingURL=classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../src/taxonomy/classifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAqBD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,SAAS,EAAE,CAiC5D"}
@@ -0,0 +1,44 @@
1
+ import registryData from "./registry.json" with { type: "json" };
2
+ let registry = null;
3
+ function getRegistry() {
4
+ if (registry)
5
+ return registry;
6
+ registry = new Map();
7
+ for (const entry of registryData) {
8
+ registry.set(entry.id, entry);
9
+ }
10
+ return registry;
11
+ }
12
+ export function classify(findings) {
13
+ const reg = getRegistry();
14
+ const detections = [];
15
+ for (const finding of findings) {
16
+ const entry = reg.get(finding.id);
17
+ if (entry) {
18
+ detections.push({
19
+ id: finding.id,
20
+ category: entry.category,
21
+ name: entry.name,
22
+ source: finding.source,
23
+ confidence: finding.confidence ?? "high",
24
+ tier: entry.tier,
25
+ taxonomyMatch: entry.id,
26
+ details: finding.details,
27
+ });
28
+ }
29
+ else {
30
+ detections.push({
31
+ id: finding.id,
32
+ category: "tooling",
33
+ name: finding.id,
34
+ source: finding.source,
35
+ confidence: finding.confidence ?? "medium",
36
+ tier: "advanced",
37
+ taxonomyMatch: null,
38
+ details: finding.details,
39
+ });
40
+ }
41
+ }
42
+ return detections;
43
+ }
44
+ //# sourceMappingURL=classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../src/taxonomy/classifier.ts"],"names":[],"mappings":"AAKA,OAAO,YAAY,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAiBjE,IAAI,QAAQ,GAAsC,IAAI,CAAC;AAEvD,SAAS,WAAW;IAClB,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC5C,KAAK,MAAM,KAAK,IAAI,YAA+B,EAAE,CAAC;QACpD,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,QAAsB;IAC7C,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;IAC1B,MAAM,UAAU,GAAgB,EAAE,CAAC;IAEnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAElC,IAAI,KAAK,EAAE,CAAC;YACV,UAAU,CAAC,IAAI,CAAC;gBACd,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,MAAM;gBACxC,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,aAAa,EAAE,KAAK,CAAC,EAAE;gBACvB,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC;gBACd,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,OAAO,CAAC,EAAE;gBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,QAAQ;gBAC1C,IAAI,EAAE,UAAU;gBAChB,aAAa,EAAE,IAAI;gBACnB,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,189 @@
1
+ [
2
+ { "id": "anthropic-api-key", "name": "Anthropic API Key", "category": "intelligence", "tier": "advanced", "signals": ["ANTHROPIC_API_KEY"] },
3
+ { "id": "openai-api-key", "name": "OpenAI API Key", "category": "intelligence", "tier": "intermediate", "signals": ["OPENAI_API_KEY"] },
4
+ { "id": "google-api-key", "name": "Google Gemini API Key", "category": "intelligence", "tier": "intermediate", "signals": ["GOOGLE_API_KEY", "GEMINI_API_KEY"] },
5
+ { "id": "xai-api-key", "name": "xAI API Key", "category": "intelligence", "tier": "intermediate", "signals": ["XAI_API_KEY"] },
6
+ { "id": "mistral-api-key", "name": "Mistral API Key", "category": "intelligence", "tier": "intermediate", "signals": ["MISTRAL_API_KEY"] },
7
+ { "id": "groq-api-key", "name": "Groq API Key", "category": "intelligence", "tier": "intermediate", "signals": ["GROQ_API_KEY"] },
8
+ { "id": "together-api-key", "name": "Together API Key", "category": "intelligence", "tier": "intermediate", "signals": ["TOGETHER_API_KEY"] },
9
+ { "id": "fireworks-api-key", "name": "Fireworks API Key", "category": "intelligence", "tier": "intermediate", "signals": ["FIREWORKS_API_KEY"] },
10
+ { "id": "azure-openai-api-key", "name": "Azure OpenAI API Key", "category": "intelligence", "tier": "intermediate", "signals": ["AZURE_OPENAI_API_KEY"] },
11
+ { "id": "model-routing", "name": "Model routing aliases", "category": "intelligence", "tier": "advanced", "signals": ["alias.*model"] },
12
+ { "id": "local-ollama", "name": "Ollama (local models)", "category": "intelligence", "tier": "advanced", "signals": ["which ollama"] },
13
+ { "id": "local-lmstudio", "name": "LM Studio (local models)", "category": "intelligence", "tier": "advanced", "signals": ["which lms"] },
14
+
15
+ { "id": "claude-code", "name": "Claude Code CLI", "category": "tooling", "tier": "advanced", "signals": ["which claude"] },
16
+ { "id": "codex-cli", "name": "Codex CLI", "category": "tooling", "tier": "advanced", "signals": ["which codex"] },
17
+ { "id": "gemini-cli", "name": "Gemini CLI", "category": "tooling", "tier": "intermediate", "signals": ["which gemini"] },
18
+ { "id": "cursor", "name": "Cursor IDE", "category": "tooling", "tier": "intermediate", "signals": ["which cursor"] },
19
+ { "id": "aider", "name": "Aider", "category": "tooling", "tier": "intermediate", "signals": ["which aider"] },
20
+ { "id": "mcp-filesystem", "name": "MCP: Filesystem", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.filesystem"] },
21
+ { "id": "mcp-github", "name": "MCP: GitHub", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.github"] },
22
+ { "id": "mcp-obsidian", "name": "MCP: Obsidian", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.obsidian"] },
23
+ { "id": "mcp-supabase", "name": "MCP: Supabase", "category": "tooling", "tier": "advanced", "signals": ["mcpServers.supabase"] },
24
+ { "id": "mcp-google-drive", "name": "MCP: Google Drive", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.google-drive"] },
25
+ { "id": "mcp-brave-search", "name": "MCP: Brave Search", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.brave-search"] },
26
+ { "id": "mcp-slack", "name": "MCP: Slack", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.slack"] },
27
+ { "id": "mcp-puppeteer", "name": "MCP: Puppeteer", "category": "tooling", "tier": "advanced", "signals": ["mcpServers.puppeteer"] },
28
+ { "id": "mcp-playwright", "name": "MCP: Playwright", "category": "tooling", "tier": "advanced", "signals": ["mcpServers.playwright"] },
29
+ { "id": "mcp-postgres", "name": "MCP: Postgres", "category": "tooling", "tier": "advanced", "signals": ["mcpServers.postgres"] },
30
+ { "id": "mcp-sqlite", "name": "MCP: SQLite", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.sqlite"] },
31
+ { "id": "mcp-sentry", "name": "MCP: Sentry", "category": "tooling", "tier": "advanced", "signals": ["mcpServers.sentry"] },
32
+ { "id": "mcp-notion", "name": "MCP: Notion", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.notion"] },
33
+ { "id": "mcp-linear", "name": "MCP: Linear", "category": "tooling", "tier": "intermediate", "signals": ["mcpServers.linear"] },
34
+ { "id": "mcp-vercel", "name": "MCP: Vercel", "category": "tooling", "tier": "advanced", "signals": ["mcpServers.vercel"] },
35
+
36
+ { "id": "claude-commands", "name": "Claude Code commands", "category": "tooling", "tier": "advanced", "signals": [".claude/commands/"] },
37
+
38
+ { "id": "claude-md", "name": "CLAUDE.md project config", "category": "continuity", "tier": "advanced", "signals": ["CLAUDE.md"] },
39
+ { "id": "claude-memories", "name": "Claude Code memories", "category": "continuity", "tier": "intermediate", "signals": ["~/.claude/memories/"] },
40
+ { "id": "split-rules", "name": "Split rules directory", "category": "continuity", "tier": "advanced", "signals": [".claude/rules/"] },
41
+ { "id": "memory-md", "name": "MEMORY.md persistent context", "category": "continuity", "tier": "advanced", "signals": ["MEMORY.md"] },
42
+ { "id": "daily-logs", "name": "Daily log files", "category": "continuity", "tier": "elite", "signals": ["YYYY-MM-DD.md"] },
43
+ { "id": "cursorrules", "name": ".cursorrules file", "category": "continuity", "tier": "intermediate", "signals": [".cursorrules"] },
44
+ { "id": "windsurfrules", "name": ".windsurfrules file", "category": "continuity", "tier": "intermediate", "signals": [".windsurfrules"] },
45
+ { "id": "copilot-instructions", "name": "Copilot instructions", "category": "continuity", "tier": "intermediate", "signals": [".github/copilot-instructions.md"] },
46
+ { "id": "evolve-md", "name": "EVOLVE.md evolution spec", "category": "continuity", "tier": "elite", "signals": ["EVOLVE.md"] },
47
+ { "id": "agents-md", "name": "AGENTS.md coordination", "category": "continuity", "tier": "elite", "signals": ["AGENTS.md"] },
48
+ { "id": "soul-md", "name": "SOUL.md identity spec", "category": "continuity", "tier": "elite", "signals": ["SOUL.md"] },
49
+
50
+ { "id": "subagents", "name": "Claude Code subagents", "category": "autonomy", "tier": "advanced", "signals": [".claude/agents/"] },
51
+ { "id": "hooks", "name": "Claude Code hooks", "category": "autonomy", "tier": "advanced", "signals": ["settings.hooks"] },
52
+ { "id": "tmux", "name": "tmux terminal multiplexer", "category": "autonomy", "tier": "intermediate", "signals": ["which tmux"] },
53
+ { "id": "git-worktrees", "name": "Git worktrees", "category": "autonomy", "tier": "advanced", "signals": ["git worktree list"] },
54
+ { "id": "orchestrator-gastown", "name": "Gastown orchestrator", "category": "autonomy", "tier": "elite", "signals": ["which gt"] },
55
+ { "id": "orchestrator-claudeflow", "name": "ClaudeFlow orchestrator", "category": "autonomy", "tier": "elite", "signals": ["which claude-flow"] },
56
+ { "id": "orchestrator-openclaw", "name": "OpenClaw orchestrator", "category": "autonomy", "tier": "elite", "signals": ["which openclaw"] },
57
+ { "id": "claude-skills", "name": "Claude Code skills", "category": "autonomy", "tier": "advanced", "signals": [".claude/skills/"] },
58
+ { "id": "orchestrator-devswarm", "name": "DevSwarm orchestrator", "category": "autonomy", "tier": "elite", "signals": ["which devswarm"] },
59
+ { "id": "heartbeat", "name": "HEARTBEAT.md agent liveness", "category": "autonomy", "tier": "elite", "signals": ["HEARTBEAT.md"] },
60
+ { "id": "parallel-scripts", "name": "Parallel execution scripts", "category": "autonomy", "tier": "advanced", "signals": ["crontab", "LaunchAgents"] },
61
+
62
+ { "id": "vercel", "name": "Vercel deployment", "category": "ship", "tier": "intermediate", "signals": ["vercel.json"] },
63
+ { "id": "netlify", "name": "Netlify deployment", "category": "ship", "tier": "intermediate", "signals": ["netlify.toml"] },
64
+ { "id": "fly", "name": "Fly.io deployment", "category": "ship", "tier": "advanced", "signals": ["fly.toml"] },
65
+ { "id": "railway", "name": "Railway deployment", "category": "ship", "tier": "intermediate", "signals": ["railway.json"] },
66
+ { "id": "render", "name": "Render deployment", "category": "ship", "tier": "intermediate", "signals": ["render.yaml"] },
67
+ { "id": "cloudflare-workers", "name": "Cloudflare Workers", "category": "ship", "tier": "advanced", "signals": ["wrangler.toml"] },
68
+ { "id": "docker", "name": "Docker containerization", "category": "ship", "tier": "intermediate", "signals": ["Dockerfile"] },
69
+ { "id": "github-actions", "name": "GitHub Actions CI", "category": "ship", "tier": "advanced", "signals": [".github/workflows/"] },
70
+ { "id": "vitest", "name": "Vitest test framework", "category": "ship", "tier": "intermediate", "signals": ["vitest.config"] },
71
+ { "id": "jest", "name": "Jest test framework", "category": "ship", "tier": "intermediate", "signals": ["jest.config"] },
72
+ { "id": "pytest", "name": "Pytest test framework", "category": "ship", "tier": "intermediate", "signals": ["pytest.ini", "pyproject.toml[pytest]"] },
73
+ { "id": "playwright", "name": "Playwright E2E testing", "category": "ship", "tier": "advanced", "signals": ["playwright.config"] },
74
+ { "id": "cypress", "name": "Cypress E2E testing", "category": "ship", "tier": "intermediate", "signals": ["cypress.config"] },
75
+
76
+ { "id": "gitignore-env", "name": ".gitignore covers .env", "category": "security", "tier": "basic", "signals": [".gitignore"] },
77
+ { "id": "env-vars", "name": "Environment variable secrets", "category": "security", "tier": "intermediate", "signals": ["shell env exports"] },
78
+ { "id": "agent-permissions", "name": "Agent permission scoping", "category": "security", "tier": "advanced", "signals": ["allowedTools", "blockedCommands"] },
79
+ { "id": "file-permissions", "name": "Sensitive file permissions", "category": "security", "tier": "advanced", "signals": ["stat.mode"] },
80
+ { "id": "canary-tokens", "name": "Canary tokens", "category": "security", "tier": "elite", "signals": ["canary", "honeypot"] },
81
+ { "id": "prompt-injection-defense", "name": "Prompt injection defense", "category": "security", "tier": "elite", "signals": ["injection", "defense", "safety"] },
82
+
83
+ { "id": "eslint", "name": "ESLint configuration", "category": "ops", "tier": "basic", "signals": ["eslint.config", ".eslintrc"] },
84
+ { "id": "prettier", "name": "Prettier configuration", "category": "ops", "tier": "basic", "signals": ["prettier.config", ".prettierrc"] },
85
+ { "id": "biome", "name": "Biome configuration", "category": "ops", "tier": "intermediate", "signals": ["biome.json"] },
86
+ { "id": "typescript-strict", "name": "TypeScript strict mode", "category": "ops", "tier": "intermediate", "signals": ["tsconfig.json strict:true"] },
87
+ { "id": "npm-scripts", "name": "Build/dev/lint scripts", "category": "ops", "tier": "basic", "signals": ["package.json scripts"] },
88
+ { "id": "task-tracking", "name": "Task tracking", "category": "ops", "tier": "intermediate", "signals": ["TODO", "TASKS"] },
89
+ { "id": "documentation", "name": "Project documentation", "category": "ops", "tier": "basic", "signals": ["README.md"] },
90
+ { "id": "kanban-integration", "name": "Kanban/project board integration", "category": "ops", "tier": "advanced", "signals": ["linear", "jira", "notion tasks"] },
91
+ { "id": "automated-docs", "name": "Automated documentation", "category": "ops", "tier": "advanced", "signals": ["typedoc", "jsdoc", "storybook"] },
92
+ { "id": "maintenance-scripts", "name": "Maintenance scripts", "category": "ops", "tier": "intermediate", "signals": ["scripts/", "Makefile"] },
93
+ { "id": "monitoring-config", "name": "Monitoring configuration", "category": "ops", "tier": "intermediate", "signals": ["sentry.config", "datadog"] },
94
+ { "id": "turbo", "name": "Turborepo", "category": "ops", "tier": "intermediate", "signals": ["turbo.json"] },
95
+ { "id": "nx", "name": "Nx monorepo", "category": "ops", "tier": "intermediate", "signals": ["nx.json"] },
96
+ { "id": "pnpm-workspace", "name": "pnpm workspace", "category": "ops", "tier": "basic", "signals": ["pnpm-workspace.yaml"] },
97
+ { "id": "lerna", "name": "Lerna monorepo", "category": "ops", "tier": "basic", "signals": ["lerna.json"] },
98
+
99
+ { "id": "github-repos", "name": "Public GitHub repositories", "category": "social", "tier": "intermediate", "signals": ["git remote"] },
100
+ { "id": "npm-public", "name": "Published npm packages", "category": "social", "tier": "advanced", "signals": ["package.json private:false"] },
101
+ { "id": "slack-webhook", "name": "Slack webhook integration", "category": "social", "tier": "intermediate", "signals": ["SLACK_WEBHOOK"] },
102
+ { "id": "discord-bot", "name": "Discord bot integration", "category": "social", "tier": "intermediate", "signals": ["DISCORD_WEBHOOK", "DISCORD_BOT_TOKEN"] },
103
+
104
+ { "id": "ufs:claude-md:deep", "name": "CLAUDE.md deep config", "category": "tooling", "tier": "advanced", "signals": ["CLAUDE.md >100 lines + keywords"] },
105
+ { "id": "ufs:claude-md:deep:continuity", "name": "CLAUDE.md deep continuity", "category": "continuity", "tier": "advanced", "signals": ["CLAUDE.md >100 lines continuity"] },
106
+ { "id": "ufs:claude-md:deep:autonomy", "name": "CLAUDE.md autonomy guidance", "category": "autonomy", "tier": "basic", "signals": ["CLAUDE.md autonomy"] },
107
+ { "id": "ufs:claude-md:rich", "name": "CLAUDE.md rich config", "category": "tooling", "tier": "intermediate", "signals": ["CLAUDE.md >50 lines"] },
108
+ { "id": "ufs:claude-md:rich:continuity", "name": "CLAUDE.md continuity context", "category": "continuity", "tier": "basic", "signals": ["CLAUDE.md >50 lines continuity"] },
109
+ { "id": "ufs:claude-md:exists", "name": "CLAUDE.md exists", "category": "tooling", "tier": "basic", "signals": ["CLAUDE.md"] },
110
+
111
+ { "id": "ufs:claude-dir:advanced", "name": ".claude/ advanced config", "category": "tooling", "tier": "advanced", "signals": [".claude/ agents/skills/rules/hooks"] },
112
+ { "id": "ufs:claude-dir:advanced:autonomy", "name": ".claude/ autonomy features", "category": "autonomy", "tier": "basic", "signals": [".claude/ autonomy"] },
113
+ { "id": "ufs:claude-settings:custom", "name": ".claude/settings.json custom", "category": "tooling", "tier": "basic", "signals": [".claude/settings.json non-default"] },
114
+ { "id": "ufs:claude-dir:exists", "name": ".claude/ directory", "category": "tooling", "tier": "basic", "signals": [".claude/"] },
115
+
116
+ { "id": "ufs:cursorrules:rich", "name": ".cursorrules rich config", "category": "tooling", "tier": "intermediate", "signals": [".cursorrules >30 lines"] },
117
+ { "id": "ufs:cursorrules:rich:continuity", "name": ".cursorrules continuity", "category": "continuity", "tier": "basic", "signals": [".cursorrules continuity"] },
118
+ { "id": "ufs:cursorrules:exists", "name": ".cursorrules exists", "category": "tooling", "tier": "basic", "signals": [".cursorrules"] },
119
+ { "id": "ufs:cursor-dir:rules", "name": ".cursor/ rules", "category": "tooling", "tier": "intermediate", "signals": [".cursor/rules"] },
120
+
121
+ { "id": "ufs:copilot-instructions:rich", "name": "Copilot instructions rich", "category": "tooling", "tier": "intermediate", "signals": ["copilot-instructions.md >20 lines"] },
122
+ { "id": "ufs:copilot-instructions:exists", "name": "Copilot instructions", "category": "tooling", "tier": "basic", "signals": ["copilot-instructions.md"] },
123
+
124
+ { "id": "ufs:agents-md:deep", "name": "AGENTS.md deep coordination", "category": "continuity", "tier": "advanced", "signals": ["AGENTS.md >50 lines + behavioral"] },
125
+ { "id": "ufs:agents-md:deep:autonomy", "name": "AGENTS.md autonomy", "category": "autonomy", "tier": "intermediate", "signals": ["AGENTS.md autonomy coordination"] },
126
+ { "id": "ufs:agents-md:exists", "name": "AGENTS.md exists", "category": "tooling", "tier": "basic", "signals": ["AGENTS.md"] },
127
+
128
+ { "id": "ufs:soul-md:rich", "name": "SOUL.md rich spec", "category": "continuity", "tier": "intermediate", "signals": ["SOUL.md >20 lines"] },
129
+ { "id": "ufs:soul-md:rich:intelligence", "name": "SOUL.md intelligence", "category": "intelligence", "tier": "basic", "signals": ["SOUL.md intelligence spec"] },
130
+ { "id": "ufs:soul-md:exists", "name": "SOUL.md identity spec", "category": "continuity", "tier": "basic", "signals": ["SOUL.md"] },
131
+
132
+ { "id": "ufs:user-md:exists", "name": "USER.md", "category": "continuity", "tier": "basic", "signals": ["USER.md"] },
133
+
134
+ { "id": "ufs:mcp-json:many", "name": ".mcp.json many servers", "category": "tooling", "tier": "advanced", "signals": [".mcp.json >6 servers"] },
135
+ { "id": "ufs:mcp-json:several", "name": ".mcp.json several servers", "category": "tooling", "tier": "intermediate", "signals": [".mcp.json >3 servers"] },
136
+ { "id": "ufs:mcp-json:exists", "name": ".mcp.json exists", "category": "tooling", "tier": "basic", "signals": [".mcp.json"] },
137
+ { "id": "ufs:mcp-sdk:pioneer", "name": "MCP SDK (Pioneer)", "category": "tooling", "tier": "elite", "signals": ["@modelcontextprotocol/sdk"] },
138
+
139
+ { "id": "ufs:memory-dir:heartbeat", "name": "Memory heartbeat state", "category": "autonomy", "tier": "basic", "signals": ["memory/heartbeat-state.json"] },
140
+ { "id": "ufs:memory-dir:active", "name": "Memory active work", "category": "continuity", "tier": "basic", "signals": ["memory/active-work.md"] },
141
+ { "id": "ufs:memory-dir:rich", "name": "Memory rich history", "category": "continuity", "tier": "intermediate", "signals": ["memory/ >5 files"] },
142
+ { "id": "ufs:memory-dir:exists", "name": "Memory directory", "category": "continuity", "tier": "basic", "signals": ["memory/"] },
143
+
144
+ { "id": "ufs:memory-md:rich", "name": "MEMORY.md rich", "category": "continuity", "tier": "intermediate", "signals": ["MEMORY.md >50 lines"] },
145
+ { "id": "ufs:memory-md:exists", "name": "MEMORY.md exists", "category": "continuity", "tier": "basic", "signals": ["MEMORY.md"] },
146
+
147
+ { "id": "ufs:heartbeat-md:exists", "name": "HEARTBEAT.md", "category": "autonomy", "tier": "basic", "signals": ["HEARTBEAT.md"] },
148
+ { "id": "ufs:evolve-md:exists", "name": "EVOLVE.md", "category": "continuity", "tier": "basic", "signals": ["EVOLVE.md"] },
149
+ { "id": "ufs:handoff:exists", "name": "Handoff/session files", "category": "continuity", "tier": "basic", "signals": ["handoff*", "handover*", "session-state*"] },
150
+
151
+ { "id": "ufs:specs-dir:exists", "name": "Specs directory", "category": "ops", "tier": "intermediate", "signals": ["specs/"] },
152
+ { "id": "ufs:prd:exists", "name": "PRD document", "category": "ops", "tier": "intermediate", "signals": ["docs/PRD*.md"] },
153
+
154
+ { "id": "ufs:test-ratio:high", "name": "High test ratio", "category": "ship", "tier": "advanced", "signals": ["test ratio >0.3"] },
155
+ { "id": "ufs:test-ratio:medium", "name": "Medium test ratio", "category": "ship", "tier": "intermediate", "signals": ["test ratio >0.1"] },
156
+ { "id": "ufs:test-ratio:zero", "name": "No tests (penalty)", "category": "ship", "tier": "basic", "signals": ["test ratio = 0"] },
157
+
158
+ { "id": "ufs:env-example:exists", "name": ".env.example", "category": "social", "tier": "basic", "signals": [".env.example"] },
159
+
160
+ { "id": "ufs:readme:badges", "name": "README badges", "category": "ops", "tier": "basic", "signals": ["README.md badges"] },
161
+ { "id": "ufs:readme:rich", "name": "README.md rich", "category": "ops", "tier": "intermediate", "signals": ["README.md >100 lines"] },
162
+ { "id": "ufs:readme:exists", "name": "README.md exists", "category": "ops", "tier": "basic", "signals": ["README.md"] },
163
+
164
+ { "id": "ufs:ci:complex", "name": "Multiple CI workflows", "category": "ship", "tier": "intermediate", "signals": [".github/workflows/ 2+"] },
165
+ { "id": "ufs:ci:exists", "name": "CI workflow", "category": "ship", "tier": "basic", "signals": [".github/workflows/"] },
166
+
167
+ { "id": "ufs:docker:exists", "name": "Dockerfile", "category": "ship", "tier": "basic", "signals": ["Dockerfile"] },
168
+ { "id": "ufs:docker-compose:exists", "name": "Docker Compose", "category": "ship", "tier": "basic", "signals": ["docker-compose.yml"] },
169
+
170
+ { "id": "ufs:turbo:exists", "name": "Turborepo", "category": "ops", "tier": "basic", "signals": ["turbo.json"] },
171
+ { "id": "ufs:nx:exists", "name": "Nx", "category": "ops", "tier": "basic", "signals": ["nx.json"] },
172
+
173
+ { "id": "ufs:codeowners:exists", "name": "CODEOWNERS", "category": "social", "tier": "basic", "signals": [".github/CODEOWNERS"] },
174
+ { "id": "ufs:pr-template:exists", "name": "PR template", "category": "social", "tier": "basic", "signals": [".github/PULL_REQUEST_TEMPLATE.md"] },
175
+ { "id": "ufs:changelog:exists", "name": "CHANGELOG", "category": "ops", "tier": "basic", "signals": ["CHANGELOG.md"] },
176
+ { "id": "ufs:husky:exists", "name": "Husky git hooks", "category": "ops", "tier": "basic", "signals": [".husky/"] },
177
+ { "id": "ufs:license:exists", "name": "LICENSE", "category": "social", "tier": "basic", "signals": ["LICENSE"] },
178
+
179
+ { "id": "ufs:security:canary", "name": "Canary in config", "category": "security", "tier": "basic", "signals": ["canary keyword"] },
180
+ { "id": "ufs:security:injection", "name": "Injection defense", "category": "security", "tier": "basic", "signals": ["injection defense keyword"] },
181
+ { "id": "ufs:security:confirm", "name": "Confirmation requirement", "category": "security", "tier": "basic", "signals": ["require confirmation"] },
182
+ { "id": "ufs:security:gitignore", "name": ".gitignore secrets", "category": "security", "tier": "basic", "signals": [".gitignore secret patterns"] },
183
+
184
+ { "id": "ufs:cron:ai", "name": "AI crontab entries", "category": "autonomy", "tier": "basic", "signals": ["crontab AI"] },
185
+ { "id": "ufs:launchd:ai", "name": "AI launchd services", "category": "autonomy", "tier": "basic", "signals": ["launchctl AI"] },
186
+
187
+ { "id": "ufs:monorepo:large", "name": "Large monorepo", "category": "ops", "tier": "basic", "signals": [">5 workspaces"] },
188
+ { "id": "ufs:monorepo:ai-consistent", "name": "Consistent AI config", "category": "tooling", "tier": "basic", "signals": ["CLAUDE.md across workspaces"] }
189
+ ]