@qulib/core 0.3.1 → 0.4.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 (74) hide show
  1. package/dist/analyze.d.ts +2 -0
  2. package/dist/analyze.d.ts.map +1 -1
  3. package/dist/analyze.js +29 -1
  4. package/dist/harness/decision-logger.d.ts +1 -0
  5. package/dist/harness/decision-logger.d.ts.map +1 -1
  6. package/dist/harness/decision-logger.js +15 -22
  7. package/dist/harness/run-options.d.ts +3 -0
  8. package/dist/harness/run-options.d.ts.map +1 -1
  9. package/dist/harness/state-manager.d.ts +3 -0
  10. package/dist/harness/state-manager.d.ts.map +1 -1
  11. package/dist/harness/state-manager.js +15 -18
  12. package/dist/index.d.ts +9 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +5 -0
  15. package/dist/llm/cost-intelligence.d.ts +13 -0
  16. package/dist/llm/cost-intelligence.d.ts.map +1 -1
  17. package/dist/llm/cost-intelligence.js +13 -0
  18. package/dist/llm/provider-registry.d.ts +9 -0
  19. package/dist/llm/provider-registry.d.ts.map +1 -0
  20. package/dist/llm/provider-registry.js +15 -0
  21. package/dist/llm/provider.d.ts +9 -11
  22. package/dist/llm/provider.d.ts.map +1 -1
  23. package/dist/llm/provider.interface.d.ts +16 -0
  24. package/dist/llm/provider.interface.d.ts.map +1 -0
  25. package/dist/llm/provider.interface.js +1 -0
  26. package/dist/llm/provider.js +8 -51
  27. package/dist/llm/providers/anthropic.d.ts +16 -0
  28. package/dist/llm/providers/anthropic.d.ts.map +1 -0
  29. package/dist/llm/providers/anthropic.js +104 -0
  30. package/dist/phases/act.d.ts.map +1 -1
  31. package/dist/phases/act.js +20 -6
  32. package/dist/phases/observe.d.ts.map +1 -1
  33. package/dist/phases/observe.js +20 -2
  34. package/dist/phases/think-finalize.d.ts.map +1 -1
  35. package/dist/phases/think-finalize.js +12 -3
  36. package/dist/phases/think.d.ts.map +1 -1
  37. package/dist/phases/think.js +14 -2
  38. package/dist/schemas/automation-maturity.schema.d.ts +78 -0
  39. package/dist/schemas/automation-maturity.schema.d.ts.map +1 -0
  40. package/dist/schemas/automation-maturity.schema.js +24 -0
  41. package/dist/schemas/config.schema.d.ts +266 -73
  42. package/dist/schemas/config.schema.d.ts.map +1 -1
  43. package/dist/schemas/config.schema.js +30 -18
  44. package/dist/schemas/gap-analysis.schema.d.ts +6 -6
  45. package/dist/schemas/index.d.ts +2 -1
  46. package/dist/schemas/index.d.ts.map +1 -1
  47. package/dist/schemas/index.js +2 -1
  48. package/dist/schemas/public-surface.schema.d.ts +4 -4
  49. package/dist/schemas/repo-analysis.schema.d.ts +134 -0
  50. package/dist/schemas/repo-analysis.schema.d.ts.map +1 -1
  51. package/dist/schemas/repo-analysis.schema.js +29 -0
  52. package/dist/telemetry/emit.d.ts +3 -0
  53. package/dist/telemetry/emit.d.ts.map +1 -0
  54. package/dist/telemetry/emit.js +11 -0
  55. package/dist/telemetry/telemetry.interface.d.ts +13 -0
  56. package/dist/telemetry/telemetry.interface.d.ts.map +1 -0
  57. package/dist/telemetry/telemetry.interface.js +3 -0
  58. package/dist/tools/auth-detector.d.ts.map +1 -1
  59. package/dist/tools/auth-detector.js +205 -26
  60. package/dist/tools/auth-surface-analyzer.d.ts.map +1 -1
  61. package/dist/tools/auth-surface-analyzer.js +26 -10
  62. package/dist/tools/automation-maturity.d.ts +4 -0
  63. package/dist/tools/automation-maturity.d.ts.map +1 -0
  64. package/dist/tools/automation-maturity.js +163 -0
  65. package/dist/tools/framework-detector.d.ts +15 -0
  66. package/dist/tools/framework-detector.d.ts.map +1 -0
  67. package/dist/tools/framework-detector.js +153 -0
  68. package/dist/tools/gap-engine.d.ts +1 -1
  69. package/dist/tools/gap-engine.d.ts.map +1 -1
  70. package/dist/tools/gap-engine.js +13 -3
  71. package/dist/tools/repo-scanner.d.ts +16 -0
  72. package/dist/tools/repo-scanner.d.ts.map +1 -1
  73. package/dist/tools/repo-scanner.js +31 -2
  74. package/package.json +11 -1
