@fastino-ai/pioneer-cli 0.2.9 → 0.2.11
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.
- package/README.md +49 -12
- package/dist/index.js +248 -0
- package/dist/yoga.wasm +0 -0
- package/package.json +14 -6
- package/src/api.ts +0 -3086
- package/src/chat/ChatApp.tsx +0 -1028
- package/src/chat/index.ts +0 -7
- package/src/client/ToolExecutor.ts +0 -175
- package/src/client/WebSocketClient.ts +0 -379
- package/src/client/index.ts +0 -2
- package/src/config.ts +0 -225
- package/src/index.tsx +0 -5763
- package/src/telemetry.ts +0 -173
- package/src/tests/api.test.ts +0 -104
- package/src/tests/config-functions.test.ts +0 -163
- package/src/tests/config.test.ts +0 -33
- package/src/tests/file-resolver-edge-cases.test.ts +0 -92
- package/src/tests/telemetry.test.ts +0 -111
- package/src/tests/tool-types.test.ts +0 -104
- package/src/tests/utils.test.ts +0 -90
- package/src/tools/bash.ts +0 -184
- package/src/tools/filesystem.ts +0 -444
- package/src/tools/index.ts +0 -22
- package/src/tools/sandbox.ts +0 -310
- package/src/tools/types.ts +0 -25
- package/src/utils/FileResolver.ts +0 -321
- package/src/utils/index.ts +0 -6
package/src/telemetry.ts
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telemetry module for Pioneer CLI.
|
|
3
|
-
* Opt-in anonymous analytics sent via Pioneer API → Datadog.
|
|
4
|
-
*
|
|
5
|
-
* Privacy-first:
|
|
6
|
-
* - Disabled by default, requires explicit opt-in
|
|
7
|
-
* - Anonymous UUID per installation (no PII)
|
|
8
|
-
* - Only tracks feature usage, never user content
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import crypto from "crypto";
|
|
12
|
-
import os from "os";
|
|
13
|
-
import { loadConfig, saveConfig, getBaseUrl, getApiKey } from "./config.js";
|
|
14
|
-
import packageJson from "../package.json";
|
|
15
|
-
|
|
16
|
-
// Telemetry endpoint on Pioneer API (forwards to Datadog)
|
|
17
|
-
const TELEMETRY_PATH = "/cli/telemetry";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Get or create an anonymous installation ID.
|
|
21
|
-
*/
|
|
22
|
-
function getAnonymousId(): string {
|
|
23
|
-
const config = loadConfig();
|
|
24
|
-
|
|
25
|
-
if (config.telemetry?.anonymousId) {
|
|
26
|
-
return config.telemetry.anonymousId;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const anonymousId = crypto.randomUUID();
|
|
30
|
-
saveConfig({
|
|
31
|
-
telemetry: {
|
|
32
|
-
...config.telemetry,
|
|
33
|
-
anonymousId,
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return anonymousId;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Check if telemetry is enabled.
|
|
42
|
-
*/
|
|
43
|
-
export function isEnabled(): boolean {
|
|
44
|
-
if (process.env.PIONEER_TELEMETRY === "false") return false;
|
|
45
|
-
if (process.env.PIONEER_TELEMETRY === "true") return true;
|
|
46
|
-
|
|
47
|
-
const config = loadConfig();
|
|
48
|
-
return config.telemetry?.enabled === true;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Check if user has made a telemetry choice.
|
|
53
|
-
*/
|
|
54
|
-
export function hasChosenTelemetry(): boolean {
|
|
55
|
-
const config = loadConfig();
|
|
56
|
-
return config.telemetry?.enabled !== undefined;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Enable or disable telemetry.
|
|
61
|
-
*/
|
|
62
|
-
export function setEnabled(enabled: boolean): void {
|
|
63
|
-
const config = loadConfig();
|
|
64
|
-
saveConfig({
|
|
65
|
-
telemetry: {
|
|
66
|
-
...config.telemetry,
|
|
67
|
-
enabled,
|
|
68
|
-
anonymousId: enabled
|
|
69
|
-
? (config.telemetry?.anonymousId || crypto.randomUUID())
|
|
70
|
-
: config.telemetry?.anonymousId,
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Send event to Pioneer API telemetry endpoint.
|
|
77
|
-
* Fire-and-forget, never blocks or throws.
|
|
78
|
-
*/
|
|
79
|
-
function sendEvent(event: string, properties?: Record<string, unknown>): void {
|
|
80
|
-
if (!isEnabled()) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const baseUrl = getBaseUrl().replace(/\/$/, "");
|
|
85
|
-
const url = `${baseUrl}${TELEMETRY_PATH}`;
|
|
86
|
-
const apiKey = getApiKey();
|
|
87
|
-
|
|
88
|
-
const payload = {
|
|
89
|
-
event,
|
|
90
|
-
installation_id: getAnonymousId(),
|
|
91
|
-
cli_version: packageJson.version,
|
|
92
|
-
os_type: os.type(),
|
|
93
|
-
os_platform: os.platform(),
|
|
94
|
-
os_arch: os.arch(),
|
|
95
|
-
...properties,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
99
|
-
if (apiKey) {
|
|
100
|
-
headers["X-API-Key"] = apiKey;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
fetch(url, {
|
|
105
|
-
method: "POST",
|
|
106
|
-
headers,
|
|
107
|
-
body: JSON.stringify(payload),
|
|
108
|
-
}).catch(() => {});
|
|
109
|
-
} catch {
|
|
110
|
-
// Silently fail
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Track an event.
|
|
116
|
-
*/
|
|
117
|
-
export function track(event: string, properties?: Record<string, unknown>): void {
|
|
118
|
-
sendEvent(event, properties);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Track CLI command invocation.
|
|
123
|
-
*/
|
|
124
|
-
export function trackCommand(command: string, subcommand?: string): void {
|
|
125
|
-
track("cli_command", { command, subcommand });
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Track dataset generation.
|
|
130
|
-
*/
|
|
131
|
-
export function trackDatasetGenerate(
|
|
132
|
-
type: "ner" | "classification" | "custom",
|
|
133
|
-
numExamples: number,
|
|
134
|
-
saveToRemote: boolean
|
|
135
|
-
): void {
|
|
136
|
-
track("dataset_generate", { type, num_examples: numExamples, save_to_remote: saveToRemote });
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Track chat session start.
|
|
141
|
-
*/
|
|
142
|
-
export function trackChatSessionStart(provider: string, model: string): void {
|
|
143
|
-
track("chat_session_start", { provider, model });
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Track chat session end.
|
|
148
|
-
*/
|
|
149
|
-
export function trackChatSessionEnd(
|
|
150
|
-
durationMs: number,
|
|
151
|
-
messageCount: number,
|
|
152
|
-
toolCallCount: number
|
|
153
|
-
): void {
|
|
154
|
-
track("chat_session_end", {
|
|
155
|
-
duration_seconds: Math.round(durationMs / 1000),
|
|
156
|
-
message_count: messageCount,
|
|
157
|
-
tool_call_count: toolCallCount,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Track job creation.
|
|
163
|
-
*/
|
|
164
|
-
export function trackJobCreate(baseModel: string): void {
|
|
165
|
-
track("job_create", { base_model: baseModel });
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Track model download.
|
|
170
|
-
*/
|
|
171
|
-
export function trackModelDownload(): void {
|
|
172
|
-
track("model_download");
|
|
173
|
-
}
|
package/src/tests/api.test.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from "bun:test";
|
|
2
|
-
import type { DatasetRef, ApiResult } from "../api";
|
|
3
|
-
|
|
4
|
-
describe("API helper functions", () => {
|
|
5
|
-
describe("Error formatting and detection", () => {
|
|
6
|
-
test("should identify 401 as authentication error", () => {
|
|
7
|
-
// Test the isAuthError logic by checking status codes
|
|
8
|
-
const authStatuses = [401, 403];
|
|
9
|
-
authStatuses.forEach(status => {
|
|
10
|
-
// These status codes should be treated as auth errors
|
|
11
|
-
expect(status === 401 || status === 403).toBe(true);
|
|
12
|
-
});
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test("should identify auth-related error text", () => {
|
|
16
|
-
const authErrorTexts = [
|
|
17
|
-
"Authentication failed",
|
|
18
|
-
"API key invalid",
|
|
19
|
-
"unauthorized access",
|
|
20
|
-
"UNAUTHORIZED",
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
authErrorTexts.forEach(text => {
|
|
24
|
-
const lowerText = text.toLowerCase();
|
|
25
|
-
const isAuthError =
|
|
26
|
-
lowerText.includes("authentication") ||
|
|
27
|
-
lowerText.includes("api key") ||
|
|
28
|
-
lowerText.includes("unauthorized");
|
|
29
|
-
|
|
30
|
-
expect(isAuthError).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("should not identify non-auth errors", () => {
|
|
35
|
-
const nonAuthErrors = [
|
|
36
|
-
"Bad request",
|
|
37
|
-
"Not found",
|
|
38
|
-
"Internal server error",
|
|
39
|
-
"Validation failed",
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
nonAuthErrors.forEach(text => {
|
|
43
|
-
const lowerText = text.toLowerCase();
|
|
44
|
-
const isAuthError =
|
|
45
|
-
lowerText.includes("authentication") ||
|
|
46
|
-
lowerText.includes("api key") ||
|
|
47
|
-
lowerText.includes("unauthorized");
|
|
48
|
-
|
|
49
|
-
expect(isAuthError).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test("auth error message should include helpful instructions", () => {
|
|
54
|
-
const expectedParts = [
|
|
55
|
-
"pioneer auth login",
|
|
56
|
-
"https://agent.pioneer.ai",
|
|
57
|
-
"Authentication failed",
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
// This tests the expected format of formatAuthError()
|
|
61
|
-
expectedParts.forEach(part => {
|
|
62
|
-
expect(typeof part).toBe("string");
|
|
63
|
-
expect(part.length).toBeGreaterThan(0);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe("Type definitions", () => {
|
|
69
|
-
test("DatasetRef should have name and version", () => {
|
|
70
|
-
const ref: DatasetRef = {
|
|
71
|
-
name: "test-dataset",
|
|
72
|
-
version: "v1"
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
expect(ref.name).toBe("test-dataset");
|
|
76
|
-
expect(ref.version).toBe("v1");
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test("ApiResult should support success with data", () => {
|
|
80
|
-
const result: ApiResult<{ message: string }> = {
|
|
81
|
-
ok: true,
|
|
82
|
-
status: 200,
|
|
83
|
-
data: { message: "success" }
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
expect(result.ok).toBe(true);
|
|
87
|
-
expect(result.status).toBe(200);
|
|
88
|
-
expect(result.data?.message).toBe("success");
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("ApiResult should support error without data", () => {
|
|
92
|
-
const result: ApiResult = {
|
|
93
|
-
ok: false,
|
|
94
|
-
status: 400,
|
|
95
|
-
error: "Bad request"
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
expect(result.ok).toBe(false);
|
|
99
|
-
expect(result.status).toBe(400);
|
|
100
|
-
expect(result.error).toBe("Bad request");
|
|
101
|
-
expect(result.data).toBeUndefined();
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
});
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
|
|
2
|
-
import * as fs from "fs";
|
|
3
|
-
import * as os from "os";
|
|
4
|
-
import * as path from "path";
|
|
5
|
-
import {
|
|
6
|
-
loadConfig,
|
|
7
|
-
saveConfig,
|
|
8
|
-
clearApiKey,
|
|
9
|
-
getApiKey,
|
|
10
|
-
getBaseUrl,
|
|
11
|
-
getMleModel,
|
|
12
|
-
setMleModel,
|
|
13
|
-
getConfigDir,
|
|
14
|
-
getHfToken,
|
|
15
|
-
setHfToken,
|
|
16
|
-
clearHfToken,
|
|
17
|
-
DEFAULT_BASE_URL,
|
|
18
|
-
} from "../config";
|
|
19
|
-
|
|
20
|
-
describe("Config file operations", () => {
|
|
21
|
-
const testConfigDir = path.join(os.tmpdir(), `.pioneer-test-${Date.now()}`);
|
|
22
|
-
const testConfigFile = path.join(testConfigDir, "config.json");
|
|
23
|
-
let originalHome: string | undefined;
|
|
24
|
-
let originalApiKey: string | undefined;
|
|
25
|
-
let originalApiUrl: string | undefined;
|
|
26
|
-
let originalHfToken: string | undefined;
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
// Save original env vars
|
|
30
|
-
originalHome = process.env.HOME;
|
|
31
|
-
originalApiKey = process.env.PIONEER_API_KEY;
|
|
32
|
-
originalApiUrl = process.env.PIONEER_API_URL;
|
|
33
|
-
originalHfToken = process.env.HF_TOKEN;
|
|
34
|
-
|
|
35
|
-
// Clear env vars for testing
|
|
36
|
-
delete process.env.PIONEER_API_KEY;
|
|
37
|
-
delete process.env.PIONEER_API_URL;
|
|
38
|
-
delete process.env.HF_TOKEN;
|
|
39
|
-
|
|
40
|
-
// Create test directory
|
|
41
|
-
if (!fs.existsSync(testConfigDir)) {
|
|
42
|
-
fs.mkdirSync(testConfigDir, { recursive: true });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Mock the config directory to use our test directory
|
|
46
|
-
process.env.HOME = os.tmpdir();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
afterEach(() => {
|
|
50
|
-
// Restore original env vars
|
|
51
|
-
if (originalHome !== undefined) {
|
|
52
|
-
process.env.HOME = originalHome;
|
|
53
|
-
}
|
|
54
|
-
if (originalApiKey !== undefined) {
|
|
55
|
-
process.env.PIONEER_API_KEY = originalApiKey;
|
|
56
|
-
}
|
|
57
|
-
if (originalApiUrl !== undefined) {
|
|
58
|
-
process.env.PIONEER_API_URL = originalApiUrl;
|
|
59
|
-
}
|
|
60
|
-
if (originalHfToken !== undefined) {
|
|
61
|
-
process.env.HF_TOKEN = originalHfToken;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Clean up test directory
|
|
65
|
-
if (fs.existsSync(testConfigDir)) {
|
|
66
|
-
fs.rmSync(testConfigDir, { recursive: true, force: true });
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe("loadConfig", () => {
|
|
71
|
-
test("should return config object (may have defaults)", () => {
|
|
72
|
-
const config = loadConfig();
|
|
73
|
-
expect(typeof config).toBe("object");
|
|
74
|
-
expect(config).toBeDefined();
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe("saveConfig and persistence", () => {
|
|
79
|
-
test("should save and load config", () => {
|
|
80
|
-
// This test interacts with actual config, so we test the behavior
|
|
81
|
-
const testModel = "claude-sonnet-4-5-20250929";
|
|
82
|
-
setMleModel(testModel);
|
|
83
|
-
|
|
84
|
-
const model = getMleModel();
|
|
85
|
-
expect(model).toBe(testModel);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("should handle HF token operations", () => {
|
|
89
|
-
// Set token
|
|
90
|
-
setHfToken("test-token-12345");
|
|
91
|
-
const token = getHfToken();
|
|
92
|
-
expect(token).toBe("test-token-12345");
|
|
93
|
-
|
|
94
|
-
// Clear token
|
|
95
|
-
clearHfToken();
|
|
96
|
-
const clearedToken = getHfToken();
|
|
97
|
-
expect(clearedToken).toBeUndefined();
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe("getBaseUrl", () => {
|
|
102
|
-
test("should return default base URL when not configured", () => {
|
|
103
|
-
const baseUrl = getBaseUrl();
|
|
104
|
-
expect(baseUrl).toBe(DEFAULT_BASE_URL);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("should prioritize environment variable over default", () => {
|
|
108
|
-
process.env.PIONEER_API_URL = "https://test.example.com";
|
|
109
|
-
const baseUrl = getBaseUrl();
|
|
110
|
-
expect(baseUrl).toBe("https://test.example.com");
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
describe("getApiKey", () => {
|
|
115
|
-
test("should return undefined when no API key is set", () => {
|
|
116
|
-
const apiKey = getApiKey();
|
|
117
|
-
expect(apiKey).toBeUndefined();
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("should prioritize environment variable", () => {
|
|
121
|
-
process.env.PIONEER_API_KEY = "test-key-from-env";
|
|
122
|
-
const apiKey = getApiKey();
|
|
123
|
-
expect(apiKey).toBe("test-key-from-env");
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe("getMleModel", () => {
|
|
128
|
-
test("should return configured model or undefined", () => {
|
|
129
|
-
const model = getMleModel();
|
|
130
|
-
// May be undefined or a valid model string depending on config state
|
|
131
|
-
if (model !== undefined) {
|
|
132
|
-
expect(typeof model).toBe("string");
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe("getConfigDir", () => {
|
|
138
|
-
test("should return a valid directory path", () => {
|
|
139
|
-
const dir = getConfigDir();
|
|
140
|
-
expect(typeof dir).toBe("string");
|
|
141
|
-
expect(dir.length).toBeGreaterThan(0);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
describe("getHfToken", () => {
|
|
146
|
-
test("should return undefined when no token is set", () => {
|
|
147
|
-
const token = getHfToken();
|
|
148
|
-
expect(token).toBeUndefined();
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test("should prioritize explicit token parameter", () => {
|
|
152
|
-
process.env.HF_TOKEN = "env-token";
|
|
153
|
-
const token = getHfToken("explicit-token");
|
|
154
|
-
expect(token).toBe("explicit-token");
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test("should use environment variable when no explicit token", () => {
|
|
158
|
-
process.env.HF_TOKEN = "env-token";
|
|
159
|
-
const token = getHfToken();
|
|
160
|
-
expect(token).toBe("env-token");
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
package/src/tests/config.test.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from "bun:test";
|
|
2
|
-
import { DEFAULT_BASE_URL, DEFAULT_MLE_MODEL, AVAILABLE_MLE_MODELS } from "../config";
|
|
3
|
-
|
|
4
|
-
describe("Config defaults", () => {
|
|
5
|
-
test("DEFAULT_BASE_URL should be defined", () => {
|
|
6
|
-
expect(DEFAULT_BASE_URL).toBeDefined();
|
|
7
|
-
expect(typeof DEFAULT_BASE_URL).toBe("string");
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test("DEFAULT_MLE_MODEL should be defined", () => {
|
|
11
|
-
expect(DEFAULT_MLE_MODEL).toBeDefined();
|
|
12
|
-
expect(typeof DEFAULT_MLE_MODEL).toBe("string");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test("AVAILABLE_MLE_MODELS should contain default model", () => {
|
|
16
|
-
const modelIds = AVAILABLE_MLE_MODELS.map(m => m.id);
|
|
17
|
-
expect(modelIds).toContain(DEFAULT_MLE_MODEL);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test("AVAILABLE_MLE_MODELS should have valid structure", () => {
|
|
21
|
-
expect(Array.isArray(AVAILABLE_MLE_MODELS)).toBe(true);
|
|
22
|
-
expect(AVAILABLE_MLE_MODELS.length).toBeGreaterThan(0);
|
|
23
|
-
|
|
24
|
-
AVAILABLE_MLE_MODELS.forEach(model => {
|
|
25
|
-
expect(model).toHaveProperty("id");
|
|
26
|
-
expect(model).toHaveProperty("name");
|
|
27
|
-
expect(model).toHaveProperty("description");
|
|
28
|
-
expect(typeof model.id).toBe("string");
|
|
29
|
-
expect(typeof model.name).toBe("string");
|
|
30
|
-
expect(typeof model.description).toBe("string");
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach } from "bun:test";
|
|
2
|
-
import { FileResolver, getFileResolver } from "../utils/FileResolver";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
|
|
5
|
-
describe("FileResolver edge cases", () => {
|
|
6
|
-
let resolver: FileResolver;
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
resolver = new FileResolver(process.cwd());
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
describe("resolve edge cases", () => {
|
|
13
|
-
test("should handle message with no @ references", () => {
|
|
14
|
-
const message = "This is a plain message without any file references";
|
|
15
|
-
const result = resolver.resolve(message);
|
|
16
|
-
|
|
17
|
-
expect(result.references.length).toBe(0);
|
|
18
|
-
expect(result.contextBlock).toBe("");
|
|
19
|
-
expect(result.cleanMessage).toBe(message);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test("should handle non-existent file references", () => {
|
|
23
|
-
const message = "Check @non-existent-file-12345.txt";
|
|
24
|
-
const result = resolver.resolve(message);
|
|
25
|
-
|
|
26
|
-
expect(result.references.length).toBe(1);
|
|
27
|
-
expect(result.references[0].exists).toBe(false);
|
|
28
|
-
expect(result.references[0].error).toBeDefined();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test("should handle absolute paths", () => {
|
|
32
|
-
const absolutePath = path.resolve(process.cwd(), "package.json");
|
|
33
|
-
const message = `Check @${absolutePath}`;
|
|
34
|
-
const result = resolver.resolve(message);
|
|
35
|
-
|
|
36
|
-
expect(result.references.length).toBeGreaterThanOrEqual(1);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("should handle existing file and include content", () => {
|
|
40
|
-
const message = "Check @package.json for version";
|
|
41
|
-
const result = resolver.resolve(message);
|
|
42
|
-
|
|
43
|
-
if (result.references.length > 0 && result.references[0].exists) {
|
|
44
|
-
expect(result.references[0].content).toBeDefined();
|
|
45
|
-
expect(result.references[0].isDirectory).toBe(false);
|
|
46
|
-
expect(result.contextBlock.length).toBeGreaterThan(0);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test("should handle directory references", () => {
|
|
51
|
-
const message = "Check @src/ directory";
|
|
52
|
-
const result = resolver.resolve(message);
|
|
53
|
-
|
|
54
|
-
if (result.references.length > 0 && result.references[0].exists) {
|
|
55
|
-
expect(result.references[0].isDirectory).toBe(true);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe("getSuggestions edge cases", () => {
|
|
61
|
-
test("should return empty array for non-existent directory", () => {
|
|
62
|
-
const suggestions = resolver.getSuggestions("non-existent-dir-12345/");
|
|
63
|
-
expect(suggestions).toEqual([]);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("should handle empty partial with custom limit", () => {
|
|
67
|
-
const suggestions = resolver.getSuggestions("", 3);
|
|
68
|
-
expect(suggestions.length).toBeLessThanOrEqual(3);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test("should filter by prefix correctly", () => {
|
|
72
|
-
const suggestions = resolver.getSuggestions("pack");
|
|
73
|
-
const hasPackageJson = suggestions.some(s => s.includes("package"));
|
|
74
|
-
expect(hasPackageJson).toBe(true);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe("getFileResolver singleton", () => {
|
|
79
|
-
test("should return same instance when called multiple times", () => {
|
|
80
|
-
const resolver1 = getFileResolver();
|
|
81
|
-
const resolver2 = getFileResolver();
|
|
82
|
-
expect(resolver1).toBe(resolver2);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("should create new instance when basePath is provided", () => {
|
|
86
|
-
const resolver1 = getFileResolver();
|
|
87
|
-
const resolver2 = getFileResolver("/custom/path");
|
|
88
|
-
// Singleton is updated, so both point to the same updated instance
|
|
89
|
-
expect(resolver2).toBeDefined();
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach, afterEach, mock } from "bun:test";
|
|
2
|
-
import {
|
|
3
|
-
isEnabled,
|
|
4
|
-
hasChosenTelemetry,
|
|
5
|
-
setEnabled,
|
|
6
|
-
track,
|
|
7
|
-
trackCommand,
|
|
8
|
-
trackDatasetGenerate,
|
|
9
|
-
trackChatSessionStart,
|
|
10
|
-
trackChatSessionEnd,
|
|
11
|
-
trackJobCreate,
|
|
12
|
-
trackModelDownload,
|
|
13
|
-
} from "../telemetry";
|
|
14
|
-
|
|
15
|
-
describe("Telemetry", () => {
|
|
16
|
-
let originalEnv: string | undefined;
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
originalEnv = process.env.PIONEER_TELEMETRY;
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
if (originalEnv !== undefined) {
|
|
24
|
-
process.env.PIONEER_TELEMETRY = originalEnv;
|
|
25
|
-
} else {
|
|
26
|
-
delete process.env.PIONEER_TELEMETRY;
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe("isEnabled", () => {
|
|
31
|
-
test("should respect PIONEER_TELEMETRY=false env var", () => {
|
|
32
|
-
process.env.PIONEER_TELEMETRY = "false";
|
|
33
|
-
expect(isEnabled()).toBe(false);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test("should respect PIONEER_TELEMETRY=true env var", () => {
|
|
37
|
-
process.env.PIONEER_TELEMETRY = "true";
|
|
38
|
-
expect(isEnabled()).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test("should check config when env var not set", () => {
|
|
42
|
-
delete process.env.PIONEER_TELEMETRY;
|
|
43
|
-
const enabled = isEnabled();
|
|
44
|
-
expect(typeof enabled).toBe("boolean");
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
describe("hasChosenTelemetry", () => {
|
|
49
|
-
test("should return boolean", () => {
|
|
50
|
-
const hasChosen = hasChosenTelemetry();
|
|
51
|
-
expect(typeof hasChosen).toBe("boolean");
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
describe("setEnabled", () => {
|
|
56
|
-
test("should enable telemetry", () => {
|
|
57
|
-
setEnabled(true);
|
|
58
|
-
// If env var not set, should read from config
|
|
59
|
-
delete process.env.PIONEER_TELEMETRY;
|
|
60
|
-
expect(hasChosenTelemetry()).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("should disable telemetry", () => {
|
|
64
|
-
setEnabled(false);
|
|
65
|
-
delete process.env.PIONEER_TELEMETRY;
|
|
66
|
-
expect(hasChosenTelemetry()).toBe(true);
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe("track functions", () => {
|
|
71
|
-
test("track should not throw when telemetry disabled", () => {
|
|
72
|
-
process.env.PIONEER_TELEMETRY = "false";
|
|
73
|
-
expect(() => track("test_event", { prop: "value" })).not.toThrow();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("track should not throw when telemetry enabled", () => {
|
|
77
|
-
process.env.PIONEER_TELEMETRY = "true";
|
|
78
|
-
expect(() => track("test_event", { prop: "value" })).not.toThrow();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("trackCommand should accept command and subcommand", () => {
|
|
82
|
-
expect(() => trackCommand("datasets", "list")).not.toThrow();
|
|
83
|
-
expect(() => trackCommand("auth", undefined)).not.toThrow();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("trackDatasetGenerate should accept all params", () => {
|
|
87
|
-
expect(() => trackDatasetGenerate("ner", 100, true)).not.toThrow();
|
|
88
|
-
expect(() => trackDatasetGenerate("classification", 50, false)).not.toThrow();
|
|
89
|
-
expect(() => trackDatasetGenerate("custom", 25, true)).not.toThrow();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test("trackChatSessionStart should accept provider and model", () => {
|
|
93
|
-
expect(() => trackChatSessionStart("openai", "gpt-4")).not.toThrow();
|
|
94
|
-
expect(() => trackChatSessionStart("anthropic", "claude-3")).not.toThrow();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("trackChatSessionEnd should accept session metrics", () => {
|
|
98
|
-
expect(() => trackChatSessionEnd(60000, 10, 5)).not.toThrow();
|
|
99
|
-
expect(() => trackChatSessionEnd(0, 0, 0)).not.toThrow();
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("trackJobCreate should accept base model", () => {
|
|
103
|
-
expect(() => trackJobCreate("gliner_small")).not.toThrow();
|
|
104
|
-
expect(() => trackJobCreate("gliner_large")).not.toThrow();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("trackModelDownload should work without params", () => {
|
|
108
|
-
expect(() => trackModelDownload()).not.toThrow();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|