@johnfaleke/fathom 0.1.0 → 0.2.1

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 (55) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +345 -285
  3. package/dist/ai/context.d.ts +15 -0
  4. package/dist/ai/context.d.ts.map +1 -0
  5. package/dist/ai/context.js +42 -0
  6. package/dist/ai/context.js.map +1 -0
  7. package/dist/ai/openai.d.ts +19 -0
  8. package/dist/ai/openai.d.ts.map +1 -0
  9. package/dist/ai/openai.js +97 -0
  10. package/dist/ai/openai.js.map +1 -0
  11. package/dist/ai/provider.d.ts +7 -1
  12. package/dist/ai/provider.d.ts.map +1 -1
  13. package/dist/cli.js +64 -20
  14. package/dist/cli.js.map +1 -1
  15. package/dist/commands/check.d.ts +2 -0
  16. package/dist/commands/check.d.ts.map +1 -1
  17. package/dist/commands/check.js +15 -2
  18. package/dist/commands/check.js.map +1 -1
  19. package/dist/commands/config.d.ts +2 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +51 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/interpret.d.ts +15 -0
  24. package/dist/commands/interpret.d.ts.map +1 -0
  25. package/dist/commands/interpret.js +82 -0
  26. package/dist/commands/interpret.js.map +1 -0
  27. package/dist/commands/scan.d.ts +4 -0
  28. package/dist/commands/scan.d.ts.map +1 -0
  29. package/dist/commands/scan.js +46 -0
  30. package/dist/commands/scan.js.map +1 -0
  31. package/dist/commands/setup.d.ts +10 -0
  32. package/dist/commands/setup.d.ts.map +1 -0
  33. package/dist/commands/setup.js +48 -0
  34. package/dist/commands/setup.js.map +1 -0
  35. package/dist/core/model.d.ts +3 -0
  36. package/dist/core/model.d.ts.map +1 -0
  37. package/dist/core/model.js +87 -0
  38. package/dist/core/model.js.map +1 -0
  39. package/dist/core/storage.d.ts +4 -1
  40. package/dist/core/storage.d.ts.map +1 -1
  41. package/dist/core/storage.js +8 -0
  42. package/dist/core/storage.js.map +1 -1
  43. package/dist/index.d.ts +7 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/render/terminal.d.ts +3 -0
  48. package/dist/render/terminal.d.ts.map +1 -1
  49. package/dist/render/terminal.js +19 -0
  50. package/dist/render/terminal.js.map +1 -1
  51. package/dist/types.d.ts +43 -0
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/types.js +1 -0
  54. package/dist/types.js.map +1 -1
  55. package/package.json +50 -50