package/dist/analyze.d.ts CHANGED
@@ -5,6 +5,7 @@ import type { RepoAnalysis } from './schemas/repo-analysis.schema.js';
5
5
  import type { DecisionLogEntry } from './schemas/decision-log.schema.js';
6
6
  import { type PublicSurface } from './schemas/public-surface.schema.js';
7
7
  import type { AnalyzeProgressSink } from './harness/progress-log.js';
8
+ import type { TelemetrySink } from './telemetry/telemetry.interface.js';
8
9
  export type AnalyzeStatus = 'complete' | 'blocked' | 'partial';
9
10
  export interface AnalyzeOptions {
10
11
  url: string;
@@ -13,6 +14,7 @@ export interface AnalyzeOptions {
13
14
  writeArtifacts?: boolean;
14
15
  skipAuthDetection?: boolean;
15
16
  progressLog?: AnalyzeProgressSink;
17
+ telemetry?: TelemetrySink;
16
18
  }
17
19
  export interface AnalyzeResult {
18
20
  status: AnalyzeStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAChG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAU7F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0GAA0G;IAC1G,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,sFAAsF;IACtF,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,WAAW,EAAE,WAAW,CAAC;IACzB,8GAA8G;IAC9G,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,0HAA0H;IAC1H,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;CACrC;AAcD,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA8HhF"}
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAChG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAU7F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAGxE,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0GAA0G;IAC1G,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,sFAAsF;IACtF,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,WAAW,EAAE,WAAW,CAAC;IACzB,8GAA8G;IAC9G,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,0HAA0H;IAC1H,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;CACrC;AAcD,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA8JhF"}
package/dist/analyze.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { RouteInventorySchema } from './schemas/route-inventory.schema.js';
2
3
  import { PublicSurfaceSchema } from './schemas/public-surface.schema.js';
3
4
  import { observe } from './phases/observe.js';
@@ -9,6 +10,7 @@ import { analyzeAuthSurfaceGaps } from './tools/auth-surface-analyzer.js';
9
10
  import { buildPublicSurface } from './tools/public-surface.js';
10
11
  import { buildAuthBlockGap } from './tools/auth-block-gap.js';
11
12
  import { finalizeGapAnalysisFromDraft } from './phases/think-finalize.js';
13
+ import { emitTelemetry } from './telemetry/emit.js';
12
14
  function logScanEnd(progress, result) {
13
15
  const rc = result.releaseConfidence === null ? 'null' : String(result.releaseConfidence);
14
16
  const cs = result.coverageScore === null ? 'null' : String(result.coverageScore);
@@ -24,17 +26,31 @@ export async function analyzeApp(options) {
24
26
  const writeArtifacts = options.writeArtifacts ?? false;
25
27
  const decisionLog = [];
26
28
  const progress = options.progressLog;
29
+ const sessionId = randomUUID();
27
30
  const artifacts = {
28
31
  writeArtifacts,
29
32
  decisionMemory: decisionLog,
33
+ telemetrySessionId: sessionId,
34
+ ...(options.telemetry !== undefined && { telemetry: options.telemetry }),
30
35
  ...(progress !== undefined && { progressLog: progress }),
31
36
  };
37
+ emitTelemetry(options.telemetry, 'scan.started', sessionId, {
38
+ url: options.url,
39
+ maxPagesToScan: options.config.maxPagesToScan,
40
+ hasAuth: Boolean(options.config.auth),
41
+ });
32
42
  progress?.info(`Starting scan → ${options.url} maxPagesToScan=${options.config.maxPagesToScan}`);
33
43
  let detectedAuth;
34
44
  let authWall = false;
35
45
  if (!options.config.auth && !options.skipAuthDetection) {
36
46
  detectedAuth = await detectAuth(options.url, options.config.timeoutMs, progress);
37
47
  authWall = Boolean(detectedAuth.hasAuth);
48
+ if (detectedAuth.hasAuth) {
49
+ emitTelemetry(options.telemetry, 'auth.detected', sessionId, {
50
+ authType: detectedAuth.type,
51
+ hasAuth: true,
52
+ });
53
+ }
38
54
  }
39
55
  const observed = await observe(options.url, options.repoPath, options.config, artifacts);
40
56
  if (authWall && !options.config.auth && detectedAuth) {
@@ -59,7 +75,7 @@ export async function analyzeApp(options) {
59
75
  const authSurfaceGaps = await analyzeAuthSurfaceGaps(options.url, detectedAuth, options.config.timeoutMs);
60
76
  const authBlockGap = buildAuthBlockGap(options.url);
61
77
  const qualityInputGaps = [...publicAnalysis.gaps, ...authSurfaceGaps];
62
- const qualityScore = computeQualityScoreFromGaps(qualityInputGaps);
78
+ const qualityScore = computeQualityScoreFromGaps(qualityInputGaps, options.config.scoringWeights);
63
79
  const draftRelease = status === 'blocked' ? null : qualityScore;
64
80
  const draft = {
65
81
  analyzedAt: new Date().toISOString(),
@@ -98,6 +114,12 @@ export async function analyzeApp(options) {
98
114
  publicSurface,
99
115
  };
100
116
  logScanEnd(progress, result);
117
+ emitTelemetry(options.telemetry, status === 'blocked' ? 'scan.blocked' : 'scan.completed', sessionId, {
118
+ status: result.status,
119
+ coverageScore: result.coverageScore,
120
+ releaseConfidence: result.releaseConfidence,
121
+ gapCount: result.gaps.length,
122
+ });
101
123
  return result;
102
124
  }
103
125
  const analysis = await think(observed, options.config, artifacts);
@@ -117,5 +139,11 @@ export async function analyzeApp(options) {
117
139
  publicSurface,
118
140
  };
119
141
  logScanEnd(progress, result);
142
+ emitTelemetry(options.telemetry, 'scan.completed', sessionId, {
143
+ status: result.status,
144
+ coverageScore: result.coverageScore,
145
+ releaseConfidence: result.releaseConfidence,
146
+ gapCount: result.gaps.length,
147
+ });
120
148
  return result;
121
149
  }
@@ -2,6 +2,7 @@ import type { DecisionLogEntry } from '../schemas/decision-log.schema.js';
2
2
  export type LogDecisionOptions = {
3
3
  persist?: boolean;
4
4
  memory?: DecisionLogEntry[];
5
+ outputDir?: string;
5
6
  };
6
7
  export declare function logDecision(entry: DecisionLogEntry, options?: LogDecisionOptions): Promise<void>;
7
8
  //# sourceMappingURL=decision-logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decision-logger.d.ts","sourceRoot":"","sources":["../../src/harness/decision-logger.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAK1E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC7B,CAAC;AAEF,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDtG"}
1
+ {"version":3,"file":"decision-logger.d.ts","sourceRoot":"","sources":["../../src/harness/decision-logger.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAG1E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAMF,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DtG"}
@@ -2,15 +2,19 @@ import { readFile, writeFile, mkdir } from 'fs/promises';
2
2
  import { existsSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import { DecisionLogEntrySchema } from '../schemas/decision-log.schema.js';
5
- const LOG_FILE = join(process.cwd(), '.scan-state', 'decision-log.json');
6
- const STATE_DIR = join(process.cwd(), '.scan-state');
5
+ import { resolveScanStateBaseDir } from './state-manager.js';
6
+ function logFilePath(options) {
7
+ return join(resolveScanStateBaseDir(options?.outputDir), 'decision-log.json');
8
+ }
7
9
  export async function logDecision(entry, options) {
8
10
  const persist = options?.persist !== false;
9
11
  const memory = options?.memory;
12
+ const logFile = logFilePath(options);
13
+ const stateDir = resolveScanStateBaseDir(options?.outputDir);
10
14
  try {
11
15
  const validation = DecisionLogEntrySchema.safeParse(entry);
12
16
  if (!validation.success) {
13
- console.warn(`Failed to log decision entry to ${LOG_FILE}: validation issues ${JSON.stringify(validation.error.issues)}`);
17
+ console.warn(`Failed to log decision entry to ${logFile}: validation issues ${JSON.stringify(validation.error.issues)}`);
14
18
  return;
15
19
  }
16
20
  if (memory) {
@@ -19,14 +23,14 @@ export async function logDecision(entry, options) {
19
23
  if (!persist) {
20
24
  return;
21
25
  }
22
- await mkdir(STATE_DIR, { recursive: true });
26
+ await mkdir(stateDir, { recursive: true });
23
27
  let log = [];
24
- if (existsSync(LOG_FILE)) {
28
+ if (existsSync(logFile)) {
25
29
  try {
26
- const raw = await readFile(LOG_FILE, 'utf8');
30
+ const raw = await readFile(logFile, 'utf8');
27
31
  const parsed = JSON.parse(raw);
28
32
  if (!Array.isArray(parsed)) {
29
- console.warn(`Failed to log decision entry to ${LOG_FILE}: file is not a JSON array; resetting log`);
33
+ console.warn(`Failed to log decision entry to ${logFile}: file is not a JSON array; resetting log`);
30
34
  }
31
35
  else {
32
36
  const validatedEntries = [];
@@ -36,7 +40,7 @@ export async function logDecision(entry, options) {
36
40
  validatedEntries.push(itemValidation.data);
37
41
  }
38
42
  else {
39
- console.warn(`Invalid existing entry skipped in ${LOG_FILE}: ${JSON.stringify(itemValidation.error.issues)}`);
43
+ console.warn(`Invalid existing entry skipped in ${logFile}: ${JSON.stringify(itemValidation.error.issues)}`);
40
44
  }
41
45
  }
42
46
  log = validatedEntries;
@@ -44,25 +48,14 @@ export async function logDecision(entry, options) {
44
48
  }
45
49
  catch (error) {
46
50
  const message = error instanceof Error ? error.message : String(error);
47
- console.warn(`Failed to read existing decision log at ${LOG_FILE}: ${message}`);
51
+ console.warn(`Failed to read existing decision log at ${logFile}: ${message}`);
48
52
  }
49
53
  }
50
54
  log.push(validation.data);
51
- await writeFile(LOG_FILE, JSON.stringify(log, null, 2), 'utf8');
55
+ await writeFile(logFile, JSON.stringify(log, null, 2), 'utf8');
52
56
  }
53
57
  catch (error) {
54
58
  const message = error instanceof Error ? error.message : String(error);
55
- console.warn(`Failed to log decision entry to ${LOG_FILE}: ${message}`);
59
+ console.warn(`Failed to log decision entry to ${logFile}: ${message}`);
56
60
  }
57
61
  }
58
- /*
59
- Manual smoke test:
60
-
61
- await logDecision({
62
- timestamp: new Date().toISOString(),
63
- phase: 'observe',
64
- decision: 'Started crawl',
65
- reason: 'Initial discovery pass',
66
- metadata: { url: 'https://example.com' },
67
- });
68
- */
@@ -1,8 +1,11 @@
1
1
  import type { DecisionLogEntry } from '../schemas/decision-log.schema.js';
2
2
  import type { AnalyzeProgressSink } from './progress-log.js';
3
+ import type { TelemetrySink } from '../telemetry/telemetry.interface.js';
3
4
  export type RunArtifactsOptions = {
4
5
  writeArtifacts: boolean;
5
6
  decisionMemory?: DecisionLogEntry[];
6
7
  progressLog?: AnalyzeProgressSink;
8
+ telemetry?: TelemetrySink;
9
+ telemetrySessionId?: string;
7
10
  };
8
11
  //# sourceMappingURL=run-options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-options.d.ts","sourceRoot":"","sources":["../../src/harness/run-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACpC,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC,CAAC"}
1
+ {"version":3,"file":"run-options.d.ts","sourceRoot":"","sources":["../../src/harness/run-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACpC,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC"}
@@ -1,5 +1,8 @@
1
1
  import type { ZodSchema } from 'zod';
2
+ export declare function resolveScanStateBaseDir(outputDir?: string): string;
2
3
  export declare class StateManager {
4
+ private readonly stateDir;
5
+ constructor(scanStateBaseDir?: string);
3
6
  readState<T>(filename: string, schema: ZodSchema<T>): Promise<T>;
4
7
  writeState<T>(filename: string, data: T, schema: ZodSchema<T>): Promise<void>;
5
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../src/harness/state-manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAIrC,qBAAa,YAAY;IACjB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA8BhE,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAiBpF"}
1
+ {"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../src/harness/state-manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAErC,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAKlE;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,gBAAgB,CAAC,EAAE,MAAM;IAI/B,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA8BhE,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAiBpF"}
@@ -1,12 +1,21 @@
1
1
  import { readFile, writeFile, mkdir } from 'fs/promises';
2
2
  import { existsSync } from 'fs';
3
- import { join } from 'path';
3
+ import { join, resolve, isAbsolute } from 'path';
4
4
  import { ZodError } from 'zod';
5
- const STATE_DIR = join(process.cwd(), '.scan-state');
5
+ export function resolveScanStateBaseDir(outputDir) {
6
+ if (outputDir === undefined || outputDir === '') {
7
+ return join(process.cwd(), '.scan-state');
8
+ }
9
+ return isAbsolute(outputDir) ? resolve(outputDir) : resolve(process.cwd(), outputDir);
10
+ }
6
11
  export class StateManager {
12
+ stateDir;
13
+ constructor(scanStateBaseDir) {
14
+ this.stateDir = resolveScanStateBaseDir(scanStateBaseDir);
15
+ }
7
16
  async readState(filename, schema) {
8
- await mkdir(STATE_DIR, { recursive: true });
9
- const filepath = join(STATE_DIR, filename);
17
+ await mkdir(this.stateDir, { recursive: true });
18
+ const filepath = join(this.stateDir, filename);
10
19
  if (!existsSync(filepath)) {
11
20
  throw new Error(`State file missing: ${filename} (${filepath})`);
12
21
  }
@@ -34,7 +43,7 @@ export class StateManager {
34
43
  }
35
44
  }
36
45
  async writeState(filename, data, schema) {
37
- const filepath = join(STATE_DIR, filename);
46
+ const filepath = join(this.stateDir, filename);
38
47
  let validatedData;
39
48
  try {
40
49
  validatedData = schema.parse(data);
@@ -46,19 +55,7 @@ export class StateManager {
46
55
  const message = error instanceof Error ? error.message : String(error);
47
56
  throw new Error(`Failed to validate state data for ${filename}: ${message}`);
48
57
  }
49
- await mkdir(STATE_DIR, { recursive: true });
58
+ await mkdir(this.stateDir, { recursive: true });
50
59
  await writeFile(filepath, JSON.stringify(validatedData, null, 2), 'utf8');
51
60
  }
52
61
  }
53
- /*
54
- Manual smoke test:
55
-
56
- import { z } from 'zod';
57
-
58
- const manager = new StateManager();
59
- const DemoSchema = z.object({ count: z.number().int() });
60
-
61
- await manager.writeState('demo.json', { count: 1 }, DemoSchema);
62
- const loaded = await manager.readState('demo.json', DemoSchema);
63
- console.log(loaded.count); // 1
64
- */
package/dist/index.d.ts CHANGED
@@ -2,8 +2,16 @@ export { analyzeApp } from './analyze.js';
2
2
  export { detectAuth } from './tools/auth-detector.js';
3
3
  export { exploreAuth } from './tools/auth-explorer.js';
4
4
  export { addUserProvider, removeUserProvider, listUserProviders } from './tools/user-providers.js';
5
+ export { scanRepo } from './tools/repo-scanner.js';
6
+ export { computeAutomationMaturity } from './tools/automation-maturity.js';
7
+ export { createProvider } from './llm/provider-registry.js';
5
8
  export { resolveMaxOutputTokensPerLlmCall } from './schemas/config.schema.js';
9
+ export { resolveScanStateBaseDir } from './harness/state-manager.js';
6
10
  export type { AnalyzeOptions, AnalyzeResult, AnalyzeStatus } from './analyze.js';
7
11
  export type { AnalyzeProgressSink } from './harness/progress-log.js';
8
- export type { HarnessConfig, AuthConfig, RouteInventory, GapAnalysis, RepoAnalysis, DetectedAuth, AuthExploration, AuthPath, AuthPathRequirements, CostIntelligence, LlmUsageRecord, RepeatedAiPattern, DeterministicMaturity, PublicSurface, } from './schemas/index.js';
12
+ export type { TelemetrySink, TelemetryEvent, TelemetryEventKind, } from './telemetry/telemetry.interface.js';
13
+ export { NoopTelemetrySink } from './telemetry/telemetry.interface.js';
14
+ export type { LlmCallResult, LlmProvider } from './llm/provider.interface.js';
15
+ export type { CallLlmConfigSlice } from './llm/provider.js';
16
+ export type { HarnessConfig, AuthConfig, RouteInventory, GapAnalysis, RepoAnalysis, DetectedAuth, AuthExploration, AuthPath, AuthPathRequirements, CostIntelligence, LlmUsageRecord, RepeatedAiPattern, DeterministicMaturity, PublicSurface, AutomationMaturity, AutomationMaturityDimension, FrameworkDetectionResult, DetectedFrameworkPrimary, } from './schemas/index.js';
9
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,gCAAgC,EAAE,MAAM,4BAA4B,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjF,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EACV,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACd,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,gCAAgC,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjF,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EACV,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC9E,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,YAAY,EACV,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -2,4 +2,9 @@ export { analyzeApp } from './analyze.js';
2
2
  export { detectAuth } from './tools/auth-detector.js';
3
3
  export { exploreAuth } from './tools/auth-explorer.js';
4
4
  export { addUserProvider, removeUserProvider, listUserProviders } from './tools/user-providers.js';
5
+ export { scanRepo } from './tools/repo-scanner.js';
6
+ export { computeAutomationMaturity } from './tools/automation-maturity.js';
7
+ export { createProvider } from './llm/provider-registry.js';
5
8
  export { resolveMaxOutputTokensPerLlmCall } from './schemas/config.schema.js';
9
+ export { resolveScanStateBaseDir } from './harness/state-manager.js';
10
+ export { NoopTelemetrySink } from './telemetry/telemetry.interface.js';
@@ -1,3 +1,16 @@
1
+ /**
2
+ * @module cost-intelligence
3
+ * @packageBoundary @qulib/core (candidate: @qulib/cost-intelligence)
4
+ *
5
+ * This module assembles CostIntelligence from scan run records.
6
+ * Extraction to @qulib/cost-intelligence is appropriate when:
7
+ * 1. Cross-scan aggregation is needed (trend analysis across multiple runs)
8
+ * 2. Pricing tables for multiple LLM providers need to be maintained
9
+ * 3. A standalone cost reporting dashboard is built
10
+ *
11
+ * The CostIntelligenceSchema is already in @qulib/core/schemas and would
12
+ * remain there (or be duplicated/re-exported) on extraction.
13
+ */
1
14
  import type { GapAnalysis } from '../schemas/gap-analysis.schema.js';
2
15
  import type { CostIntelligence, DeterministicMaturity, LlmUsageRecord, RepeatedAiPattern } from '../schemas/cost-intelligence.schema.js';
3
16
  export declare function summarizeUsageQuality(records: LlmUsageRecord[]): CostIntelligence['usageSummary'];
@@ -1 +1 @@
1
- {"version":3,"file":"cost-intelligence.d.ts","sourceRoot":"","sources":["../../src/llm/cost-intelligence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EAClB,MAAM,wCAAwC,CAAC;AAEhD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAYjG;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,yBAAyB,EAAE,MAAM,GAChC,MAAM,EAAE,CAuBV;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,CAiBzF;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,cAAc,EAAE,KAAK,GAAG,UAAU,CAAC;IACnC,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,EAAE,CAuBX;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,KAAK,GAAG,UAAU,CAAC;IACnC,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG,qBAAqB,CA+CxB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,yBAAyB,EAAE,MAAM,CAAC;IAClC,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,IAAI,CACX,WAAW,EACX,MAAM,GAAG,sBAAsB,GAAG,mBAAmB,GAAG,MAAM,CAC/D,CAAC;IACF,cAAc,EAAE,KAAK,GAAG,UAAU,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG,gBAAgB,CA8BnB;AAED,wBAAgB,8BAA8B,CAAC,yBAAyB,EAAE,MAAM,GAAG,gBAAgB,CAoBlG"}
1
+ {"version":3,"file":"cost-intelligence.d.ts","sourceRoot":"","sources":["../../src/llm/cost-intelligence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EAClB,MAAM,wCAAwC,CAAC;AAEhD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAYjG;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,yBAAyB,EAAE,MAAM,GAChC,MAAM,EAAE,CAuBV;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,CAiBzF;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,cAAc,EAAE,KAAK,GAAG,UAAU,CAAC;IACnC,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,EAAE,CAuBX;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,KAAK,GAAG,UAAU,CAAC;IACnC,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG,qBAAqB,CA+CxB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,yBAAyB,EAAE,MAAM,CAAC;IAClC,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,IAAI,CACX,WAAW,EACX,MAAM,GAAG,sBAAsB,GAAG,mBAAmB,GAAG,MAAM,CAC/D,CAAC;IACF,cAAc,EAAE,KAAK,GAAG,UAAU,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG,gBAAgB,CA8BnB;AAED,wBAAgB,8BAA8B,CAAC,yBAAyB,EAAE,MAAM,GAAG,gBAAgB,CAoBlG"}
@@ -1,3 +1,16 @@
1
+ /**
2
+ * @module cost-intelligence
3
+ * @packageBoundary @qulib/core (candidate: @qulib/cost-intelligence)
4
+ *
5
+ * This module assembles CostIntelligence from scan run records.
6
+ * Extraction to @qulib/cost-intelligence is appropriate when:
7
+ * 1. Cross-scan aggregation is needed (trend analysis across multiple runs)
8
+ * 2. Pricing tables for multiple LLM providers need to be maintained
9
+ * 3. A standalone cost reporting dashboard is built
10
+ *
11
+ * The CostIntelligenceSchema is already in @qulib/core/schemas and would
12
+ * remain there (or be duplicated/re-exported) on extraction.
13
+ */
1
14
  export function summarizeUsageQuality(records) {
2
15
  if (records.length === 0) {
3
16
  return { totalInputTokens: 0, totalOutputTokens: 0, dataQuality: 'none' };
@@ -0,0 +1,9 @@
1
+ import type { HarnessConfig } from '../schemas/config.schema.js';
2
+ import type { LlmProvider } from './provider.interface.js';
3
+ import type { TelemetrySink } from '../telemetry/telemetry.interface.js';
4
+ export type CreateProviderInput = Pick<HarnessConfig, 'llmProvider' | 'llmModel'> & {
5
+ telemetry?: TelemetrySink;
6
+ telemetrySessionId?: string;
7
+ };
8
+ export declare function createProvider(config?: CreateProviderInput): LlmProvider;
9
+ //# sourceMappingURL=provider-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-registry.d.ts","sourceRoot":"","sources":["../../src/llm/provider-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAGzE,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,UAAU,CAAC,GAAG;IAClF,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAMF,wBAAgB,cAAc,CAAC,MAAM,GAAE,mBAAwB,GAAG,WAAW,CAU5E"}
@@ -0,0 +1,15 @@
1
+ import { AnthropicProvider } from './providers/anthropic.js';
2
+ // TODO(@qulib/cost-intelligence): When OpenAI or Vertex provider types are added,
3
+ // LlmUsageRecord.estimatedCostUsd must be populated from provider-specific pricing tables.
4
+ // The cost-intelligence schema already supports this field — it is currently unused.
5
+ export function createProvider(config = {}) {
6
+ const provider = config.llmProvider ?? 'anthropic';
7
+ if (provider === 'anthropic') {
8
+ return new AnthropicProvider({
9
+ model: config.llmModel,
10
+ telemetry: config.telemetry,
11
+ sessionId: config.telemetrySessionId,
12
+ });
13
+ }
14
+ throw new Error(`Unsupported llmProvider: ${String(provider)}`);
15
+ }
@@ -1,14 +1,12 @@
1
1
  import { type Gap, type NeutralScenario } from '../schemas/gap-analysis.schema.js';
2
- export interface LlmCallResult {
3
- text: string;
4
- usage: {
5
- provider: string;
6
- model: string;
7
- inputTokens: number;
8
- outputTokens: number;
9
- dataQuality: 'actual' | 'estimated';
10
- } | null;
11
- }
12
- export declare function callLLM(prompt: string, tokenBudget: number): Promise<LlmCallResult>;
2
+ import type { HarnessConfig } from '../schemas/config.schema.js';
3
+ import type { LlmCallResult } from './provider.interface.js';
4
+ export type { LlmCallResult } from './provider.interface.js';
5
+ export type { LlmProvider } from './provider.interface.js';
6
+ export type CallLlmConfigSlice = Pick<HarnessConfig, 'llmProvider' | 'llmModel'> & {
7
+ telemetry?: import('../telemetry/telemetry.interface.js').TelemetrySink;
8
+ telemetrySessionId?: string;
9
+ };
10
+ export declare function callLLM(prompt: string, tokenBudget: number, harness?: CallLlmConfigSlice): Promise<LlmCallResult>;
13
11
  export declare function generateScenariosFromTemplate(gaps: Gap[]): NeutralScenario[];
14
12
  //# sourceMappingURL=provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,GAAG,EAAE,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAE1G,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,QAAQ,GAAG,WAAW,CAAC;KACrC,GAAG,IAAI,CAAC;CACV;AAMD,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAwDzF;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,eAAe,EAAE,CAuC5E"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,GAAG,EAAE,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAC1G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,UAAU,CAAC,GAAG;IACjF,SAAS,CAAC,EAAE,OAAO,qCAAqC,EAAE,aAAa,CAAC;IACxE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAOxB;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,eAAe,EAAE,CAuC5E"}
@@ -0,0 +1,16 @@
1
+ export interface LlmCallResult {
2
+ text: string;
3
+ usage: {
4
+ provider: string;
5
+ model: string;
6
+ inputTokens: number;
7
+ outputTokens: number;
8
+ dataQuality: 'actual' | 'estimated';
9
+ };
10
+ }
11
+ export interface LlmProvider {
12
+ readonly name: string;
13
+ readonly model: string;
14
+ call(prompt: string, maxOutputTokens: number): Promise<LlmCallResult>;
15
+ }
16
+ //# sourceMappingURL=provider.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.interface.d.ts","sourceRoot":"","sources":["../../src/llm/provider.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,QAAQ,GAAG,WAAW,CAAC;KACrC,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACvE"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,56 +1,13 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { NeutralScenarioSchema } from '../schemas/gap-analysis.schema.js';
3
- function estimateTokensFromChars(chars) {
4
- return Math.max(0, Math.ceil(chars / 4));
5
- }
6
- export async function callLLM(prompt, tokenBudget) {
7
- const apiKey = process.env.ANTHROPIC_API_KEY;
8
- if (!apiKey)
9
- throw new Error('ANTHROPIC_API_KEY is not set');
10
- const model = 'claude-sonnet-4-20250514';
11
- const response = await fetch('https://api.anthropic.com/v1/messages', {
12
- method: 'POST',
13
- headers: {
14
- 'x-api-key': apiKey,
15
- 'anthropic-version': '2023-06-01',
16
- 'content-type': 'application/json',
17
- },
18
- body: JSON.stringify({
19
- model,
20
- max_tokens: tokenBudget,
21
- messages: [{ role: 'user', content: prompt }],
22
- }),
23
- });
24
- if (!response.ok) {
25
- const text = await response.text();
26
- throw new Error(`LLM call failed: ${response.status} ${text}`);
27
- }
28
- const data = (await response.json());
29
- const text = data.content.find((b) => b.type === 'text')?.text ?? '';
30
- const inTok = data.usage?.input_tokens;
31
- const outTok = data.usage?.output_tokens;
32
- if (typeof inTok === 'number' && typeof outTok === 'number') {
33
- return {
34
- text,
35
- usage: {
36
- provider: 'anthropic',
37
- model: data.model ?? model,
38
- inputTokens: inTok,
39
- outputTokens: outTok,
40
- dataQuality: 'actual',
41
- },
42
- };
43
- }
44
- return {
45
- text,
46
- usage: {
47
- provider: 'anthropic',
48
- model: data.model ?? model,
49
- inputTokens: estimateTokensFromChars(prompt.length),
50
- outputTokens: estimateTokensFromChars(text.length),
51
- dataQuality: 'estimated',
52
- },
53
- };
3
+ import { createProvider } from './provider-registry.js';
4
+ export async function callLLM(prompt, tokenBudget, harness) {
5
+ return createProvider({
6
+ llmProvider: harness?.llmProvider,
7
+ llmModel: harness?.llmModel,
8
+ telemetry: harness?.telemetry,
9
+ telemetrySessionId: harness?.telemetrySessionId,
10
+ }).call(prompt, tokenBudget);
54
11
  }
55
12
  export function generateScenariosFromTemplate(gaps) {
56
13
  return gaps.map((gap) => {
@@ -0,0 +1,16 @@
1
+ import type { LlmCallResult, LlmProvider } from '../provider.interface.js';
2
+ import type { TelemetrySink } from '../../telemetry/telemetry.interface.js';
3
+ export type AnthropicProviderOptions = {
4
+ model?: string;
5
+ telemetry?: TelemetrySink;
6
+ sessionId?: string;
7
+ };
8
+ export declare class AnthropicProvider implements LlmProvider {
9
+ readonly name = "anthropic";
10
+ readonly model: string;
11
+ private readonly telemetry?;
12
+ private readonly sessionId;
13
+ constructor(options?: AnthropicProviderOptions);
14
+ call(prompt: string, maxOutputTokens: number): Promise<LlmCallResult>;
15
+ }
16
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAS5E,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,iBAAkB,YAAW,WAAW;IACnD,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,CAAC,EAAE,wBAAwB;IAMxC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CA+F5E"}