@praneeth_54/agentdoctor 1.1.0 → 2.0.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 (170) hide show
  1. package/CHANGELOG.md +119 -5
  2. package/README.md +165 -332
  3. package/dist/agents/aider/adapter.d.ts +1 -0
  4. package/dist/agents/aider/adapter.js +1 -0
  5. package/dist/agents/aider/detector.d.ts +14 -0
  6. package/dist/agents/aider/detector.js +120 -0
  7. package/dist/agents/copilot/adapter.d.ts +1 -0
  8. package/dist/agents/copilot/adapter.js +1 -0
  9. package/dist/agents/copilot/detector.d.ts +13 -0
  10. package/dist/agents/copilot/detector.js +113 -0
  11. package/dist/agents/gemini/adapter.d.ts +1 -0
  12. package/dist/agents/gemini/adapter.js +1 -0
  13. package/dist/agents/gemini/detector.d.ts +13 -0
  14. package/dist/agents/gemini/detector.js +151 -0
  15. package/dist/agents/registry.js +13 -1
  16. package/dist/agents/types.d.ts +1 -1
  17. package/dist/agents/windsurf/adapter.d.ts +1 -0
  18. package/dist/agents/windsurf/adapter.js +1 -0
  19. package/dist/agents/windsurf/detector.d.ts +14 -0
  20. package/dist/agents/windsurf/detector.js +119 -0
  21. package/dist/architecture/c4.d.ts +22 -0
  22. package/dist/architecture/c4.js +62 -0
  23. package/dist/cli/commands/brain.d.ts +12 -0
  24. package/dist/cli/commands/brain.js +162 -0
  25. package/dist/cli/commands/complete.d.ts +23 -0
  26. package/dist/cli/commands/complete.js +232 -0
  27. package/dist/cli/commands/explain.js +1 -1
  28. package/dist/cli/commands/fix.js +22 -2
  29. package/dist/cli/commands/mcp.d.ts +8 -0
  30. package/dist/cli/commands/mcp.js +14 -0
  31. package/dist/cli/commands/platform.d.ts +15 -0
  32. package/dist/cli/commands/platform.js +191 -0
  33. package/dist/cli/commands/v2.d.ts +55 -0
  34. package/dist/cli/commands/v2.js +278 -0
  35. package/dist/cli/program.js +809 -2
  36. package/dist/constants.d.ts +3 -2
  37. package/dist/constants.js +5 -1
  38. package/dist/contracts/adapters.d.ts +7 -0
  39. package/dist/contracts/adapters.js +60 -0
  40. package/dist/contracts/index.d.ts +162 -0
  41. package/dist/contracts/index.js +18 -0
  42. package/dist/core/baseline/store.d.ts +48 -0
  43. package/dist/core/baseline/store.js +163 -0
  44. package/dist/core/brain-cli/service.d.ts +26 -0
  45. package/dist/core/brain-cli/service.js +175 -0
  46. package/dist/core/brain-product/init.d.ts +45 -0
  47. package/dist/core/brain-product/init.js +232 -0
  48. package/dist/core/changes/analyze.d.ts +41 -0
  49. package/dist/core/changes/analyze.js +223 -0
  50. package/dist/core/context-health/analyze.d.ts +15 -0
  51. package/dist/core/context-health/analyze.js +234 -0
  52. package/dist/core/fix/apply.d.ts +21 -4
  53. package/dist/core/fix/apply.js +118 -18
  54. package/dist/core/fix/backup.d.ts +30 -0
  55. package/dist/core/fix/backup.js +193 -0
  56. package/dist/core/fix/plan.d.ts +6 -3
  57. package/dist/core/fix/plan.js +113 -9
  58. package/dist/core/fix/render.d.ts +2 -0
  59. package/dist/core/fix/render.js +36 -21
  60. package/dist/core/fix/run.js +5 -1
  61. package/dist/core/fix/safe-target.d.ts +14 -0
  62. package/dist/core/fix/safe-target.js +81 -0
  63. package/dist/core/fix/types.d.ts +12 -1
  64. package/dist/core/fix/types.js +2 -0
  65. package/dist/core/fix/writers/claude-settings.js +3 -1
  66. package/dist/core/fix/writers/codex-config.d.ts +3 -0
  67. package/dist/core/fix/writers/codex-config.js +24 -3
  68. package/dist/core/fix/writers/cursorignore.js +3 -1
  69. package/dist/core/fix/writers/simple-ignore.d.ts +16 -0
  70. package/dist/core/fix/writers/simple-ignore.js +68 -0
  71. package/dist/core/monorepo/detect.d.ts +13 -0
  72. package/dist/core/monorepo/detect.js +121 -0
  73. package/dist/core/rules/build-context.js +22 -3
  74. package/dist/core/rules/context/generated-directory.js +11 -1
  75. package/dist/core/rules/context/large-instruction-file.js +6 -0
  76. package/dist/core/rules/context/large-log-file.js +16 -1
  77. package/dist/core/rules/ignore.d.ts +11 -1
  78. package/dist/core/rules/ignore.js +22 -1
  79. package/dist/core/rules/instructions/empty-instructions.js +7 -0
  80. package/dist/core/rules/security/env-file-exposure.js +23 -2
  81. package/dist/core/rules/security/private-key-file.js +1 -1
  82. package/dist/core/scanner/scan.js +1 -1
  83. package/dist/core/schemas/validate.d.ts +6 -0
  84. package/dist/core/schemas/validate.js +62 -0
  85. package/dist/core/scoring/compute-scores.d.ts +1 -1
  86. package/dist/core/scoring/compute-scores.js +5 -1
  87. package/dist/core/scoring/placeholder.d.ts +1 -1
  88. package/dist/core/scoring/placeholder.js +5 -1
  89. package/dist/core/secrets/scan.d.ts +23 -0
  90. package/dist/core/secrets/scan.js +172 -0
  91. package/dist/dashboard/server.d.ts +24 -0
  92. package/dist/dashboard/server.js +386 -0
  93. package/dist/enforcement/runner.d.ts +23 -0
  94. package/dist/enforcement/runner.js +56 -0
  95. package/dist/index.d.ts +13 -0
  96. package/dist/index.js +12 -0
  97. package/dist/integrations/github/pr-analyze.d.ts +28 -0
  98. package/dist/integrations/github/pr-analyze.js +98 -0
  99. package/dist/integrations/local-ai/provider.d.ts +45 -0
  100. package/dist/integrations/local-ai/provider.js +104 -0
  101. package/dist/intelligence/git/analyze.d.ts +34 -0
  102. package/dist/intelligence/git/analyze.js +136 -0
  103. package/dist/intelligence/graph/build.d.ts +13 -0
  104. package/dist/intelligence/graph/build.js +215 -0
  105. package/dist/knowledge/store.d.ts +25 -0
  106. package/dist/knowledge/store.js +91 -0
  107. package/dist/mcp/agentdoctor/server.d.ts +16 -0
  108. package/dist/mcp/agentdoctor/server.js +67 -0
  109. package/dist/mcp/brain/session.js +7 -7
  110. package/dist/mcp/intelligence/handlers.d.ts +11 -0
  111. package/dist/mcp/intelligence/handlers.js +175 -0
  112. package/dist/mcp/intelligence/path-safety.d.ts +11 -0
  113. package/dist/mcp/intelligence/path-safety.js +82 -0
  114. package/dist/mcp/intelligence/registry.d.ts +8 -0
  115. package/dist/mcp/intelligence/registry.js +160 -0
  116. package/dist/ops/health.d.ts +18 -0
  117. package/dist/ops/health.js +51 -0
  118. package/dist/platform/ai-quality/analyze.d.ts +9 -0
  119. package/dist/platform/ai-quality/analyze.js +65 -0
  120. package/dist/platform/architecture/drift.d.ts +17 -0
  121. package/dist/platform/architecture/drift.js +74 -0
  122. package/dist/platform/auth/local.d.ts +15 -0
  123. package/dist/platform/auth/local.js +58 -0
  124. package/dist/platform/context-security/analyze.d.ts +6 -0
  125. package/dist/platform/context-security/analyze.js +97 -0
  126. package/dist/platform/firewall/evaluate.d.ts +54 -0
  127. package/dist/platform/firewall/evaluate.js +308 -0
  128. package/dist/platform/graph/build.d.ts +6 -0
  129. package/dist/platform/graph/build.js +193 -0
  130. package/dist/platform/health/analyze.d.ts +7 -0
  131. package/dist/platform/health/analyze.js +186 -0
  132. package/dist/platform/index.d.ts +27 -0
  133. package/dist/platform/index.js +87 -0
  134. package/dist/platform/knowledge/analyze.d.ts +20 -0
  135. package/dist/platform/knowledge/analyze.js +96 -0
  136. package/dist/platform/provenance/build.d.ts +44 -0
  137. package/dist/platform/provenance/build.js +65 -0
  138. package/dist/platform/readiness/scorecard.d.ts +5 -0
  139. package/dist/platform/readiness/scorecard.js +98 -0
  140. package/dist/platform/refactor/impact.d.ts +20 -0
  141. package/dist/platform/refactor/impact.js +60 -0
  142. package/dist/platform/reports/export.d.ts +12 -0
  143. package/dist/platform/reports/export.js +92 -0
  144. package/dist/platform/security/redact.d.ts +15 -0
  145. package/dist/platform/security/redact.js +87 -0
  146. package/dist/platform/sessions/store.d.ts +32 -0
  147. package/dist/platform/sessions/store.js +97 -0
  148. package/dist/platform/store.d.ts +6 -0
  149. package/dist/platform/store.js +57 -0
  150. package/dist/platform/test-impact/analyze.d.ts +32 -0
  151. package/dist/platform/test-impact/analyze.js +164 -0
  152. package/dist/platform/time-machine/compare.d.ts +17 -0
  153. package/dist/platform/time-machine/compare.js +62 -0
  154. package/dist/platform/tokens/plan.d.ts +28 -0
  155. package/dist/platform/tokens/plan.js +89 -0
  156. package/dist/platform/types.d.ts +111 -0
  157. package/dist/platform/types.js +5 -0
  158. package/dist/plugins/runtime.d.ts +36 -0
  159. package/dist/plugins/runtime.js +101 -0
  160. package/dist/plugins/sdk.d.ts +29 -0
  161. package/dist/plugins/sdk.js +114 -0
  162. package/dist/policy/packs.d.ts +9 -0
  163. package/dist/policy/packs.js +59 -0
  164. package/dist/reporters/terminal/report.js +38 -5
  165. package/dist/storage/provider.d.ts +35 -0
  166. package/dist/storage/provider.js +103 -0
  167. package/dist/team/auth.d.ts +35 -0
  168. package/dist/team/auth.js +70 -0
  169. package/dist/types/index.d.ts +5 -1
  170. package/package.json +14 -7