@@ -0,0 +1,42 @@
1
+ const DEFAULT_MAX_FILE_BYTES = 50_000;
2
+ const SENSITIVE_NAME = /(^|\/)(\.env(?:\..*)?|.*\.(?:pem|key|p12|pfx|jks|crt|cer|der)|id_rsa(?:\..*)?|credentials(?:\..*)?|secrets?(?:\..*)?)$/i;
3
+ const BINARY_EXTENSION = /\.(?:png|jpe?g|gif|webp|ico|pdf|zip|tar|gz|7z|woff2?|ttf|mp[34]|mov|avi|db|sqlite)$/i;
4
+ const SECRET_ASSIGNMENT = /((?:api[_-]?key|access[_-]?token|auth[_-]?token|client[_-]?secret|password|passwd|private[_-]?key|secret)\s*["']?\s*[:=]\s*["']?)([^\s"',}\]]+)/gi;
5
+ const BEARER_TOKEN = /(Bearer\s+)[A-Za-z0-9._~+/=-]+/gi;
6
+ const PEM_BLOCK = /-----BEGIN [^-]+-----[\s\S]*?-----END [^-]+-----/g;
7
+ export async function collectSafeAIContext(ctx, policy = {}) {
8
+ const maxFileBytes = policy.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
9
+ const allowed = policy.includePaths ? new Set(policy.includePaths) : null;
10
+ const files = {};
11
+ const excluded = [];
12
+ for (const relPath of ctx.files) {
13
+ if (SENSITIVE_NAME.test(relPath)) {
14
+ excluded.push({ path: relPath, reason: "sensitive" });
15
+ continue;
16
+ }
17
+ if (allowed && !allowed.has(relPath)) {
18
+ excluded.push({ path: relPath, reason: "not-allowed" });
19
+ continue;
20
+ }
21
+ if (BINARY_EXTENSION.test(relPath)) {
22
+ excluded.push({ path: relPath, reason: "binary" });
23
+ continue;
24
+ }
25
+ const text = await ctx.readText(relPath);
26
+ if (text === null)
27
+ continue;
28
+ if (Buffer.byteLength(text, "utf8") > maxFileBytes) {
29
+ excluded.push({ path: relPath, reason: "too-large" });
30
+ continue;
31
+ }
32
+ files[relPath] = redactSensitiveText(text);
33
+ }
34
+ return { files, excluded };
35
+ }
36
+ export function redactSensitiveText(text) {
37
+ return text
38
+ .replace(PEM_BLOCK, "[REDACTED_PRIVATE_KEY]")
39
+ .replace(BEARER_TOKEN, "$1[REDACTED_TOKEN]")
40
+ .replace(SECRET_ASSIGNMENT, "$1[REDACTED]");
41
+ }
42
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/ai/context.ts"],"names":[],"mappings":"AAEA,MAAM,sBAAsB,GAAG,MAAM,CAAC;AACtC,MAAM,cAAc,GAAG,yHAAyH,CAAC;AACjJ,MAAM,gBAAgB,GAAG,sFAAsF,CAAC;AAChH,MAAM,iBAAiB,GAAG,mJAAmJ,CAAC;AAC9K,MAAM,YAAY,GAAG,kCAAkC,CAAC;AACxD,MAAM,SAAS,GAAG,mDAAmD,CAAC;AAYtE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAmB,EACnB,SAA0B,EAAE;IAE5B,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,sBAAsB,CAAC;IACnE,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,MAAM,QAAQ,GAA8B,EAAE,CAAC;IAE/C,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;YACtD,SAAS;QACX,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;YACxD,SAAS;QACX,CAAC;QACD,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;YACnD,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,IAAI;YAAE,SAAS;QAC5B,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,YAAY,EAAE,CAAC;YACnD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;YACtD,SAAS;QACX,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI;SACR,OAAO,CAAC,SAAS,EAAE,wBAAwB,CAAC;SAC5C,OAAO,CAAC,YAAY,EAAE,oBAAoB,CAAC;SAC3C,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { AIInterpretationRequest, AIInterpretationResult, AIProvider } from "./provider.js";
2
+ import type { ProviderType } from "./provider.js";
3
+ export interface OpenAIProviderOptions {
4
+ apiKey: string;
5
+ model: string;
6
+ baseUrl?: string;
7
+ providerType?: ProviderType;
8
+ }
9
+ export declare class OpenAIProvider implements AIProvider {
10
+ readonly id: string;
11
+ readonly name: string;
12
+ readonly type: ProviderType;
13
+ private readonly apiKey;
14
+ private readonly model;
15
+ private readonly baseUrl;
16
+ constructor(options: OpenAIProviderOptions);
17
+ interpret(input: AIInterpretationRequest): Promise<AIInterpretationResult>;
18
+ }
19
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACtB,UAAU,EACX,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAMD,qBAAa,cAAe,YAAW,UAAU;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,qBAAqB;IAepC,SAAS,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC;CAqDjF"}
@@ -0,0 +1,97 @@
1
+ export class OpenAIProvider {
2
+ id;
3
+ name;
4
+ type;
5
+ apiKey;
6
+ model;
7
+ baseUrl;
8
+ constructor(options) {
9
+ if (!options.apiKey.trim())
10
+ throw new Error("OpenAI API key is required");
11
+ if (!options.model.trim())
12
+ throw new Error("OpenAI model is required");
13
+ this.apiKey = options.apiKey;
14
+ this.model = options.model;
15
+ const baseUrl = new URL(options.baseUrl ?? "https://api.openai.com/v1");
16
+ if (!['http:', 'https:'].includes(baseUrl.protocol) || baseUrl.username || baseUrl.password) {
17
+ throw new Error("Provider base URL must be an http(s) URL without embedded credentials");
18
+ }
19
+ this.baseUrl = baseUrl.toString().replace(/\/$/, "");
20
+ this.type = options.providerType ?? "openai";
21
+ this.id = this.type;
22
+ this.name = this.type === "custom" ? "Custom OpenAI-compatible provider" : "OpenAI";
23
+ }
24
+ async interpret(input) {
25
+ if (input.consent !== true) {
26
+ throw new Error("Explicit consent is required before sending project context");
27
+ }
28
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
29
+ method: "POST",
30
+ headers: {
31
+ Authorization: `Bearer ${this.apiKey}`,
32
+ "Content-Type": "application/json",
33
+ },
34
+ body: JSON.stringify({
35
+ model: this.model,
36
+ temperature: 0,
37
+ response_format: { type: "json_object" },
38
+ messages: [
39
+ {
40
+ role: "system",
41
+ content: "You interpret project work state. Return JSON with summary (string), confidence (number from 0 to 1), and notes (string array). Do not invent evidence.",
42
+ },
43
+ {
44
+ role: "user",
45
+ content: JSON.stringify({
46
+ prompt: input.prompt,
47
+ workState: input.workState,
48
+ evidence: input.evidence,
49
+ context: input.context ?? { files: {}, excluded: [] },
50
+ }),
51
+ },
52
+ ],
53
+ }),
54
+ });
55
+ if (!response.ok) {
56
+ const detail = (await response.text()).slice(0, 500);
57
+ throw new Error(`OpenAI request failed (${response.status}): ${detail}`);
58
+ }
59
+ const payload = (await response.json());
60
+ const content = payload.choices?.[0]?.message?.content;
61
+ if (!content)
62
+ throw new Error("OpenAI response did not contain message content");
63
+ const parsed = parseInterpretation(content);
64
+ return {
65
+ interpretation: true,
66
+ summary: parsed.summary,
67
+ confidence: parsed.confidence,
68
+ notes: parsed.notes,
69
+ evidence: input.evidence,
70
+ provider: this.type,
71
+ };
72
+ }
73
+ }
74
+ function parseInterpretation(content) {
75
+ let value;
76
+ try {
77
+ value = JSON.parse(content);
78
+ }
79
+ catch {
80
+ return { summary: content.trim(), confidence: 0.5, notes: [] };
81
+ }
82
+ if (!value || typeof value !== "object")
83
+ throw new Error("OpenAI response JSON must be an object");
84
+ const result = value;
85
+ if (typeof result.summary !== "string")
86
+ throw new Error("OpenAI response is missing a string summary");
87
+ const confidence = typeof result.confidence === "number" ? result.confidence : 0.5;
88
+ const notes = Array.isArray(result.notes)
89
+ ? result.notes.filter((note) => typeof note === "string")
90
+ : [];
91
+ return {
92
+ summary: result.summary,
93
+ confidence: Math.max(0, Math.min(1, confidence)),
94
+ notes,
95
+ };
96
+ }
97
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,20 @@
1
+ import type { Evidence } from "../types.js";
2
+ import type { SafeAIContext } from "./context.js";
1
3
  export type ProviderType = "openai" | "anthropic" | "google" | "custom";
