@northflare/runner 0.0.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.
- package/DEBUG_LOGGING.md +60 -0
- package/LICENSE +21 -0
- package/MIGRATION_PLAN.md +52 -0
- package/README.md +220 -0
- package/SDK_IMPLEMENTATION_GUIDE.md +1036 -0
- package/bin/northflare-runner +367 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-final.json +12 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +176 -0
- package/coverage/lib/index.html +116 -0
- package/coverage/lib/preload-script.js.html +964 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/src/collections/index.html +116 -0
- package/coverage/src/collections/runner-messages.ts.html +312 -0
- package/coverage/src/components/claude-manager.ts.html +1290 -0
- package/coverage/src/components/index.html +146 -0
- package/coverage/src/components/message-handler.ts.html +730 -0
- package/coverage/src/components/repository-manager.ts.html +841 -0
- package/coverage/src/index.html +131 -0
- package/coverage/src/index.ts.html +448 -0
- package/coverage/src/runner.ts.html +1239 -0
- package/coverage/src/utils/config.ts.html +780 -0
- package/coverage/src/utils/console.ts.html +121 -0
- package/coverage/src/utils/index.html +161 -0
- package/coverage/src/utils/logger.ts.html +475 -0
- package/coverage/src/utils/status-line.ts.html +445 -0
- package/dist/collections/runner-messages.d.ts +52 -0
- package/dist/collections/runner-messages.d.ts.map +1 -0
- package/dist/collections/runner-messages.js +161 -0
- package/dist/collections/runner-messages.js.map +1 -0
- package/dist/components/claude-manager.d.ts +39 -0
- package/dist/components/claude-manager.d.ts.map +1 -0
- package/dist/components/claude-manager.js +783 -0
- package/dist/components/claude-manager.js.map +1 -0
- package/dist/components/claude-sdk-manager.d.ts +47 -0
- package/dist/components/claude-sdk-manager.d.ts.map +1 -0
- package/dist/components/claude-sdk-manager.js +1088 -0
- package/dist/components/claude-sdk-manager.js.map +1 -0
- package/dist/components/enhanced-repository-manager.d.ts +134 -0
- package/dist/components/enhanced-repository-manager.d.ts.map +1 -0
- package/dist/components/enhanced-repository-manager.js +602 -0
- package/dist/components/enhanced-repository-manager.js.map +1 -0
- package/dist/components/message-handler-sse.d.ts +46 -0
- package/dist/components/message-handler-sse.d.ts.map +1 -0
- package/dist/components/message-handler-sse.js +734 -0
- package/dist/components/message-handler-sse.js.map +1 -0
- package/dist/components/message-handler.d.ts +35 -0
- package/dist/components/message-handler.d.ts.map +1 -0
- package/dist/components/message-handler.js +689 -0
- package/dist/components/message-handler.js.map +1 -0
- package/dist/components/repository-manager.d.ts +51 -0
- package/dist/components/repository-manager.d.ts.map +1 -0
- package/dist/components/repository-manager.js +295 -0
- package/dist/components/repository-manager.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -0
- package/dist/runner-sse.d.ts +57 -0
- package/dist/runner-sse.d.ts.map +1 -0
- package/dist/runner-sse.js +698 -0
- package/dist/runner-sse.js.map +1 -0
- package/dist/runner.d.ts +51 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +530 -0
- package/dist/runner.js.map +1 -0
- package/dist/services/RunnerAPIClient.d.ts +30 -0
- package/dist/services/RunnerAPIClient.d.ts.map +1 -0
- package/dist/services/RunnerAPIClient.js +112 -0
- package/dist/services/RunnerAPIClient.js.map +1 -0
- package/dist/services/SSEClient.d.ts +60 -0
- package/dist/services/SSEClient.d.ts.map +1 -0
- package/dist/services/SSEClient.js +204 -0
- package/dist/services/SSEClient.js.map +1 -0
- package/dist/types/claude.d.ts +45 -0
- package/dist/types/claude.d.ts.map +1 -0
- package/dist/types/claude.js +6 -0
- package/dist/types/claude.js.map +1 -0
- package/dist/types/index.d.ts +47 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/messages.d.ts +31 -0
- package/dist/types/messages.d.ts.map +1 -0
- package/dist/types/messages.js +6 -0
- package/dist/types/messages.js.map +1 -0
- package/dist/types/runner-interface.d.ts +24 -0
- package/dist/types/runner-interface.d.ts.map +1 -0
- package/dist/types/runner-interface.js +6 -0
- package/dist/types/runner-interface.js.map +1 -0
- package/dist/utils/StateManager.d.ts +52 -0
- package/dist/utils/StateManager.d.ts.map +1 -0
- package/dist/utils/StateManager.js +162 -0
- package/dist/utils/StateManager.js.map +1 -0
- package/dist/utils/config.d.ts +41 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +250 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/console.d.ts +11 -0
- package/dist/utils/console.d.ts.map +1 -0
- package/dist/utils/console.js +15 -0
- package/dist/utils/console.js.map +1 -0
- package/dist/utils/expand-env.d.ts +2 -0
- package/dist/utils/expand-env.d.ts.map +1 -0
- package/dist/utils/expand-env.js +20 -0
- package/dist/utils/expand-env.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +108 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/status-line.d.ts +37 -0
- package/dist/utils/status-line.d.ts.map +1 -0
- package/dist/utils/status-line.js +113 -0
- package/dist/utils/status-line.js.map +1 -0
- package/docs/claude-manager.md +91 -0
- package/exceptions.log +22 -0
- package/lib/preload-script.js +293 -0
- package/package.json +55 -0
- package/rejections.log +63 -0
- package/runner.log +488 -0
- package/src/components/claude-sdk-manager.ts +1354 -0
- package/src/components/enhanced-repository-manager.ts +823 -0
- package/src/components/message-handler-sse.ts +1011 -0
- package/src/components/repository-manager.ts +337 -0
- package/src/index.ts +166 -0
- package/src/runner-sse.ts +847 -0
- package/src/services/RunnerAPIClient.ts +135 -0
- package/src/services/SSEClient.ts +258 -0
- package/src/types/claude.ts +55 -0
- package/src/types/computer-name.d.ts +4 -0
- package/src/types/index.ts +63 -0
- package/src/types/messages.ts +39 -0
- package/src/types/runner-interface.ts +34 -0
- package/src/utils/StateManager.ts +187 -0
- package/src/utils/codex-sdk.js +448 -0
- package/src/utils/config.ts +315 -0
- package/src/utils/console.ts +13 -0
- package/src/utils/expand-env.ts +22 -0
- package/src/utils/logger.ts +131 -0
- package/src/utils/sdk-demo.js +34 -0
- package/src/utils/status-line.ts +121 -0
- package/test-debug.sh +26 -0
- package/tests/retry-strategies.test.ts +410 -0
- package/tests/sdk-integration.test.ts +329 -0
- package/tests/sdk-streaming.test.ts +1180 -0
- package/tests/setup.ts +5 -0
- package/tests/test-claude-manager.ts +120 -0
- package/tsconfig.json +36 -0
- package/vitest.config.ts +27 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI executable for Northflare Runner
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { program, Command } = require("commander");
|
|
8
|
+
const pkg = require("../package.json");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Helper function to fetch runner ID from orchestrator
|
|
12
|
+
*/
|
|
13
|
+
async function fetchRunnerId(orchestratorUrl, token) {
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(`${orchestratorUrl}/api/runner/id`, {
|
|
16
|
+
method: "GET",
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${token}`,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
24
|
+
throw new Error(`Failed to fetch runner ID: ${error.error || response.statusText}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const data = await response.json();
|
|
28
|
+
if (!data.runnerId) {
|
|
29
|
+
throw new Error("Server did not return runnerId");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return data.runnerId;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Failed to fetch runner ID: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Create the start command
|
|
39
|
+
const startCommand = new Command("start")
|
|
40
|
+
.description("start the runner")
|
|
41
|
+
.option("-c, --config <path>", "path to configuration file")
|
|
42
|
+
.option("-d, --debug", "enable debug logging")
|
|
43
|
+
.option("--data-dir <path>", "override data directory")
|
|
44
|
+
.option(
|
|
45
|
+
"--workspace-dir <path>",
|
|
46
|
+
"workspace directory for Git checkouts (default: uses env-paths data directory)"
|
|
47
|
+
)
|
|
48
|
+
.option("--token <token>", "authentication token")
|
|
49
|
+
.action(async (options, command) => {
|
|
50
|
+
// Set environment variables from CLI options
|
|
51
|
+
if (options.debug) {
|
|
52
|
+
process.env.DEBUG = "true";
|
|
53
|
+
}
|
|
54
|
+
if (options.dataDir) {
|
|
55
|
+
process.env.NORTHFLARE_DATA_DIR = options.dataDir;
|
|
56
|
+
}
|
|
57
|
+
if (options.workspaceDir) {
|
|
58
|
+
process.env.NORTHFLARE_WORKSPACE_DIR = options.workspaceDir;
|
|
59
|
+
}
|
|
60
|
+
const token = options.token || command.parent?.opts().token;
|
|
61
|
+
if (token) {
|
|
62
|
+
process.env.NORTHFLARE_RUNNER_TOKEN = token;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Load the main module with config path if provided
|
|
66
|
+
// Clear argv[2] since it contains 'start' command
|
|
67
|
+
process.argv.splice(2);
|
|
68
|
+
const configPath = options.config || command.parent?.opts().config;
|
|
69
|
+
if (configPath) {
|
|
70
|
+
process.argv[2] = configPath;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Manually call the main function since require.main won't match
|
|
74
|
+
const { main } = require("../dist");
|
|
75
|
+
await main().catch((error) => {
|
|
76
|
+
console.error("Fatal error:", error.message);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Create the validate command
|
|
82
|
+
const validateCommand = new Command("validate")
|
|
83
|
+
.description("validate configuration without starting")
|
|
84
|
+
.option("-c, --config <path>", "path to configuration file")
|
|
85
|
+
.option("--token <token>", "authentication token")
|
|
86
|
+
.option("--data-dir <path>", "override data directory")
|
|
87
|
+
.option(
|
|
88
|
+
"--workspace-dir <path>",
|
|
89
|
+
"workspace directory for Git checkouts (default: uses env-paths data directory)"
|
|
90
|
+
)
|
|
91
|
+
.action(async (options, command) => {
|
|
92
|
+
try {
|
|
93
|
+
// Set environment variables from CLI options before validation
|
|
94
|
+
const token = options.token || command.parent?.opts().token;
|
|
95
|
+
if (token) {
|
|
96
|
+
process.env.NORTHFLARE_RUNNER_TOKEN = token;
|
|
97
|
+
}
|
|
98
|
+
if (options.dataDir) {
|
|
99
|
+
process.env.NORTHFLARE_DATA_DIR = options.dataDir;
|
|
100
|
+
}
|
|
101
|
+
if (options.workspaceDir) {
|
|
102
|
+
process.env.NORTHFLARE_WORKSPACE_DIR = options.workspaceDir;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const { ConfigManager } = require("../dist/utils/config.js");
|
|
106
|
+
const configPath = options.config || command.parent?.opts().config;
|
|
107
|
+
const config = await ConfigManager.loadConfig(configPath);
|
|
108
|
+
console.log("Configuration is valid");
|
|
109
|
+
console.log("Runner ID:", config.runnerId);
|
|
110
|
+
console.log("ElectricSQL URL:", config.electricUrl);
|
|
111
|
+
console.log("Orchestrator URL:", config.orchestratorUrl);
|
|
112
|
+
console.log("Workspace Directory:", process.env.NORTHFLARE_WORKSPACE_DIR);
|
|
113
|
+
process.exit(0);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error("Configuration validation failed:", error.message);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Create the list-repos command
|
|
121
|
+
const listReposCommand = new Command("list-repos")
|
|
122
|
+
.description("list current runner repositories")
|
|
123
|
+
.option(
|
|
124
|
+
"-c, --config <path>",
|
|
125
|
+
"path to configuration file (defaults to ~/.config/northflare-runner/config.json)"
|
|
126
|
+
)
|
|
127
|
+
.option("--token <token>", "authentication token")
|
|
128
|
+
.action(async (options, command) => {
|
|
129
|
+
try {
|
|
130
|
+
const fs = require("fs").promises;
|
|
131
|
+
const path = require("path");
|
|
132
|
+
const envPaths = require("env-paths").default || require("env-paths");
|
|
133
|
+
|
|
134
|
+
// Get token from command options, parent options, or environment
|
|
135
|
+
const token = options.token || command.parent?.opts().token || process.env.NORTHFLARE_RUNNER_TOKEN;
|
|
136
|
+
if (!token) {
|
|
137
|
+
console.error("Error: NORTHFLARE_RUNNER_TOKEN is required. Provide it via --token or environment variable.");
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Get default config path
|
|
142
|
+
const paths = envPaths("northflare-runner", { suffix: "" });
|
|
143
|
+
|
|
144
|
+
// Determine config path from command options, parent options, or default
|
|
145
|
+
const configOption = options.config || command.parent?.opts().config;
|
|
146
|
+
let configPath;
|
|
147
|
+
if (configOption) {
|
|
148
|
+
configPath = path.resolve(configOption);
|
|
149
|
+
} else {
|
|
150
|
+
configPath = path.join(paths.config, "config.json");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Load config file
|
|
154
|
+
let config = {};
|
|
155
|
+
try {
|
|
156
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
157
|
+
config = JSON.parse(content);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (error.code === "ENOENT") {
|
|
160
|
+
if (options.config) {
|
|
161
|
+
console.error(`Configuration file not found: ${configPath}`);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
} else {
|
|
164
|
+
console.log(
|
|
165
|
+
`No configuration file found at default location: ${configPath}`
|
|
166
|
+
);
|
|
167
|
+
console.log(
|
|
168
|
+
"Use -c/--config to specify a config file or add-repo to create one."
|
|
169
|
+
);
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Log config file location in debug mode
|
|
177
|
+
if (process.env.DEBUG) {
|
|
178
|
+
console.log(`Config file location: ${configPath}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Get orchestrator URL from config or environment
|
|
182
|
+
const orchestratorUrl = config.orchestratorUrl || process.env.NORTHFLARE_ORCHESTRATOR_URL || "https://api.northflare.ai";
|
|
183
|
+
|
|
184
|
+
// Fetch runner ID
|
|
185
|
+
const runnerId = await fetchRunnerId(orchestratorUrl, token);
|
|
186
|
+
console.log(`Runner ID: ${runnerId}\n`);
|
|
187
|
+
|
|
188
|
+
// Ensure runnerRepos is properly structured
|
|
189
|
+
if (!config.runnerRepos || typeof config.runnerRepos !== "object") {
|
|
190
|
+
config.runnerRepos = {};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Get repos for this runner
|
|
194
|
+
const repos = config.runnerRepos[runnerId] || [];
|
|
195
|
+
|
|
196
|
+
// List runner repos
|
|
197
|
+
if (repos.length > 0) {
|
|
198
|
+
console.log(`Found ${repos.length} runner repositories:`);
|
|
199
|
+
repos.forEach((repo, index) => {
|
|
200
|
+
console.log(
|
|
201
|
+
`${index + 1}. ${repo.name} (${repo.path})${
|
|
202
|
+
repo.uuid ? ` [UUID: ${repo.uuid}]` : ""
|
|
203
|
+
}`
|
|
204
|
+
);
|
|
205
|
+
});
|
|
206
|
+
} else {
|
|
207
|
+
console.log("No runner repositories configured for this runner.");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
process.exit(0);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error("Error listing repositories:", error.message);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Create the add-repo command
|
|
218
|
+
const addRepoCommand = new Command("add-repo")
|
|
219
|
+
.description("add a repository to the configuration")
|
|
220
|
+
.argument("<path>", "path to the repository")
|
|
221
|
+
.option(
|
|
222
|
+
"-c, --config <path>",
|
|
223
|
+
"path to configuration file (defaults to ~/.config/northflare-runner/config.json)"
|
|
224
|
+
)
|
|
225
|
+
.option("-n, --name <name>", "repository name (defaults to folder name)")
|
|
226
|
+
.option("--token <token>", "authentication token")
|
|
227
|
+
.action(async (repoPath, options, command) => {
|
|
228
|
+
try {
|
|
229
|
+
const fs = require("fs").promises;
|
|
230
|
+
const path = require("path");
|
|
231
|
+
const envPaths = require("env-paths").default || require("env-paths");
|
|
232
|
+
const crypto = require("crypto");
|
|
233
|
+
|
|
234
|
+
// Get token from command options, parent options, or environment
|
|
235
|
+
const token = options.token || command.parent?.opts().token || process.env.NORTHFLARE_RUNNER_TOKEN;
|
|
236
|
+
if (!token) {
|
|
237
|
+
console.error("Error: NORTHFLARE_RUNNER_TOKEN is required. Provide it via --token or environment variable.");
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Get default config path
|
|
242
|
+
const paths = envPaths("northflare-runner", { suffix: "" });
|
|
243
|
+
|
|
244
|
+
// Determine config path from command options, parent options, or default
|
|
245
|
+
const configOption = options.config || command.parent?.opts().config;
|
|
246
|
+
let configPath;
|
|
247
|
+
if (configOption) {
|
|
248
|
+
configPath = path.resolve(configOption);
|
|
249
|
+
} else {
|
|
250
|
+
configPath = path.join(paths.config, "config.json");
|
|
251
|
+
// Ensure config directory exists
|
|
252
|
+
await fs.mkdir(paths.config, { recursive: true });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Load existing config
|
|
256
|
+
let config = {};
|
|
257
|
+
try {
|
|
258
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
259
|
+
config = JSON.parse(content);
|
|
260
|
+
} catch (error) {
|
|
261
|
+
if (error.code === "ENOENT") {
|
|
262
|
+
console.log(
|
|
263
|
+
`Configuration file not found: ${configPath}. Creating new config file.`
|
|
264
|
+
);
|
|
265
|
+
config = {};
|
|
266
|
+
} else {
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Log config file location in debug mode
|
|
272
|
+
if (process.env.DEBUG) {
|
|
273
|
+
console.log(`Config file location: ${configPath}`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Get orchestrator URL from config or environment
|
|
277
|
+
const orchestratorUrl = config.orchestratorUrl || process.env.NORTHFLARE_ORCHESTRATOR_URL || "https://api.northflare.ai";
|
|
278
|
+
|
|
279
|
+
// Fetch runner ID
|
|
280
|
+
const runnerId = await fetchRunnerId(orchestratorUrl, token);
|
|
281
|
+
console.log(`Runner ID: ${runnerId}`);
|
|
282
|
+
|
|
283
|
+
// Ensure runnerRepos is properly structured
|
|
284
|
+
if (!config.runnerRepos || typeof config.runnerRepos !== "object" || Array.isArray(config.runnerRepos)) {
|
|
285
|
+
config.runnerRepos = {};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Initialize repos array for this runner if not present
|
|
289
|
+
if (!config.runnerRepos[runnerId] || !Array.isArray(config.runnerRepos[runnerId])) {
|
|
290
|
+
config.runnerRepos[runnerId] = [];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Resolve the repository path
|
|
294
|
+
const absoluteRepoPath = path.resolve(repoPath);
|
|
295
|
+
|
|
296
|
+
// Check if path exists
|
|
297
|
+
try {
|
|
298
|
+
const stats = await fs.stat(absoluteRepoPath);
|
|
299
|
+
if (!stats.isDirectory()) {
|
|
300
|
+
console.error(`Error: ${absoluteRepoPath} is not a directory`);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error(
|
|
305
|
+
`Error: Repository path does not exist: ${absoluteRepoPath}`
|
|
306
|
+
);
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Check for duplicates
|
|
311
|
+
const duplicate = config.runnerRepos[runnerId].find(
|
|
312
|
+
(repo) => repo.path === absoluteRepoPath
|
|
313
|
+
);
|
|
314
|
+
if (duplicate) {
|
|
315
|
+
console.error(
|
|
316
|
+
`Error: Repository already exists in configuration: ${duplicate.name} (${duplicate.path})`
|
|
317
|
+
);
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Determine repository name
|
|
322
|
+
const repoName = options.name || path.basename(absoluteRepoPath);
|
|
323
|
+
|
|
324
|
+
// Generate UUID for the repository
|
|
325
|
+
const repoUuid = crypto.randomUUID();
|
|
326
|
+
|
|
327
|
+
// Add new repository
|
|
328
|
+
const newRepo = {
|
|
329
|
+
uuid: repoUuid,
|
|
330
|
+
name: repoName,
|
|
331
|
+
path: absoluteRepoPath,
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
config.runnerRepos[runnerId].push(newRepo);
|
|
335
|
+
|
|
336
|
+
// Save updated config
|
|
337
|
+
const { ConfigManager } = require("../dist/utils/config.js");
|
|
338
|
+
await ConfigManager.saveConfigFile(configPath, config);
|
|
339
|
+
|
|
340
|
+
console.log(
|
|
341
|
+
`Successfully added repository: ${repoName} (${absoluteRepoPath})`
|
|
342
|
+
);
|
|
343
|
+
console.log(`UUID: ${repoUuid}`);
|
|
344
|
+
console.log(`Total repositories for this runner: ${config.runnerRepos[runnerId].length}`);
|
|
345
|
+
|
|
346
|
+
process.exit(0);
|
|
347
|
+
} catch (error) {
|
|
348
|
+
console.error("Error adding repository:", error.message);
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// Set up the main program
|
|
354
|
+
program
|
|
355
|
+
.name("northflare-runner")
|
|
356
|
+
.description("Distributed conversation runner for Northflare")
|
|
357
|
+
.version(pkg.version)
|
|
358
|
+
.option("--token <token>", "authentication token (can be used with any command)")
|
|
359
|
+
.option("-c, --config <path>", "path to configuration file (can be used with any command)")
|
|
360
|
+
.enablePositionalOptions() // Allow options to be placed before or after positional arguments
|
|
361
|
+
.passThroughOptions() // Pass options through to subcommands
|
|
362
|
+
.addCommand(startCommand, { isDefault: true })
|
|
363
|
+
.addCommand(validateCommand)
|
|
364
|
+
.addCommand(listReposCommand)
|
|
365
|
+
.addCommand(addRepoCommand);
|
|
366
|
+
|
|
367
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
body, html {
|
|
2
|
+
margin:0; padding: 0;
|
|
3
|
+
height: 100%;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
font-family: Helvetica Neue, Helvetica, Arial;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
color:#333;
|
|
9
|
+
}
|
|
10
|
+
.small { font-size: 12px; }
|
|
11
|
+
*, *:after, *:before {
|
|
12
|
+
-webkit-box-sizing:border-box;
|
|
13
|
+
-moz-box-sizing:border-box;
|
|
14
|
+
box-sizing:border-box;
|
|
15
|
+
}
|
|
16
|
+
h1 { font-size: 20px; margin: 0;}
|
|
17
|
+
h2 { font-size: 14px; }
|
|
18
|
+
pre {
|
|
19
|
+
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
-moz-tab-size: 2;
|
|
23
|
+
-o-tab-size: 2;
|
|
24
|
+
tab-size: 2;
|
|
25
|
+
}
|
|
26
|
+
a { color:#0074D9; text-decoration:none; }
|
|
27
|
+
a:hover { text-decoration:underline; }
|
|
28
|
+
.strong { font-weight: bold; }
|
|
29
|
+
.space-top1 { padding: 10px 0 0 0; }
|
|
30
|
+
.pad2y { padding: 20px 0; }
|
|
31
|
+
.pad1y { padding: 10px 0; }
|
|
32
|
+
.pad2x { padding: 0 20px; }
|
|
33
|
+
.pad2 { padding: 20px; }
|
|
34
|
+
.pad1 { padding: 10px; }
|
|
35
|
+
.space-left2 { padding-left:55px; }
|
|
36
|
+
.space-right2 { padding-right:20px; }
|
|
37
|
+
.center { text-align:center; }
|
|
38
|
+
.clearfix { display:block; }
|
|
39
|
+
.clearfix:after {
|
|
40
|
+
content:'';
|
|
41
|
+
display:block;
|
|
42
|
+
height:0;
|
|
43
|
+
clear:both;
|
|
44
|
+
visibility:hidden;
|
|
45
|
+
}
|
|
46
|
+
.fl { float: left; }
|
|
47
|
+
@media only screen and (max-width:640px) {
|
|
48
|
+
.col3 { width:100%; max-width:100%; }
|
|
49
|
+
.hide-mobile { display:none!important; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.quiet {
|
|
53
|
+
color: #7f7f7f;
|
|
54
|
+
color: rgba(0,0,0,0.5);
|
|
55
|
+
}
|
|
56
|
+
.quiet a { opacity: 0.7; }
|
|
57
|
+
|
|
58
|
+
.fraction {
|
|
59
|
+
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
60
|
+
font-size: 10px;
|
|
61
|
+
color: #555;
|
|
62
|
+
background: #E8E8E8;
|
|
63
|
+
padding: 4px 5px;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
vertical-align: middle;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
div.path a:link, div.path a:visited { color: #333; }
|
|
69
|
+
table.coverage {
|
|
70
|
+
border-collapse: collapse;
|
|
71
|
+
margin: 10px 0 0 0;
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
table.coverage td {
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
vertical-align: top;
|
|
79
|
+
}
|
|
80
|
+
table.coverage td.line-count {
|
|
81
|
+
text-align: right;
|
|
82
|
+
padding: 0 5px 0 20px;
|
|
83
|
+
}
|
|
84
|
+
table.coverage td.line-coverage {
|
|
85
|
+
text-align: right;
|
|
86
|
+
padding-right: 10px;
|
|
87
|
+
min-width:20px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
table.coverage td span.cline-any {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
padding: 0 5px;
|
|
93
|
+
width: 100%;
|
|
94
|
+
}
|
|
95
|
+
.missing-if-branch {
|
|
96
|
+
display: inline-block;
|
|
97
|
+
margin-right: 5px;
|
|
98
|
+
border-radius: 3px;
|
|
99
|
+
position: relative;
|
|
100
|
+
padding: 0 4px;
|
|
101
|
+
background: #333;
|
|
102
|
+
color: yellow;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.skip-if-branch {
|
|
106
|
+
display: none;
|
|
107
|
+
margin-right: 10px;
|
|
108
|
+
position: relative;
|
|
109
|
+
padding: 0 4px;
|
|
110
|
+
background: #ccc;
|
|
111
|
+
color: white;
|
|
112
|
+
}
|
|
113
|
+
.missing-if-branch .typ, .skip-if-branch .typ {
|
|
114
|
+
color: inherit !important;
|
|
115
|
+
}
|
|
116
|
+
.coverage-summary {
|
|
117
|
+
border-collapse: collapse;
|
|
118
|
+
width: 100%;
|
|
119
|
+
}
|
|
120
|
+
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
|
121
|
+
.keyline-all { border: 1px solid #ddd; }
|
|
122
|
+
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
|
123
|
+
.coverage-summary tbody { border: 1px solid #bbb; }
|
|
124
|
+
.coverage-summary td { border-right: 1px solid #bbb; }
|
|
125
|
+
.coverage-summary td:last-child { border-right: none; }
|
|
126
|
+
.coverage-summary th {
|
|
127
|
+
text-align: left;
|
|
128
|
+
font-weight: normal;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
}
|
|
131
|
+
.coverage-summary th.file { border-right: none !important; }
|
|
132
|
+
.coverage-summary th.pct { }
|
|
133
|
+
.coverage-summary th.pic,
|
|
134
|
+
.coverage-summary th.abs,
|
|
135
|
+
.coverage-summary td.pct,
|
|
136
|
+
.coverage-summary td.abs { text-align: right; }
|
|
137
|
+
.coverage-summary td.file { white-space: nowrap; }
|
|
138
|
+
.coverage-summary td.pic { min-width: 120px !important; }
|
|
139
|
+
.coverage-summary tfoot td { }
|
|
140
|
+
|
|
141
|
+
.coverage-summary .sorter {
|
|
142
|
+
height: 10px;
|
|
143
|
+
width: 7px;
|
|
144
|
+
display: inline-block;
|
|
145
|
+
margin-left: 0.5em;
|
|
146
|
+
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
147
|
+
}
|
|
148
|
+
.coverage-summary .sorted .sorter {
|
|
149
|
+
background-position: 0 -20px;
|
|
150
|
+
}
|
|
151
|
+
.coverage-summary .sorted-desc .sorter {
|
|
152
|
+
background-position: 0 -10px;
|
|
153
|
+
}
|
|
154
|
+
.status-line { height: 10px; }
|
|
155
|
+
/* yellow */
|
|
156
|
+
.cbranch-no { background: yellow !important; color: #111; }
|
|
157
|
+
/* dark red */
|
|
158
|
+
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
|
159
|
+
.low .chart { border:1px solid #C21F39 }
|
|
160
|
+
.highlighted,
|
|
161
|
+
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
|
|
162
|
+
background: #C21F39 !important;
|
|
163
|
+
}
|
|
164
|
+
/* medium red */
|
|
165
|
+
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
|
166
|
+
/* light red */
|
|
167
|
+
.low, .cline-no { background:#FCE1E5 }
|
|
168
|
+
/* light green */
|
|
169
|
+
.high, .cline-yes { background:rgb(230,245,208) }
|
|
170
|
+
/* medium green */
|
|
171
|
+
.cstat-yes { background:rgb(161,215,106) }
|
|
172
|
+
/* dark green */
|
|
173
|
+
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
|
174
|
+
.high .chart { border:1px solid rgb(77,146,33) }
|
|
175
|
+
/* dark yellow (gold) */
|
|
176
|
+
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
|
|
177
|
+
.medium .chart { border:1px solid #f9cd0b; }
|
|
178
|
+
/* light yellow */
|
|
179
|
+
.medium { background: #fff4c2; }
|
|
180
|
+
|
|
181
|
+
.cstat-skip { background: #ddd; color: #111; }
|
|
182
|
+
.fstat-skip { background: #ddd; color: #111 !important; }
|
|
183
|
+
.cbranch-skip { background: #ddd !important; color: #111; }
|
|
184
|
+
|
|
185
|
+
span.cline-neutral { background: #eaeaea; }
|
|
186
|
+
|
|
187
|
+
.coverage-summary td.empty {
|
|
188
|
+
opacity: .5;
|
|
189
|
+
padding-top: 4px;
|
|
190
|
+
padding-bottom: 4px;
|
|
191
|
+
line-height: 1;
|
|
192
|
+
color: #888;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.cover-fill, .cover-empty {
|
|
196
|
+
display:inline-block;
|
|
197
|
+
height: 12px;
|
|
198
|
+
}
|
|
199
|
+
.chart {
|
|
200
|
+
line-height: 0;
|
|
201
|
+
}
|
|
202
|
+
.cover-empty {
|
|
203
|
+
background: white;
|
|
204
|
+
}
|
|
205
|
+
.cover-full {
|
|
206
|
+
border-right: none !important;
|
|
207
|
+
}
|
|
208
|
+
pre.prettyprint {
|
|
209
|
+
border: none !important;
|
|
210
|
+
padding: 0 !important;
|
|
211
|
+
margin: 0 !important;
|
|
212
|
+
}
|
|
213
|
+
.com { color: #999 !important; }
|
|
214
|
+
.ignore-none { color: #999; font-weight: normal; }
|
|
215
|
+
|
|
216
|
+
.wrapper {
|
|
217
|
+
min-height: 100%;
|
|
218
|
+
height: auto !important;
|
|
219
|
+
height: 100%;
|
|
220
|
+
margin: 0 auto -48px;
|
|
221
|
+
}
|
|
222
|
+
.footer, .push {
|
|
223
|
+
height: 48px;
|
|
224
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
var jumpToCode = (function init() {
|
|
3
|
+
// Classes of code we would like to highlight in the file view
|
|
4
|
+
var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
|
|
5
|
+
|
|
6
|
+
// Elements to highlight in the file listing view
|
|
7
|
+
var fileListingElements = ['td.pct.low'];
|
|
8
|
+
|
|
9
|
+
// We don't want to select elements that are direct descendants of another match
|
|
10
|
+
var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
|
|
11
|
+
|
|
12
|
+
// Selecter that finds elements on the page to which we can jump
|
|
13
|
+
var selector =
|
|
14
|
+
fileListingElements.join(', ') +
|
|
15
|
+
', ' +
|
|
16
|
+
notSelector +
|
|
17
|
+
missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
|
|
18
|
+
|
|
19
|
+
// The NodeList of matching elements
|
|
20
|
+
var missingCoverageElements = document.querySelectorAll(selector);
|
|
21
|
+
|
|
22
|
+
var currentIndex;
|
|
23
|
+
|
|
24
|
+
function toggleClass(index) {
|
|
25
|
+
missingCoverageElements
|
|
26
|
+
.item(currentIndex)
|
|
27
|
+
.classList.remove('highlighted');
|
|
28
|
+
missingCoverageElements.item(index).classList.add('highlighted');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function makeCurrent(index) {
|
|
32
|
+
toggleClass(index);
|
|
33
|
+
currentIndex = index;
|
|
34
|
+
missingCoverageElements.item(index).scrollIntoView({
|
|
35
|
+
behavior: 'smooth',
|
|
36
|
+
block: 'center',
|
|
37
|
+
inline: 'center'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function goToPrevious() {
|
|
42
|
+
var nextIndex = 0;
|
|
43
|
+
if (typeof currentIndex !== 'number' || currentIndex === 0) {
|
|
44
|
+
nextIndex = missingCoverageElements.length - 1;
|
|
45
|
+
} else if (missingCoverageElements.length > 1) {
|
|
46
|
+
nextIndex = currentIndex - 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
makeCurrent(nextIndex);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function goToNext() {
|
|
53
|
+
var nextIndex = 0;
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
typeof currentIndex === 'number' &&
|
|
57
|
+
currentIndex < missingCoverageElements.length - 1
|
|
58
|
+
) {
|
|
59
|
+
nextIndex = currentIndex + 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
makeCurrent(nextIndex);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return function jump(event) {
|
|
66
|
+
if (
|
|
67
|
+
document.getElementById('fileSearch') === document.activeElement &&
|
|
68
|
+
document.activeElement != null
|
|
69
|
+
) {
|
|
70
|
+
// if we're currently focused on the search input, we don't want to navigate
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
switch (event.which) {
|
|
75
|
+
case 78: // n
|
|
76
|
+
case 74: // j
|
|
77
|
+
goToNext();
|
|
78
|
+
break;
|
|
79
|
+
case 66: // b
|
|
80
|
+
case 75: // k
|
|
81
|
+
case 80: // p
|
|
82
|
+
goToPrevious();
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
})();
|
|
87
|
+
window.addEventListener('keydown', jumpToCode);
|