@@ -7,7 +7,39 @@ import { formatPackageManager, formatPackageManagers } from "../../detectors/pac
7
7
  import { colors, symbolFail, symbolInfo, symbolOk, symbolWarn } from "../../utils/colors.js";
8
8
  import { sanitizeTerminalText } from "../../security/redaction.js";
9
9
  const DEFAULT_FINDING_LIMIT = 12;
10
- const LIMITED_ANALYSIS_NOTE = "No supported coding-agent configuration detected; agent-specific security exposure checks are limited.";
10
+ const LIMITED_ANALYSIS_NOTE = "Agent-specific exposure checks are limited (no supported agent config); repository hygiene still applied.";
11
+ /** Agents with an implemented Safe Fix writer (detect-only agents are excluded). */
12
+ const SAFE_FIX_AGENT_IDS = new Set([
13
+ "cursor",
14
+ "claude-code",
15
+ "codex",
16
+ "gemini-cli",
17
+ "aider",
18
+ ]);
19
+ function renderAgentCoverageSummary(result) {
20
+ const configured = result.agents.filter((a) => a.configured);
21
+ const detectedOnly = result.agents.filter((a) => a.detected && !a.configured);
22
+ const withFix = configured.filter((a) => SAFE_FIX_AGENT_IDS.has(a.id));
23
+ const detectOnlyConfigured = configured.filter((a) => !SAFE_FIX_AGENT_IDS.has(a.id));
24
+ const lines = [];
25
+ lines.push("");
26
+ if (result.agentSecurityAnalysis === "limited") {
27
+ lines.push(colors.dim(" Coverage: 0 configured · universal hygiene still runs (limited agent analysis)"));
28
+ return lines;
29
+ }
30
+ const parts = [`${configured.length} configured`];
31
+ if (detectedOnly.length > 0) {
32
+ parts.push(`${detectedOnly.length} detected-only`);
33
+ }
34
+ if (withFix.length > 0) {
35
+ parts.push(`Safe Fix: ${withFix.map((a) => a.displayName).join(", ")}`);
36
+ }
37
+ if (detectOnlyConfigured.length > 0) {
38
+ parts.push(`detect-only (no Safe Fix writer): ${detectOnlyConfigured.map((a) => a.displayName).join(", ")}`);
39
+ }
40
+ lines.push(colors.dim(` Coverage: ${parts.join(" · ")}`));
41
+ return lines;
42
+ }
11
43
  function groupFindings(findings) {
12
44
  return {
13
45
  critical: findings.filter((f) => f.severity === "critical"),
@@ -152,6 +184,7 @@ export function renderTerminalReport(result, options = {}) {
152
184
  }
153
185
  }
154
186
  }