2
4
  export interface AIInterpretationRequest {
3
5
  projectRoot: string;
4
6
  workState: unknown;
5
7
  prompt: string;
6
- context?: Record<string, unknown>;
8
+ consent: true;
9
+ evidence: Evidence[];
10
+ context?: SafeAIContext;
7
11
  }
8
12
  export interface AIInterpretationResult {
13
+ interpretation: true;
9
14
  summary: string;
10
15
  confidence: number;
11
16
  notes: string[];
17
+ evidence: Evidence[];
12
18
  provider: ProviderType;
13
19
  }
14
20
  export interface AIProvider {
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExE,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC5E"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExE,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC5E"}
package/dist/cli.js CHANGED
@@ -3,26 +3,37 @@ import { cmdInit } from "./commands/init.js";
3
3
  import { cmdCheck } from "./commands/check.js";
4
4
  import { cmdStatus } from "./commands/status.js";
5
5
  import { cmdDiff } from "./commands/diff.js";
6
- const VERSION = "0.1.0";
6
+ import { cmdInterpret } from "./commands/interpret.js";
7
+ import { cmdConfig } from "./commands/config.js";
8
+ import { cmdSetup } from "./commands/setup.js";
9
+ import { cmdScan } from "./commands/scan.js";
10
+ const VERSION = "0.2.1";
7
11
  function printHelp() {
8
- console.log(`fathom ${VERSION}
9
-
10
- Understand the work — local-first Work State with evidence.
11
-
12
- Usage:
13
- fathom <command> [options]
14
-
15
- Commands:
16
- init Initialize Fathom in the current project
17
- set [--current <text>] [--complete <item>] [--incomplete <item>]
18
- Update the active work state
19
- status [--json] Where does the project actually stand?
20
- diff [--json] What meaningfully changed (git-backed in v0.1)
21
- check [--json] Find inconsistencies and forgotten wiring
22
-
23
- Options:
24
- -h, --help Show help
25
- -v, --version Show version
12
+ console.log(`fathom ${VERSION}
13
+
14
+ Understand the work — local-first Work State with evidence.
15
+
16
+ Usage:
17
+ fathom <command> [options]
18
+
19
+ Commands:
20
+ init Initialize Fathom in the current project
21
+ set [--current <text>] [--complete <item>] [--incomplete <item>]
22
+ Update the active work state
23
+ status [--json] Where does the project actually stand?
24
+ diff [--json] What meaningfully changed (git-backed in v0.1)
25
+ check [--json] Find inconsistencies and forgotten wiring
26
+ check --ai [--json] Add opt-in provider interpretation
27
+ config show Show local configuration
28
+ config set <key> <value> Update AI profile configuration
29
+ setup Guided AI setup for this workspace
30
+ scan [--json] Build the local Project Model
31
+ interpret --provider openai
32
+ Opt-in AI interpretation with explicit consent
33
+
34
+ Options:
35
+ -h, --help Show help
36
+ -v, --version Show version
26
37
  `);
27
38
  }
28
39
  async function main() {
@@ -62,7 +73,35 @@ async function main() {
62
73
  process.exitCode = await cmdDiff(process.cwd(), { json });
63
74
  break;
64
75
  case "check":
65
- process.exitCode = await cmdCheck(process.cwd(), { json });
76
+ process.exitCode = await cmdCheck(process.cwd(), {
77
+ json,
78
+ ai: args.includes("--ai"),
79
+ prompt: parseOption(args.slice(1), "--prompt"),
80
+ });
81
+ break;
82
+ case "config":
83
+ process.exitCode = await cmdConfig(process.cwd(), args.slice(1));
84
+ break;
85
+ case "setup":
86
+ process.exitCode = await cmdSetup(process.cwd(), {
87
+ profile: parseOption(args.slice(1), "--profile"),
88
+ provider: parseOption(args.slice(1), "--provider"),
89
+ model: parseOption(args.slice(1), "--model"),
90
+ baseUrl: parseOption(args.slice(1), "--base-url"),
91
+ apiKeyEnv: parseOption(args.slice(1), "--api-key-env"),
92
+ nonInteractive: args.includes("--non-interactive"),
93
+ });
94
+ break;
95
+ case "scan":
96
+ process.exitCode = await cmdScan(process.cwd(), { json });
97
+ break;
98
+ case "interpret":
99
+ process.exitCode = await cmdInterpret(process.cwd(), {
100
+ json,
101
+ provider: parseOption(args.slice(1), "--provider"),
102
+ prompt: parseOption(args.slice(1), "--prompt"),
103
+ consent: args.includes("--consent"),
104
+ });
66
105
  break;
67
106
  default:
68
107
  console.error(`Unknown command: ${command}`);
@@ -116,6 +155,11 @@ function splitList(value) {
116
155
  .map((item) => item.trim())
117
156
  .filter(Boolean);
118
157
  }
158
+ function parseOption(args, option) {
159
+ const index = args.indexOf(option);
160
+ const value = index >= 0 ? args[index + 1] : undefined;
161
+ return value && !value.startsWith("--") ? value : undefined;
162
+ }
119
163
  main().catch((err) => {
120
164
  console.error(err);
121
165
  process.exitCode = 1;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  export declare function cmdCheck(cwd: string, opts?: {
2
2
  json?: boolean;
3
+ ai?: boolean;
4
+ prompt?: string;
3
5
  }): Promise<number>;
4
6
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAcA,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5B,OAAO,CAAC,MAAM,CAAC,CA4BjB"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAeA,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3D,OAAO,CAAC,MAAM,CAAC,CAuCjB"}
@@ -3,7 +3,8 @@ import { builtinChecks } from "../checks/index.js";
3
3
  import { createProjectContext } from "../core/project.js";
4
4
  import { runChecks } from "../core/runner.js";
5
5
  import { appendEvent, applyFindings, isInitialized, loadConfig, loadState, saveState, } from "../core/storage.js";
6
- import { renderFindings } from "../render/terminal.js";
6
+ import { renderFindings, renderInterpretation } from "../render/terminal.js";
7
+ import { interpretProject } from "./interpret.js";
7
8
  export async function cmdCheck(cwd, opts = {}) {
8
9
  const root = path.resolve(cwd);
9
10
  if (!(await isInitialized(root))) {
@@ -21,11 +22,23 @@ export async function cmdCheck(cwd, opts = {}) {
21
22
  at: new Date().toISOString(),
22
23
  findingCount: findings.length,
23
24
  });
25
+ let interpretation;
26
+ if (opts.ai) {
27
+ try {
28
+ interpretation = await interpretProject(root, config, opts.prompt);
29
+ }
30
+ catch (error) {
31
+ console.error(error instanceof Error ? error.message : String(error));
32
+ return 1;
33
+ }
34
+ }
24
35
  if (opts.json) {
25
- console.log(JSON.stringify({ findings, attention: state.attention }, null, 2));
36
+ console.log(JSON.stringify({ findings, attention: state.attention, interpretation: interpretation ? { ...interpretation.result, context: { filesIncluded: Object.keys(interpretation.context.files), excluded: interpretation.context.excluded } } : undefined }, null, 2));
26
37
  }
27
38
  else {
28
39
  process.stdout.write(renderFindings(findings));
40
+ if (interpretation)
41
+ process.stdout.write(renderInterpretation(interpretation.result, interpretation.context));
29
42
  }
30
43
  return findings.some((f) => f.severity === "warning") ? 2 : 0;
31
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,UAAU,EACV,SAAS,EACT,SAAS,GACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAW,EACX,OAA2B,EAAE;IAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAE/B,IAAI,CAAC,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACrE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAErD,IAAI,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACvC,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7B,MAAM,WAAW,CAAC,IAAI,EAAE;QACtB,IAAI,EAAE,OAAO;QACb,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,YAAY,EAAE,QAAQ,CAAC,MAAM;KAC9B,CAAC,CAAC;IAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdConfig(cwd: string, args: string[]): Promise<number>;
2
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAKA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB5E"}
@@ -0,0 +1,51 @@
1
+ import path from "node:path";
2
+ import { isInitialized, loadConfig, fathomPaths } from "../core/storage.js";
3
+ import { writeFile } from "node:fs/promises";
4
+ export async function cmdConfig(cwd, args) {
5
+ const root = path.resolve(cwd);
6
+ if (!(await isInitialized(root))) {
7
+ console.error("Fathom is not initialized. Run `fathom init` first.");
8
+ return 1;
9
+ }
10
+ if (args[0] === "show") {
11
+ console.log(JSON.stringify(await loadConfig(root), null, 2));
12
+ return 0;
13
+ }
14
+ if (args[0] !== "set" || !args[1] || args[2] === undefined) {
15
+ console.error("Usage: fathom config show | fathom config set <key> <value>");
16
+ return 1;
17
+ }
18
+ const config = await loadConfig(root);
19
+ setConfigValue(config, args[1], parseValue(args.slice(2).join(" ")));
20
+ await writeFile(fathomPaths(root).config, JSON.stringify(config, null, 2) + "\n", "utf8");
21
+ console.log(`Updated ${args[1]}.`);
22
+ return 0;
23
+ }
24
+ function setConfigValue(config, key, value) {
25
+ const parts = key.split(".").filter(Boolean);
26
+ if (parts[0] !== "ai" || parts.length < 2) {
27
+ throw new Error("Only ai.* configuration keys can be changed");
28
+ }
29
+ if (parts[1] === "profile" || parts[1] === "enabled" || parts[1] === "includePaths" || parts[1] === "maxFileBytes") {
30
+ (config.ai ??= {})[parts[1]] = value;
31
+ return;
32
+ }
33
+ if (parts[1] !== "profiles" || !parts[2] || !parts[3]) {
34
+ throw new Error("Use ai.profile, ai.enabled, or ai.profiles.<name>.<field>");
35
+ }
36
+ const profiles = (config.ai ??= {}).profiles ??= {};
37
+ const profile = profiles[parts[2]] ??= { provider: "openai", model: "gpt-4o-mini" };
38
+ if (!["provider", "model", "baseUrl", "apiKeyEnv", "includePaths", "maxFileBytes"].includes(parts[3])) {
39
+ throw new Error(`Unknown AI profile field: ${parts[3]}`);
40
+ }
41
+ profile[parts[3]] = value;
42
+ }
43
+ function parseValue(value) {
44
+ try {
45
+ return JSON.parse(value);
46
+ }
47
+ catch {
48
+ return value;
49
+ }
50
+ }
51
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { collectSafeAIContext } from "../ai/context.js";
2
+ import type { AIInterpretationResult } from "../ai/provider.js";
3
+ import type { FathomConfig } from "../types.js";
4
+ export interface InterpretationRun {
5
+ result: AIInterpretationResult;
6
+ context: Awaited<ReturnType<typeof collectSafeAIContext>>;
7
+ }
8
+ export declare function interpretProject(root: string, config: FathomConfig, prompt?: string): Promise<InterpretationRun>;
9
+ export declare function cmdInterpret(cwd: string, opts?: {
10
+ json?: boolean;
11
+ provider?: string;
12
+ prompt?: string;
13
+ consent?: boolean;
14
+ }): Promise<number>;
15
+ //# sourceMappingURL=interpret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpret.d.ts","sourceRoot":"","sources":["../../src/commands/interpret.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC;CAC3D;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,EACpB,MAAM,SAA+C,GACpD,OAAO,CAAC,iBAAiB,CAAC,CA0C5B;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GACnF,OAAO,CAAC,MAAM,CAAC,CA6BjB"}
@@ -0,0 +1,82 @@
1
+ import path from "node:path";
2
+ import { OpenAIProvider } from "../ai/openai.js";
3
+ import { collectSafeAIContext } from "../ai/context.js";
4
+ import { createProjectContext } from "../core/project.js";
5
+ import { appendEvent, isInitialized, loadConfig, loadState } from "../core/storage.js";
6
+ import { renderInterpretation } from "../render/terminal.js";
7
+ export async function interpretProject(root, config, prompt = "Summarize likely follow-up work and risks.") {
8
+ const state = await loadState(root);
9
+ const profileName = config.ai?.profile ?? "default";
10
+ const profile = config.ai?.profiles?.[profileName] ?? {
11
+ provider: "openai",
12
+ model: process.env.FATHOM_AI_MODEL ?? "gpt-4o-mini",
13
+ baseUrl: process.env.FATHOM_AI_BASE_URL,
14
+ apiKeyEnv: "OPENAI_API_KEY",
15
+ includePaths: config.ai?.includePaths,
16
+ maxFileBytes: config.ai?.maxFileBytes,
17
+ };
18
+ const apiKeyName = profile.apiKeyEnv ?? "OPENAI_API_KEY";
19
+ const apiKey = process.env[apiKeyName];
20
+ if (!apiKey)
21
+ throw new Error(`${apiKeyName} is required for the ${profileName} AI profile.`);
22
+ const projectContext = await createProjectContext(root, config);
23
+ const context = await collectSafeAIContext(projectContext, {
24
+ includePaths: profile.includePaths ?? config.ai?.includePaths,
25
+ maxFileBytes: profile.maxFileBytes ?? config.ai?.maxFileBytes,
26
+ });
27
+ const provider = new OpenAIProvider({
28
+ apiKey,
29
+ model: profile.model,
30
+ baseUrl: profile.baseUrl,
31
+ providerType: profile.provider,
32
+ });
33
+ const result = await provider.interpret({
34
+ projectRoot: root,
35
+ workState: state,
36
+ prompt,
37
+ consent: true,
38
+ evidence: state.findings.flatMap((finding) => finding.evidence),
39
+ context,
40
+ });
41
+ await appendEvent(root, {
42
+ type: "interpret",
43
+ at: new Date().toISOString(),
44
+ provider: result.provider,
45
+ profile: profileName,
46
+ filesIncluded: Object.keys(context.files).length,
47
+ filesExcluded: context.excluded.length,
48
+ });
49
+ return { result, context };
50
+ }
51
+ export async function cmdInterpret(cwd, opts = {}) {
52
+ const root = path.resolve(cwd);
53
+ if (!(await isInitialized(root))) {
54
+ console.error("Fathom is not initialized. Run `fathom init` first.");
55
+ return 1;
56
+ }
57
+ if (opts.consent !== true) {
58
+ console.error("Interpretation sends filtered project context to a provider.");
59
+ console.error("Repeat with `--consent` after reviewing the provider and ignore rules.");
60
+ return 1;
61
+ }
62
+ if (opts.provider && opts.provider !== "openai" && opts.provider !== "custom") {
63
+ console.error(`Unsupported provider: ${opts.provider}. v0.2 supports openai and custom.`);
64
+ return 1;
65
+ }
66
+ try {
67
+ const config = await loadConfig(root);
68
+ const run = await interpretProject(root, config, opts.prompt);
69
+ if (opts.json) {
70
+ console.log(JSON.stringify({ ...run.result, context: { filesIncluded: Object.keys(run.context.files), excluded: run.context.excluded } }, null, 2));
71
+ }
72
+ else {
73
+ process.stdout.write(renderInterpretation(run.result, run.context));
74
+ }
75
+ return 0;
76
+ }
77
+ catch (error) {
78
+ console.error(error instanceof Error ? error.message : String(error));
79
+ return 1;
80
+ }
81
+ }
82
+ //# sourceMappingURL=interpret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpret.js","sourceRoot":"","sources":["../../src/commands/interpret.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function cmdScan(cwd: string, opts?: {
2
+ json?: boolean;
3
+ }): Promise<number>;
4
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAMA,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBzF"}
@@ -0,0 +1,46 @@
1
+ import path from "node:path";
2
+ import { buildProjectModel } from "../core/model.js";
3
+ import { createProjectContext } from "../core/project.js";
4
+ import { appendEvent, isInitialized, loadConfig, saveProjectModel } from "../core/storage.js";
5
+ export async function cmdScan(cwd, opts = {}) {
6
+ const root = path.resolve(cwd);
7
+ if (!(await isInitialized(root))) {
8
+ console.error("Fathom is not initialized. Run `fathom init` first.");
9
+ return 1;
10
+ }
11
+ const config = await loadConfig(root);
12
+ const context = await createProjectContext(root, config);
13
+ const model = await buildProjectModel(context);
14
+ await saveProjectModel(root, model);
15
+ await appendEvent(root, {
16
+ type: "scan",
17
+ at: new Date().toISOString(),
18
+ files: model.project.files,
19
+ claims: model.claims.length,
20
+ });
21
+ if (opts.json) {
22
+ console.log(JSON.stringify(model, null, 2));
23
+ }
24
+ else {
25
+ process.stdout.write(renderScan(model));
26
+ }
27
+ return 0;
28
+ }
29
+ function renderScan(model) {
30
+ const lines = [
31
+ "FATHOM SCAN",
32
+ "",
33
+ `Project: ${model.project.name ?? "(unnamed)"}`,
34
+ `Files: ${model.project.files}`,
35
+ `Stack: ${model.project.stack.length ? model.project.stack.join(", ") : "(not detected)"}`,
36
+ `Dependencies: ${model.project.dependencies.length}`,
37
+ "",
38
+ "Claims:",
39
+ ];
40
+ for (const claim of model.claims) {
41
+ lines.push(` ${claim.subject} ${claim.predicate} ${claim.object} (${Math.round(claim.confidence * 100)}% confidence)`);
42
+ }
43
+ lines.push("", "Saved to .fathom/model.json");
44
+ return lines.join("\n") + "\n";
45
+ }
46
+ //# sourceMappingURL=scan.js.map