tuneprompt 1.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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +146 -0
  5. package/dist/commands/activate.d.ts +1 -0
  6. package/dist/commands/activate.js +91 -0
  7. package/dist/commands/fix.d.ts +1 -0
  8. package/dist/commands/fix.js +187 -0
  9. package/dist/commands/history.d.ts +5 -0
  10. package/dist/commands/history.js +63 -0
  11. package/dist/commands/init.d.ts +1 -0
  12. package/dist/commands/init.js +96 -0
  13. package/dist/commands/run.d.ts +9 -0
  14. package/dist/commands/run.js +216 -0
  15. package/dist/db/migrate.d.ts +2 -0
  16. package/dist/db/migrate.js +8 -0
  17. package/dist/engine/constraintExtractor.d.ts +8 -0
  18. package/dist/engine/constraintExtractor.js +54 -0
  19. package/dist/engine/loader.d.ts +5 -0
  20. package/dist/engine/loader.js +74 -0
  21. package/dist/engine/metaPrompt.d.ts +11 -0
  22. package/dist/engine/metaPrompt.js +129 -0
  23. package/dist/engine/optimizer.d.ts +26 -0
  24. package/dist/engine/optimizer.js +246 -0
  25. package/dist/engine/reporter.d.ts +7 -0
  26. package/dist/engine/reporter.js +58 -0
  27. package/dist/engine/runner.d.ts +9 -0
  28. package/dist/engine/runner.js +169 -0
  29. package/dist/engine/shadowTester.d.ts +11 -0
  30. package/dist/engine/shadowTester.js +156 -0
  31. package/dist/index.d.ts +7 -0
  32. package/dist/index.js +26 -0
  33. package/dist/providers/anthropic.d.ts +12 -0
  34. package/dist/providers/anthropic.js +51 -0
  35. package/dist/providers/base.d.ts +15 -0
  36. package/dist/providers/base.js +10 -0
  37. package/dist/providers/openai.d.ts +12 -0
  38. package/dist/providers/openai.js +58 -0
  39. package/dist/providers/openrouter.d.ts +11 -0
  40. package/dist/providers/openrouter.js +83 -0
  41. package/dist/scoring/exact-match.d.ts +1 -0
  42. package/dist/scoring/exact-match.js +8 -0
  43. package/dist/scoring/json-validator.d.ts +4 -0
  44. package/dist/scoring/json-validator.js +29 -0
  45. package/dist/scoring/semantic.d.ts +8 -0
  46. package/dist/scoring/semantic.js +107 -0
  47. package/dist/services/cloud.service.d.ts +49 -0
  48. package/dist/services/cloud.service.js +82 -0
  49. package/dist/storage/database.d.ts +10 -0
  50. package/dist/storage/database.js +179 -0
  51. package/dist/types/fix.d.ts +28 -0
  52. package/dist/types/fix.js +2 -0
  53. package/dist/types/index.d.ts +58 -0
  54. package/dist/types/index.js +2 -0
  55. package/dist/utils/analytics.d.ts +2 -0
  56. package/dist/utils/analytics.js +22 -0
  57. package/dist/utils/config.d.ts +3 -0
  58. package/dist/utils/config.js +70 -0
  59. package/dist/utils/errorHandler.d.ts +14 -0
  60. package/dist/utils/errorHandler.js +40 -0
  61. package/dist/utils/license.d.ts +40 -0
  62. package/dist/utils/license.js +207 -0
  63. package/dist/utils/storage.d.ts +2 -0
  64. package/dist/utils/storage.js +25 -0
  65. package/package.json +76 -0
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.loadConfig = exports.runTests = void 0;
18
+ __exportStar(require("./engine/runner"), exports);
19
+ __exportStar(require("./engine/loader"), exports);
20
+ __exportStar(require("./engine/optimizer"), exports);
21
+ __exportStar(require("./services/cloud.service"), exports);
22
+ __exportStar(require("./types"), exports);
23
+ var run_1 = require("./commands/run");
24
+ Object.defineProperty(exports, "runTests", { enumerable: true, get: function () { return run_1.runTests; } });
25
+ var config_1 = require("./utils/config");
26
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
@@ -0,0 +1,12 @@
1
+ import { BaseProvider, ProviderResponse } from './base';
2
+ import { ProviderConfig } from '../types';
3
+ export declare class AnthropicProvider extends BaseProvider {
4
+ private client;
5
+ constructor(config: ProviderConfig);
6
+ complete(prompt: string | {
7
+ system?: string;
8
+ user: string;
9
+ }): Promise<ProviderResponse>;
10
+ getEmbedding(text: string): Promise<number[]>;
11
+ private calculateCost;
12
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AnthropicProvider = void 0;
7
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
8
+ const base_1 = require("./base");
9
+ class AnthropicProvider extends base_1.BaseProvider {
10
+ client;
11
+ constructor(config) {
12
+ super(config);
13
+ this.client = new sdk_1.default({
14
+ apiKey: config.apiKey
15
+ });
16
+ }
17
+ async complete(prompt) {
18
+ const systemPrompt = typeof prompt === 'string' ? undefined : prompt.system;
19
+ const userPrompt = typeof prompt === 'string' ? prompt : prompt.user;
20
+ const response = await this.client.messages.create({
21
+ model: this.config.model,
22
+ max_tokens: this.config.maxTokens || 1000,
23
+ temperature: this.config.temperature,
24
+ system: systemPrompt,
25
+ messages: [
26
+ { role: 'user', content: userPrompt }
27
+ ]
28
+ });
29
+ const content = response.content[0].type === 'text'
30
+ ? response.content[0].text
31
+ : '';
32
+ return {
33
+ content,
34
+ tokens: response.usage.input_tokens + response.usage.output_tokens,
35
+ cost: this.calculateCost(response.usage.input_tokens, response.usage.output_tokens)
36
+ };
37
+ }
38
+ async getEmbedding(text) {
39
+ // Anthropic doesn't provide embeddings, use OpenAI as fallback
40
+ // or implement a separate embedding service
41
+ throw new Error('Anthropic does not support embeddings. Use OpenAI provider.');
42
+ }
43
+ calculateCost(inputTokens, outputTokens) {
44
+ // Claude Sonnet 4 pricing (example)
45
+ const inputCostPer1M = 3.00;
46
+ const outputCostPer1M = 15.00;
47
+ return ((inputTokens / 1_000_000) * inputCostPer1M +
48
+ (outputTokens / 1_000_000) * outputCostPer1M);
49
+ }
50
+ }
51
+ exports.AnthropicProvider = AnthropicProvider;
@@ -0,0 +1,15 @@
1
+ import { ProviderConfig } from '../types';
2
+ export interface ProviderResponse {
3
+ content: string;
4
+ tokens?: number;
5
+ cost?: number;
6
+ }
7
+ export declare abstract class BaseProvider {
8
+ protected config: ProviderConfig;
9
+ constructor(config: ProviderConfig);
10
+ abstract complete(prompt: string | {
11
+ system?: string;
12
+ user: string;
13
+ }): Promise<ProviderResponse>;
14
+ abstract getEmbedding(text: string): Promise<number[]>;
15
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseProvider = void 0;
4
+ class BaseProvider {
5
+ config;
6
+ constructor(config) {
7
+ this.config = config;
8
+ }
9
+ }
10
+ exports.BaseProvider = BaseProvider;
@@ -0,0 +1,12 @@
1
+ import { BaseProvider, ProviderResponse } from './base';
2
+ import { ProviderConfig } from '../types';
3
+ export declare class OpenAIProvider extends BaseProvider {
4
+ private client;
5
+ constructor(config: ProviderConfig);
6
+ complete(prompt: string | {
7
+ system?: string;
8
+ user: string;
9
+ }): Promise<ProviderResponse>;
10
+ getEmbedding(text: string): Promise<number[]>;
11
+ private calculateCost;
12
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OpenAIProvider = void 0;
7
+ const openai_1 = __importDefault(require("openai"));
8
+ const base_1 = require("./base");
9
+ class OpenAIProvider extends base_1.BaseProvider {
10
+ client;
11
+ constructor(config) {
12
+ super(config);
13
+ this.client = new openai_1.default({
14
+ apiKey: config.apiKey,
15
+ baseURL: config.baseURL
16
+ });
17
+ }
18
+ async complete(prompt) {
19
+ const messages = [];
20
+ if (typeof prompt === 'string') {
21
+ messages.push({ role: 'user', content: prompt });
22
+ }
23
+ else {
24
+ if (prompt.system) {
25
+ messages.push({ role: 'system', content: prompt.system });
26
+ }
27
+ messages.push({ role: 'user', content: prompt.user });
28
+ }
29
+ const response = await this.client.chat.completions.create({
30
+ model: this.config.model,
31
+ messages,
32
+ max_tokens: this.config.maxTokens,
33
+ temperature: this.config.temperature
34
+ });
35
+ const content = response.choices[0]?.message?.content || '';
36
+ const tokens = response.usage?.total_tokens;
37
+ return {
38
+ content,
39
+ tokens,
40
+ cost: this.calculateCost(tokens || 0)
41
+ };
42
+ }
43
+ async getEmbedding(text) {
44
+ const response = await this.client.embeddings.create({
45
+ model: 'text-embedding-3-small',
46
+ input: text
47
+ });
48
+ return response.data[0].embedding;
49
+ }
50
+ calculateCost(tokens) {
51
+ // Pricing for GPT-4o (example rates)
52
+ const inputCostPer1k = 0.005;
53
+ const outputCostPer1k = 0.015;
54
+ // Simplified: assume 50/50 input/output split
55
+ return ((tokens / 1000) * (inputCostPer1k + outputCostPer1k)) / 2;
56
+ }
57
+ }
58
+ exports.OpenAIProvider = OpenAIProvider;
@@ -0,0 +1,11 @@
1
+ import { BaseProvider, ProviderResponse } from './base';
2
+ import { ProviderConfig } from '../types';
3
+ export declare class OpenRouterProvider extends BaseProvider {
4
+ private baseURL;
5
+ constructor(config: ProviderConfig);
6
+ complete(prompt: string | {
7
+ system?: string;
8
+ user: string;
9
+ }): Promise<ProviderResponse>;
10
+ getEmbedding(text: string): Promise<number[]>;
11
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OpenRouterProvider = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const base_1 = require("./base");
9
+ class OpenRouterProvider extends base_1.BaseProvider {
10
+ baseURL;
11
+ constructor(config) {
12
+ super(config);
13
+ this.baseURL = config.baseURL || 'https://openrouter.ai/api/v1';
14
+ }
15
+ async complete(prompt) {
16
+ const messages = [];
17
+ if (typeof prompt === 'string') {
18
+ messages.push({ role: 'user', content: prompt });
19
+ }
20
+ else {
21
+ if (prompt.system) {
22
+ messages.push({ role: 'system', content: prompt.system });
23
+ }
24
+ messages.push({ role: 'user', content: prompt.user });
25
+ }
26
+ try {
27
+ const response = await axios_1.default.post(`${this.baseURL}/chat/completions`, {
28
+ model: this.config.model,
29
+ messages,
30
+ max_tokens: this.config.maxTokens,
31
+ temperature: this.config.temperature
32
+ }, {
33
+ headers: {
34
+ 'Authorization': `Bearer ${this.config.apiKey}`,
35
+ 'HTTP-Referer': 'https://github.com/tuneprompt/tuneprompt',
36
+ 'X-Title': 'TunePrompt',
37
+ 'Content-Type': 'application/json'
38
+ }
39
+ });
40
+ const data = response.data;
41
+ const content = data.choices?.[0]?.message?.content || '';
42
+ const tokens = data.usage?.total_tokens || 0;
43
+ return {
44
+ content,
45
+ tokens,
46
+ cost: 0
47
+ };
48
+ }
49
+ catch (error) {
50
+ if (error.response) {
51
+ const errorMsg = error.response.data?.error?.message || JSON.stringify(error.response.data);
52
+ throw new Error(`OpenRouter API Error (${error.response.status}): ${errorMsg}`);
53
+ }
54
+ throw new Error(`OpenRouter network error: ${error.message}`);
55
+ }
56
+ }
57
+ async getEmbedding(text) {
58
+ try {
59
+ // Attempt to use OpenRouter's embedding endpoint (which proxies to OpenAI or others)
60
+ // Note: User must be entitled to use the requested embedding model
61
+ const response = await axios_1.default.post(`${this.baseURL}/embeddings`, {
62
+ model: 'text-embedding-3-small', // Default fallback, customizable in future
63
+ input: text
64
+ }, {
65
+ headers: {
66
+ 'Authorization': `Bearer ${this.config.apiKey}`,
67
+ 'HTTP-Referer': 'https://github.com/tuneprompt/tuneprompt',
68
+ 'X-Title': 'TunePrompt',
69
+ 'Content-Type': 'application/json'
70
+ }
71
+ });
72
+ return response.data.data[0].embedding;
73
+ }
74
+ catch (error) {
75
+ if (error.response) {
76
+ const errorMsg = error.response.data?.error?.message || JSON.stringify(error.response.data);
77
+ throw new Error(`OpenRouter Embedding Error (${error.response.status}): ${errorMsg}`);
78
+ }
79
+ throw new Error(`OpenRouter embedding network error: ${error.message}`);
80
+ }
81
+ }
82
+ }
83
+ exports.OpenRouterProvider = OpenRouterProvider;
@@ -0,0 +1 @@
1
+ export declare function exactMatch(expected: string, actual: string): number;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exactMatch = exactMatch;
4
+ function exactMatch(expected, actual) {
5
+ const normalizedExpected = expected.trim().toLowerCase();
6
+ const normalizedActual = actual.trim().toLowerCase();
7
+ return normalizedExpected === normalizedActual ? 1.0 : 0.0;
8
+ }
@@ -0,0 +1,4 @@
1
+ export declare function validateJSON(expected: any, actual: string): {
2
+ score: number;
3
+ error?: string;
4
+ };
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateJSON = validateJSON;
4
+ function validateJSON(expected, actual) {
5
+ try {
6
+ const parsed = JSON.parse(actual);
7
+ // Check if structure matches
8
+ const matches = deepCompare(expected, parsed);
9
+ return { score: matches ? 1.0 : 0.0 };
10
+ }
11
+ catch (error) {
12
+ return {
13
+ score: 0.0,
14
+ error: `Invalid JSON: ${error.message}`
15
+ };
16
+ }
17
+ }
18
+ function deepCompare(expected, actual) {
19
+ if (typeof expected !== typeof actual)
20
+ return false;
21
+ if (typeof expected === 'object' && expected !== null) {
22
+ const expectedKeys = Object.keys(expected);
23
+ const actualKeys = Object.keys(actual);
24
+ if (expectedKeys.length !== actualKeys.length)
25
+ return false;
26
+ return expectedKeys.every(key => actualKeys.includes(key) && deepCompare(expected[key], actual[key]));
27
+ }
28
+ return expected === actual;
29
+ }
@@ -0,0 +1,8 @@
1
+ import { BaseProvider } from '../providers/base';
2
+ export declare class SemanticScorer {
3
+ private embeddingProvider;
4
+ constructor(provider: BaseProvider);
5
+ score(expected: string, actual: string): Promise<number>;
6
+ private cosineSimilarity;
7
+ }
8
+ export declare function calculateSemanticSimilarity(actual: string, expected: string): Promise<number>;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SemanticScorer = void 0;
37
+ exports.calculateSemanticSimilarity = calculateSemanticSimilarity;
38
+ class SemanticScorer {
39
+ embeddingProvider;
40
+ constructor(provider) {
41
+ this.embeddingProvider = provider;
42
+ }
43
+ async score(expected, actual) {
44
+ const [expectedEmb, actualEmb] = await Promise.all([
45
+ this.embeddingProvider.getEmbedding(expected),
46
+ this.embeddingProvider.getEmbedding(actual)
47
+ ]);
48
+ return this.cosineSimilarity(expectedEmb, actualEmb);
49
+ }
50
+ cosineSimilarity(a, b) {
51
+ if (a.length !== b.length) {
52
+ throw new Error('Vectors must have same length');
53
+ }
54
+ let dotProduct = 0;
55
+ let normA = 0;
56
+ let normB = 0;
57
+ for (let i = 0; i < a.length; i++) {
58
+ dotProduct += a[i] * b[i];
59
+ normA += a[i] * a[i];
60
+ normB += b[i] * b[i];
61
+ }
62
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
63
+ }
64
+ }
65
+ exports.SemanticScorer = SemanticScorer;
66
+ async function calculateSemanticSimilarity(actual, expected) {
67
+ const providersToTry = [];
68
+ // Prioritize OpenAI if key looks potentially valid
69
+ if (process.env.OPENAI_API_KEY && !process.env.OPENAI_API_KEY.startsWith('api_key')) {
70
+ providersToTry.push('openai');
71
+ }
72
+ // Always try OpenRouter if key is present
73
+ if (process.env.OPENROUTER_API_KEY) {
74
+ providersToTry.push('openrouter');
75
+ }
76
+ // Fallback to OpenAI if nothing else was added
77
+ if (providersToTry.length === 0) {
78
+ providersToTry.push('openai');
79
+ }
80
+ let lastError;
81
+ for (const providerType of providersToTry) {
82
+ try {
83
+ let provider;
84
+ if (providerType === 'openai') {
85
+ const { OpenAIProvider } = await Promise.resolve().then(() => __importStar(require('../providers/openai')));
86
+ provider = new OpenAIProvider({
87
+ apiKey: process.env.OPENAI_API_KEY || '',
88
+ model: 'text-embedding-3-small'
89
+ });
90
+ }
91
+ else {
92
+ const { OpenRouterProvider } = await Promise.resolve().then(() => __importStar(require('../providers/openrouter')));
93
+ provider = new OpenRouterProvider({
94
+ apiKey: process.env.OPENROUTER_API_KEY || '',
95
+ model: 'text-embedding-3-small'
96
+ });
97
+ }
98
+ const scorer = new SemanticScorer(provider);
99
+ return await scorer.score(expected, actual);
100
+ }
101
+ catch (error) {
102
+ lastError = error;
103
+ continue;
104
+ }
105
+ }
106
+ throw lastError || new Error('No embedding provider available');
107
+ }
@@ -0,0 +1,49 @@
1
+ export interface RunData {
2
+ project_id: string;
3
+ commit_hash?: string;
4
+ branch_name?: string;
5
+ commit_message?: string;
6
+ environment: 'local' | 'ci' | 'production';
7
+ ci_provider?: string;
8
+ total_tests: number;
9
+ passed_tests: number;
10
+ failed_tests: number;
11
+ duration_ms: number;
12
+ cost_usd: number;
13
+ started_at: string;
14
+ completed_at: string;
15
+ test_results: CloudTestResult[];
16
+ }
17
+ export interface CloudTestResult {
18
+ test_name: string;
19
+ test_description?: string;
20
+ prompt: string;
21
+ input_data?: any;
22
+ expected_output: string;
23
+ actual_output: string;
24
+ score?: number;
25
+ method: string;
26
+ status: 'pass' | 'fail' | 'error';
27
+ model: string;
28
+ tokens_used?: number;
29
+ latency_ms?: number;
30
+ cost_usd?: number;
31
+ error_message?: string;
32
+ error_type?: string;
33
+ }
34
+ export declare class CloudService {
35
+ private backendUrl;
36
+ private subscriptionId?;
37
+ constructor();
38
+ init(): Promise<void>;
39
+ private getSubscriptionId;
40
+ uploadRun(data: RunData): Promise<{
41
+ success: boolean;
42
+ run_id?: string;
43
+ url?: string;
44
+ error?: string;
45
+ }>;
46
+ createProject(name: string, description?: string): Promise<any>;
47
+ getProjects(): Promise<any[]>;
48
+ isAuthenticated(): Promise<boolean>;
49
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CloudService = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const license_1 = require("../utils/license");
9
+ class CloudService {
10
+ backendUrl;
11
+ subscriptionId;
12
+ constructor() {
13
+ this.backendUrl = process.env.TUNEPROMPT_API_URL || process.env.BACKEND_URL || 'https://api.tuneprompt.com';
14
+ }
15
+ async init() {
16
+ // Load subscription ID from local storage (Phase 2 activation)
17
+ this.subscriptionId = await this.getSubscriptionId();
18
+ }
19
+ async getSubscriptionId() {
20
+ const license = (0, license_1.loadLicense)();
21
+ return license?.subscriptionId;
22
+ }
23
+ async uploadRun(data) {
24
+ if (!this.subscriptionId) {
25
+ return { success: false, error: 'Not activated. Run `tuneprompt activate` first.' };
26
+ }
27
+ try {
28
+ const response = await axios_1.default.post(`${this.backendUrl}/api/cloud/ingest-run`, data, {
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ 'x-subscription-id': this.subscriptionId,
32
+ },
33
+ timeout: 30000,
34
+ });
35
+ return response.data;
36
+ }
37
+ catch (error) {
38
+ console.error('Failed to upload run:', error.message);
39
+ return {
40
+ success: false,
41
+ error: error.response?.data?.error || error.message
42
+ };
43
+ }
44
+ }
45
+ async createProject(name, description) {
46
+ if (!this.subscriptionId) {
47
+ throw new Error('Not activated');
48
+ }
49
+ try {
50
+ const response = await axios_1.default.post(`${this.backendUrl}/api/cloud/projects`, { name, description }, {
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ 'x-subscription-id': this.subscriptionId,
54
+ },
55
+ });
56
+ return response.data.project;
57
+ }
58
+ catch (error) {
59
+ throw new Error(error.response?.data?.error || error.message);
60
+ }
61
+ }
62
+ async getProjects() {
63
+ if (!this.subscriptionId) {
64
+ return [];
65
+ }
66
+ try {
67
+ const response = await axios_1.default.get(`${this.backendUrl}/api/cloud/projects`, {
68
+ headers: {
69
+ 'x-subscription-id': this.subscriptionId,
70
+ },
71
+ });
72
+ return response.data.projects || [];
73
+ }
74
+ catch (error) {
75
+ return [];
76
+ }
77
+ }
78
+ async isAuthenticated() {
79
+ return !!this.subscriptionId;
80
+ }
81
+ }
82
+ exports.CloudService = CloudService;
@@ -0,0 +1,10 @@
1
+ import { TestRun } from '../types';
2
+ export declare class TestDatabase {
3
+ private db;
4
+ constructor(dbPath?: string);
5
+ private migrate;
6
+ saveRun(run: TestRun): void;
7
+ getRecentRuns(limit?: number): TestRun[];
8
+ private getRunResults;
9
+ close(): void;
10
+ }