187
+ lines.push(...renderAgentCoverageSummary(result));
155
188
  lines.push("");
156
189
  const grouped = groupFindings(result.findings);
157
190
  const total = result.summary.total;
@@ -164,10 +197,10 @@ export function renderTerminalReport(result, options = {}) {
164
197
  }
165
198
  if (total === 0) {
166
199
  if (limited) {
167
- lines.push(` ${symbolWarn()} Nothing to audit yet — no Cursor, Claude Code, or Codex config found`);
200
+ lines.push(` ${symbolOk()} No repository-hygiene findings — agent readiness not scored (no supported agent config)`);
168
201
  lines.push("");
169
- lines.push(colors.dim(" Next: add project agent config (for example `.cursor/`, `CLAUDE.md` / `.claude/`, or `AGENTS.md`),"));
170
- lines.push(colors.dim(" then re-run `agentdoctor` in this repository."));
202
+ lines.push(colors.dim(" Optional next: add project agent config (`.cursor/`, `CLAUDE.md`, `AGENTS.md`, `.github/copilot-instructions.md`, `.windsurf/rules/`, `GEMINI.md`, or `.aider.conf.yml`)"));
203
+ lines.push(colors.dim(" so agent exposure checks run fully. CLI, Action, and Project Brain MCP still work without an agent."));
171
204
  }
172
205
  else {
173
206
  lines.push(` ${symbolOk()} No findings`);
@@ -217,7 +250,7 @@ export function renderTerminalReport(result, options = {}) {
217
250
  lines.push("");
218
251
  if (result.scoringAvailable && result.scores) {
219
252
  if (limited) {
220
- lines.push(` Readiness: n/a — configure Cursor, Claude Code, or Codex before treating scores as agent readiness`);
253
+ lines.push(` Readiness: n/a — configure a supported agent (Cursor, Claude Code, Codex, Copilot, Windsurf, Gemini CLI, or Aider) before treating scores as agent readiness`);
221
254
  lines.push(colors.dim(` Numeric scores remain in JSON (overall ${result.scores.overall}/100) for repository-risk findings only`));
222
255
  }
223
256
  else {
@@ -0,0 +1,35 @@
1
+ import type { StorageProvider } from "../contracts/index.js";
2
+ export declare class FilesystemStorageProvider implements StorageProvider {
3
+ readonly kind: "filesystem";
4
+ private readonly root;
5
+ constructor(rootInput: string, subdir?: string);
6
+ private resolveKey;
7
+ get(key: string): Promise<string | null>;
8
+ set(key: string, value: string): Promise<void>;
9
+ delete(key: string): Promise<void>;
10
+ list(prefix: string): Promise<string[]>;
11
+ }
12
+ /** In-memory provider for tests and optional ephemeral mode. */
13
+ export declare class MemoryStorageProvider implements StorageProvider {
14
+ readonly kind: "memory";
15
+ private readonly map;
16
+ get(key: string): Promise<string | null>;
17
+ set(key: string, value: string): Promise<void>;
18
+ delete(key: string): Promise<void>;
19
+ list(prefix: string): Promise<string[]>;
20
+ }
21
+ /**
22
+ * SQLite provider — optional. Requires better-sqlite3 when enabled.
23
+ * Without the dependency, construction throws a documented error (no fake DB).
24
+ */
25
+ export declare function tryCreateSqliteStorage(_root: string): Promise<StorageProvider | {
26
+ error: string;
27
+ }>;
28
+ export interface WorkspaceRecord {
29
+ id: string;
30
+ name: string;
31
+ repositoryRoots: string[];
32
+ createdAt: string;
33
+ }
34
+ export declare function saveWorkspace(storage: StorageProvider, workspace: WorkspaceRecord): Promise<void>;
35
+ export declare function loadWorkspace(storage: StorageProvider, id: string): Promise<WorkspaceRecord | null>;
@@ -0,0 +1,103 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { resolveRepoRoot, isPathInsideRoot } from "../utils/path.js";
4
+ import { atomicWriteTextFile } from "../utils/fs.js";
5
+ export class FilesystemStorageProvider {
6
+ kind = "filesystem";
7
+ root;
8
+ constructor(rootInput, subdir = ".agentdoctor/storage") {
9
+ this.root = path.join(resolveRepoRoot(rootInput), subdir);
10
+ }
11
+ resolveKey(key) {
12
+ if (key.includes("\0") || key.split(/[/\\]/).includes("..") || path.isAbsolute(key)) {
13
+ throw new Error(`unsafe storage key: ${key}`);
14
+ }
15
+ const target = path.resolve(this.root, key);
16
+ if (!isPathInsideRoot(this.root, target))
17
+ throw new Error("storage path escape");
18
+ return target;
19
+ }
20
+ async get(key) {
21
+ try {
22
+ return await fs.readFile(this.resolveKey(key), "utf8");
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ async set(key, value) {
29
+ const target = this.resolveKey(key);
30
+ await fs.mkdir(path.dirname(target), { recursive: true });
31
+ await atomicWriteTextFile(target, value);
32
+ }
33
+ async delete(key) {
34
+ try {
35
+ await fs.unlink(this.resolveKey(key));
36
+ }
37
+ catch {
38
+ // ignore
39
+ }
40
+ }
41
+ async list(prefix) {
42
+ const base = this.resolveKey(prefix || ".");
43
+ const out = [];
44
+ async function walk(dir, rel) {
45
+ let entries;
46
+ try {
47
+ entries = await fs.readdir(dir, { withFileTypes: true });
48
+ }
49
+ catch {
50
+ return;
51
+ }
52
+ for (const e of entries) {
53
+ const nextRel = rel ? `${rel}/${e.name}` : e.name;
54
+ if (e.isDirectory())
55
+ await walk(path.join(dir, e.name), nextRel);
56
+ else
57
+ out.push(nextRel);
58
+ }
59
+ }
60
+ const st = await fs.stat(base).catch(() => null);
61
+ if (!st)
62
+ return [];
63
+ if (st.isFile())
64
+ return [prefix];
65
+ await walk(base, prefix === "." ? "" : prefix);
66
+ return out.sort();
67
+ }
68
+ }
69
+ /** In-memory provider for tests and optional ephemeral mode. */
70
+ export class MemoryStorageProvider {
71
+ kind = "memory";
72
+ map = new Map();
73
+ async get(key) {
74
+ return this.map.get(key) ?? null;
75
+ }
76
+ async set(key, value) {
77
+ this.map.set(key, value);
78
+ }
79
+ async delete(key) {
80
+ this.map.delete(key);
81
+ }
82
+ async list(prefix) {
83
+ return [...this.map.keys()].filter((k) => k.startsWith(prefix)).sort();
84
+ }
85
+ }
86
+ /**
87
+ * SQLite provider — optional. Requires better-sqlite3 when enabled.
88
+ * Without the dependency, construction throws a documented error (no fake DB).
89
+ */
90
+ export async function tryCreateSqliteStorage(_root) {
91
+ return {
92
+ error: "SQLite storage is feature-flagged and requires optional dependency better-sqlite3 (not bundled). Use filesystem provider for local-first default.",
93
+ };
94
+ }
95
+ export async function saveWorkspace(storage, workspace) {
96
+ await storage.set(`workspaces/${workspace.id}.json`, `${JSON.stringify(workspace, null, 2)}\n`);
97
+ }
98
+ export async function loadWorkspace(storage, id) {
99
+ const raw = await storage.get(`workspaces/${id}.json`);
100
+ if (!raw)
101
+ return null;
102
+ return JSON.parse(raw);
103
+ }
@@ -0,0 +1,35 @@
1
+ import type { StorageProvider } from "../contracts/index.js";
2
+ export type TeamRole = "owner" | "admin" | "member" | "viewer";
3
+ export interface TeamUser {
4
+ id: string;
5
+ username: string;
6
+ passwordHash: string;
7
+ salt: string;
8
+ role: TeamRole;
9
+ createdAt: string;
10
+ /** Development-only local auth — not enterprise SSO. */
11
+ authMode: "local-dev";
12
+ }
13
+ export interface SessionToken {
14
+ token: string;
15
+ userId: string;
16
+ expiresAt: string;
17
+ }
18
+ export declare function registerLocalDevUser(options: {
19
+ root: string;
20
+ username: string;
21
+ password: string;
22
+ role?: TeamRole;
23
+ storage?: StorageProvider;
24
+ }): Promise<TeamUser>;
25
+ export declare function authenticateLocalDev(options: {
26
+ root: string;
27
+ username: string;
28
+ password: string;
29
+ storage?: StorageProvider;
30
+ }): Promise<SessionToken>;
31
+ export declare function authorize(root: string, token: string, minRole: TeamRole, storage?: StorageProvider): Promise<{
32
+ ok: boolean;
33
+ user?: TeamUser;
34
+ reason: string;
35
+ }>;
@@ -0,0 +1,70 @@
1
+ import { createHash, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
2
+ import { FilesystemStorageProvider } from "../storage/provider.js";
3
+ function hashPassword(password, salt) {
4
+ return scryptSync(password, salt, 32).toString("hex");
5
+ }
6
+ export async function registerLocalDevUser(options) {
7
+ if (options.password.length < 8)
8
+ throw new Error("password must be at least 8 characters");
9
+ const storage = options.storage ?? new FilesystemStorageProvider(options.root, ".agentdoctor/team");
10
+ const salt = randomBytes(16).toString("hex");
11
+ const user = {
12
+ id: `user_${createHash("sha1").update(options.username).digest("hex").slice(0, 10)}`,
13
+ username: options.username,
14
+ passwordHash: hashPassword(options.password, salt),
15
+ salt,
16
+ role: options.role ?? "member",
17
+ createdAt: new Date().toISOString(),
18
+ authMode: "local-dev",
19
+ };
20
+ await storage.set(`users/${user.id}.json`, `${JSON.stringify(user, null, 2)}\n`);
21
+ return {
22
+ ...user,
23
+ passwordHash: "[REDACTED]",
24
+ salt: "[REDACTED]",
25
+ };
26
+ }
27
+ export async function authenticateLocalDev(options) {
28
+ const storage = options.storage ?? new FilesystemStorageProvider(options.root, ".agentdoctor/team");
29
+ const keys = await storage.list("users");
30
+ for (const key of keys) {
31
+ const raw = await storage.get(key.startsWith("users/") ? key : `users/${key}`);
32
+ if (!raw)
33
+ continue;
34
+ const user = JSON.parse(raw);
35
+ if (user.username !== options.username)
36
+ continue;
37
+ const next = hashPassword(options.password, user.salt);
38
+ const a = Buffer.from(next, "hex");
39
+ const b = Buffer.from(user.passwordHash, "hex");
40
+ if (a.length !== b.length || !timingSafeEqual(a, b))
41
+ break;
42
+ const token = randomBytes(24).toString("hex");
43
+ const session = {
44
+ token,
45
+ userId: user.id,
46
+ expiresAt: new Date(Date.now() + 8 * 3600_000).toISOString(),
47
+ };
48
+ await storage.set(`sessions/${token}.json`, `${JSON.stringify(session, null, 2)}\n`);
49
+ return session;
50
+ }
51
+ throw new Error("invalid credentials");
52
+ }
53
+ export async function authorize(root, token, minRole, storage) {
54
+ const store = storage ?? new FilesystemStorageProvider(root, ".agentdoctor/team");
55
+ const raw = await store.get(`sessions/${token}.json`);
56
+ if (!raw)
57
+ return { ok: false, reason: "missing session" };
58
+ const session = JSON.parse(raw);
59
+ if (Date.parse(session.expiresAt) < Date.now())
60
+ return { ok: false, reason: "expired session" };
61
+ const userRaw = await store.get(`users/${session.userId}.json`);
62
+ if (!userRaw)
63
+ return { ok: false, reason: "missing user" };
64
+ const user = JSON.parse(userRaw);
65
+ const rank = { viewer: 1, member: 2, admin: 3, owner: 4 };
66
+ if ((rank[user.role] ?? 0) < (rank[minRole] ?? 99)) {
67
+ return { ok: false, reason: "insufficient role", user };
68
+ }
69
+ return { ok: true, user, reason: "authorized" };
70
+ }
@@ -9,7 +9,7 @@ export type LanguageId = "typescript" | "javascript" | "python" | "dart" | "php"
9
9
  export type FrameworkId = "nextjs" | "react" | "vue" | "nuxt" | "svelte" | "nodejs" | "express" | "nestjs" | "flutter" | "laravel" | "django" | "fastapi" | "unknown";
10
10
  export type PackageManagerId = "npm" | "pnpm" | "yarn" | "bun" | "composer" | "pub" | "pip" | "poetry" | "cargo" | "gradle" | "unknown";
11
11
  export type MonorepoToolId = "npm-workspaces" | "pnpm-workspaces" | "turborepo" | "nx" | "multi-project" | "none";
12
- export type AgentId = "cursor" | "claude-code" | "codex";
12
+ export type AgentId = "cursor" | "claude-code" | "codex" | "copilot" | "windsurf" | "gemini-cli" | "aider";
13
13
  export interface DiscoveredFile {
14
14
  /** Absolute path */
15
15
  absolutePath: string;
@@ -76,6 +76,10 @@ export interface AgentScores {
76
76
  cursor: number;
77
77
  "claude-code": number;
78
78
  codex: number;
79
+ copilot: number;
80
+ windsurf: number;
81
+ "gemini-cli": number;
82
+ aider: number;
79
83
  }
80
84
  export interface Scores {
81
85
  overall: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@praneeth_54/agentdoctor",
3
- "version": "1.1.0",
4
- "description": "Audit AI coding agent configuration in a repository — local, deterministic, no API key.",
3
+ "version": "2.0.0",
4
+ "description": "Codebase intelligence, repository analysis, safety controls, and MCP tools for developers and engineering teams.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "agentdoctor": "./dist/cli/index.js"
@@ -54,6 +54,10 @@
54
54
  "cursor",
55
55
  "claude-code",
56
56
  "codex",
57
+ "copilot",
58
+ "windsurf",
59
+ "gemini",
60
+ "aider",
57
61
  "mcp",
58
62
  "security",
59
63
  "linter",
@@ -77,19 +81,22 @@
77
81
  "dependencies": {
78
82
  "@modelcontextprotocol/sdk": "^1.30.0",
79
83
  "commander": "^14.0.3",
80
- "picocolors": "^1.1.1"
84
+ "picocolors": "^1.1.1",
85
+ "typescript": "^5.9.3"
81
86
  },
82
87
  "devDependencies": {
83
88
  "@eslint/js": "^9.39.2",
84
89
  "@types/node": "^22.19.1",
85
90
  "eslint": "^9.39.2",
86
91
  "prettier": "^3.7.4",
87
- "tsx": "^4.21.0",
88
- "typescript": "^5.9.3",
89
- "typescript-eslint": "^8.50.0",
92
+ "tsx": "^4.23.13",
93
+ "typescript-eslint": "^8.70.0",
90
94
  "vitest": "^3.2.4"
91
95
  },
92
96
  "overrides": {
93
- "js-yaml": "4.3.1"
97
+ "js-yaml": "4.3.2",
98
+ "fast-uri": "3.1.8",
99
+ "hono": "4.13.8",
100
+ "qs": "6.16.0"
94
101
  }
95
102
  }