@cloud-cli/on 1.58.0 → 1.59.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.
- package/dist/api-key-repository.d.ts +2 -2
- package/dist/api-key-repository.d.ts.map +1 -1
- package/dist/on.js +204 -98
- package/dist/queue.d.ts +8 -0
- package/dist/queue.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/settings-ui.d.ts +1 -1
- package/dist/settings-ui.d.ts.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/worker.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const API_KEY_SCOPES: readonly ["workflows:read", "workflows:write", "logs:read", "artifacts:read", "runs:control", "runs:dispatch"];
|
|
1
|
+
export declare const API_KEY_SCOPES: readonly ["workflows:read", "workflows:write", "logs:read", "artifacts:read", "runs:control", "runs:dispatch", "workers:read"];
|
|
2
2
|
export type ApiKeyScope = (typeof API_KEY_SCOPES)[number];
|
|
3
3
|
export declare class ApiKeyRepository {
|
|
4
4
|
init(): Promise<void>;
|
|
@@ -6,7 +6,7 @@ export declare class ApiKeyRepository {
|
|
|
6
6
|
issue(name: string, scopes: string[]): Promise<{
|
|
7
7
|
id: `${string}-${string}-${string}-${string}-${string}`;
|
|
8
8
|
name: string;
|
|
9
|
-
scopes: ("workflows:read" | "workflows:write" | "logs:read" | "artifacts:read" | "runs:control" | "runs:dispatch")[];
|
|
9
|
+
scopes: ("workflows:read" | "workflows:write" | "logs:read" | "artifacts:read" | "runs:control" | "runs:dispatch" | "workers:read")[];
|
|
10
10
|
token: string;
|
|
11
11
|
}>;
|
|
12
12
|
scopesForToken(token: string): Promise<string[] | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-key-repository.d.ts","sourceRoot":"","sources":["../src/api-key-repository.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"api-key-repository.d.ts","sourceRoot":"","sources":["../src/api-key-repository.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,cAAc,gIAAiI,CAAC;AAC7J,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,qBAAa,gBAAgB;IACrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAYrB,IAAI;IAKJ,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;;;;;;IAUpC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IAQvD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAI3C"}
|
package/dist/on.js
CHANGED
|
@@ -280,7 +280,7 @@ var ye = class extends l {
|
|
|
280
280
|
return await C.run("UPDATE jobs SET status = 'pending', worker_id = NULL WHERE status = 'running' AND started_at < datetime('now', '-1 hour');");
|
|
281
281
|
}
|
|
282
282
|
async createTables() {
|
|
283
|
-
await C.exec("\n CREATE TABLE IF NOT EXISTS jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parentId INTEGER,\n workflow_id TEXT NOT NULL,\n workflow_revision INTEGER NOT NULL,\n required_tags TEXT NOT NULL DEFAULT '[]',\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n concurrency_key TEXT,\n worker_id TEXT,\n report TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n started_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n finished_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE TABLE IF NOT EXISTS step_logs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n job_id INTEGER NOT NULL,\n step_id TEXT NOT NULL,\n log_content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY(job_id) REFERENCES jobs(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_step_logs_job ON step_logs(job_id);\n\n DELETE FROM step_logs\n WHERE id NOT IN (\n SELECT MAX(id) FROM step_logs GROUP BY job_id, step_id\n );\n CREATE UNIQUE INDEX IF NOT EXISTS idx_step_logs_job_step ON step_logs(job_id, step_id);\n\n CREATE TABLE IF NOT EXISTS stored_files (\n kind TEXT NOT NULL,\n owner_key TEXT NOT NULL,\n file_path TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (kind, owner_key, file_path)\n );\n CREATE INDEX IF NOT EXISTS idx_stored_files_owner ON stored_files(kind, owner_key);\n ");
|
|
283
|
+
await C.exec("\n CREATE TABLE IF NOT EXISTS jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parentId INTEGER,\n workflow_id TEXT NOT NULL,\n workflow_revision INTEGER NOT NULL,\n required_tags TEXT NOT NULL DEFAULT '[]',\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n concurrency_key TEXT,\n worker_id TEXT,\n report TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n started_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n finished_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE TABLE IF NOT EXISTS step_logs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n job_id INTEGER NOT NULL,\n step_id TEXT NOT NULL,\n log_content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY(job_id) REFERENCES jobs(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_step_logs_job ON step_logs(job_id);\n\n DELETE FROM step_logs\n WHERE id NOT IN (\n SELECT MAX(id) FROM step_logs GROUP BY job_id, step_id\n );\n CREATE UNIQUE INDEX IF NOT EXISTS idx_step_logs_job_step ON step_logs(job_id, step_id);\n\n CREATE TABLE IF NOT EXISTS stored_files (\n kind TEXT NOT NULL,\n owner_key TEXT NOT NULL,\n file_path TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (kind, owner_key, file_path)\n );\n CREATE INDEX IF NOT EXISTS idx_stored_files_owner ON stored_files(kind, owner_key);\n\n CREATE TABLE IF NOT EXISTS worker_presence (\n worker_id TEXT PRIMARY KEY,\n version TEXT NOT NULL,\n tags TEXT NOT NULL DEFAULT '[]',\n concurrency INTEGER NOT NULL DEFAULT 0,\n active_jobs INTEGER NOT NULL DEFAULT 0,\n last_seen DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n ");
|
|
284
284
|
}
|
|
285
285
|
async getJob(e) {
|
|
286
286
|
return C.get("SELECT * FROM jobs WHERE id = ?", [e]);
|
|
@@ -326,6 +326,26 @@ var ye = class extends l {
|
|
|
326
326
|
async getStoredFiles(e, t) {
|
|
327
327
|
return this.fileStorage.enabled ? this.fileStorage.load(`${e}/${t}`) : C.all("SELECT file_path AS path, content FROM stored_files WHERE kind = ? AND owner_key = ?", [e, t]);
|
|
328
328
|
}
|
|
329
|
+
async updateWorkerPresence(e) {
|
|
330
|
+
await C.run("INSERT INTO worker_presence (worker_id, version, tags, concurrency, active_jobs, last_seen)\n VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)\n ON CONFLICT(worker_id) DO UPDATE SET version = excluded.version, tags = excluded.tags,\n concurrency = excluded.concurrency, active_jobs = excluded.active_jobs, last_seen = CURRENT_TIMESTAMP", [
|
|
331
|
+
e.id,
|
|
332
|
+
e.version,
|
|
333
|
+
JSON.stringify(e.tags),
|
|
334
|
+
e.concurrency,
|
|
335
|
+
e.activeJobs
|
|
336
|
+
]);
|
|
337
|
+
}
|
|
338
|
+
async listWorkerPresence() {
|
|
339
|
+
return (await C.all("SELECT worker_id, version, tags, concurrency, active_jobs, last_seen FROM worker_presence ORDER BY worker_id")).map((e) => ({
|
|
340
|
+
workerId: e.worker_id,
|
|
341
|
+
version: e.version,
|
|
342
|
+
tags: JSON.parse(e.tags || "[]"),
|
|
343
|
+
concurrency: e.concurrency,
|
|
344
|
+
activeJobs: e.active_jobs,
|
|
345
|
+
lastSeen: e.last_seen,
|
|
346
|
+
online: Date.now() - Date.parse(`${e.last_seen}Z`) < 45e3
|
|
347
|
+
}));
|
|
348
|
+
}
|
|
329
349
|
async saveAiRequest(e, t, n) {
|
|
330
350
|
await C.run("INSERT INTO ai_requests (job_id, workflow_url, request_json) VALUES (?, ?, ?)", [
|
|
331
351
|
e,
|
|
@@ -6340,7 +6360,8 @@ var oa = {
|
|
|
6340
6360
|
"logs:read",
|
|
6341
6361
|
"artifacts:read",
|
|
6342
6362
|
"runs:control",
|
|
6343
|
-
"runs:dispatch"
|
|
6363
|
+
"runs:dispatch",
|
|
6364
|
+
"workers:read"
|
|
6344
6365
|
], ca = class {
|
|
6345
6366
|
async init() {
|
|
6346
6367
|
await C.exec("CREATE TABLE IF NOT EXISTS api_keys (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n key_hash TEXT NOT NULL UNIQUE,\n scopes TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_used_at DATETIME,\n revoked_at DATETIME\n )");
|
|
@@ -6375,7 +6396,7 @@ var oa = {
|
|
|
6375
6396
|
let t = await C.run("UPDATE api_keys SET revoked_at = CURRENT_TIMESTAMP WHERE id = ? AND revoked_at IS NULL", [e]);
|
|
6376
6397
|
return Number(t?.changes || 0) > 0;
|
|
6377
6398
|
}
|
|
6378
|
-
}, la = "<!doctype html>\n<html lang=\"en\" class=\"dark\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Runner settings</title>\n <script type=\"importmap\">\n { \"imports\": { \"@li3/\": \"https://cdn.li3.dev/@li3/\" } }\n <\/script>\n <link rel=\"component\" href=\"https://sodium.static.apphor.de/lucide-icon.html\" />\n <link rel=\"component\" href=\"/app-header.html\" />\n </head>\n <body data-page=\"__SETTINGS_PAGE__\" class=\"min-h-screen bg-gray-950 p-4 font-sans text-gray-100 md:p-6\">\n <template app>\n <main class=\"mx-auto max-w-6xl space-y-5 py-6\">\n <app-header title=\"Settings\" subtitle=\"Human-admin controls and automation credentials\" back=\"/runs\" back-label=\"Back to jobs\"></app-header>\n <nav class=\"flex flex-wrap gap-1 rounded-xl border border-gray-800 bg-gray-900/70 p-1\" aria-label=\"Settings navigation\">\n <a href=\"/settings/workflows\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">Workflows</a>\n <a href=\"/settings/secrets\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">Secrets</a>\n <a href=\"/settings/tokens\" bind-class=\"page === 'tokens' ? 'bg-gray-800.text-white' : ''\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">API tokens</a>\n <a href=\"/settings/notifications\" bind-class=\"page === 'notifications' ? 'bg-gray-800.text-white' : ''\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">Notifications</a>\n </nav>\n\n <template if=\"page === 'tokens'\">\n </template>\n <template if=\"page === 'notifications'\">\n <section class=\"rounded-2xl border border-gray-800 bg-gray-900/80 p-5\" aria-labelledby=\"notifications-title\">\n <h2 id=\"notifications-title\" class=\"text-lg font-semibold text-white\">Notifications</h2>\n <p class=\"mt-1 text-sm text-gray-400\">Receive job completion notifications on this device.</p>\n <button type=\"button\" on-click=\"toggleNotifications()\" class=\"mt-5 inline-flex items-center gap-2 rounded-lg border border-indigo-500/60 px-4 py-2.5 text-sm font-medium text-indigo-200 outline-none hover:bg-indigo-500/10 focus-visible:ring-2 focus-visible:ring-indigo-400/60\">\n <lucide-icon bind-icon=\"notificationsEnabled ? 'bell-off' : 'bell-ring'\" size=\"16\"></lucide-icon>\n {{ notificationsEnabled ? 'Disable notifications' : 'Enable notifications' }}\n </button>\n <p class=\"mt-3 text-sm text-gray-400\" role=\"status\">{{ notificationMessage }}</p>\n </section>\n </template>\n\n <template if=\"page === 'tokens'\">\n <section class=\"rounded-2xl border border-gray-800 bg-gray-900/80 p-5\" aria-labelledby=\"keys-title\">\n <div class=\"flex items-start justify-between gap-3\">\n <div>\n <h2 id=\"keys-title\" class=\"text-lg font-semibold text-white\">API keys</h2>\n <p class=\"mt-1 text-sm text-gray-400\">Issue narrowly scoped credentials for automation tools. Keys are shown only once.</p>\n </div>\n </div>\n <div class=\"mt-5 grid gap-3 rounded-xl border border-gray-800 bg-gray-950/50 p-4 md:grid-cols-[1fr_auto]\">\n <label class=\"sr-only\" for=\"key-name\">Key name</label>\n <input id=\"key-name\" bind-value=\"keyName\" on-input=\"setKeyName($event)\" placeholder=\"Documentation bot\" class=\"rounded-lg border border-gray-700 bg-gray-900 px-3 py-2.5 text-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/30\" />\n <button type=\"button\" on-click=\"issueKey()\" class=\"inline-flex items-center justify-center gap-2 rounded-lg bg-indigo-500 px-4 py-2.5 text-sm font-semibold text-white outline-none hover:bg-indigo-400 focus-visible:ring-2 focus-visible:ring-indigo-400/60\"><lucide-icon icon=\"key-round\" size=\"16\"></lucide-icon>Issue key</button>\n <fieldset class=\"md:col-span-2\">\n <legend class=\"mb-2 text-xs font-semibold uppercase tracking-wider text-gray-500\">Scopes</legend>\n <div class=\"space-y-2\">\n <template for=\"scope of scopeOptions\">\n <label class=\"group flex cursor-pointer items-center gap-3 text-sm text-gray-300\">\n <input type=\"checkbox\" bind-checked=\"scope.selected\" on-change=\"toggleScope(scope)\" class=\"peer sr-only\" />\n <span aria-hidden=\"true\" class=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-md border border-gray-600 bg-gray-900 text-transparent transition peer-checked:border-indigo-400 peer-checked:bg-indigo-500 peer-checked:text-white peer-focus-visible:ring-2 peer-focus-visible:ring-indigo-400/70 peer-disabled:opacity-50\">\n <svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m3 8 3 3 7-7\"></path></svg>\n </span>\n <span class=\"group-hover:text-white\">{{ scope.label }}</span>\n </label>\n </template>\n </div>\n </fieldset>\n </div>\n <template if=\"newToken\">\n <div class=\"mt-4 rounded-xl border border-amber-500/40 bg-amber-500/10 p-4\" role=\"alert\">\n <p class=\"text-sm font-semibold text-amber-200\">Copy this key now. It cannot be shown again.</p>\n <code class=\"mt-2 block select-all break-all rounded bg-gray-950 p-3 font-mono text-xs text-amber-100\">{{ newToken }}</code>\n </div>\n </template>\n <h3 class=\"mt-5 text-xs font-semibold uppercase tracking-wider text-gray-500\">Active tokens</h3>\n <ul class=\"mt-2 space-y-2\" aria-label=\"Active API keys\">\n <template for=\"key of keys\">\n <li class=\"flex items-center justify-between gap-3 rounded-xl border border-gray-800 bg-gray-950/60 px-4 py-3\">\n <div class=\"min-w-0\"><p class=\"truncate text-sm font-medium text-gray-200\">{{ key.name }}</p><p class=\"text-xs text-gray-500\">{{ key.scopes.join(', ') }} · created {{ key.created_at }}</p></div>\n <button type=\"button\" on-click=\"revokeKey(key)\" class=\"shrink-0 rounded-lg p-2 text-rose-300 outline-none hover:bg-rose-500/10 focus-visible:ring-2 focus-visible:ring-rose-400/60\" aria-label=\"Revoke {{ key.name }}\" title=\"Revoke key\"><lucide-icon icon=\"trash\" size=\"16\"></lucide-icon></button>\n </li>\n </template>\n </ul>\n </section>\n </template>\n <p class=\"text-sm text-rose-300\" role=\"alert\" class-hidden=\"!error\">{{ error }}</p>\n </main>\n <script setup>\n import { onInit, ref } from '@li3/web';\n export default function () {\n const page = document.body.dataset.page;\n const keys = ref([]);\n const keyName = ref('');\n const newToken = ref('');\n const error = ref('');\n const notificationsSupported = ref('Notification' in window && 'serviceWorker' in navigator);\n const notificationsEnabled = ref(notificationsSupported.value && Notification.permission === 'granted' && localStorage.getItem('runner-notifications') === 'enabled');\n const notificationMessage = ref('');\n const scopeOptions = ref([\n { name: 'workflows:read', label: 'Read workflows', selected: true },\n { name: 'workflows:write', label: 'Modify workflows', selected: false },\n { name: 'logs:read', label: 'Read logs', selected: false },\n { name: 'artifacts:read', label: 'Read artifacts', selected: false },\n { name: 'runs:control', label: 'Control runs', selected: false },\n { name: 'runs:dispatch', label: 'Dispatch runs', selected: false },\n ]);\n const api = async (url, options = {}) => { const response = await fetch(url, { headers: { accept: 'application/json', ...(options.body ? { 'content-type': 'application/json' } : {}) }, ...options }); const body = await response.json().catch(() => ({})); if (!response.ok) throw new Error(body.error || `Request failed: ${response.status}`); return body; };\n const load = async () => { keys.value = (await api('/api/api-keys')).keys; };\n const issueKey = async () => { try { error.value = ''; const result = await api('/api/api-keys', { method: 'POST', body: JSON.stringify({ name: keyName.value, scopes: scopeOptions.value.filter((scope) => scope.selected).map((scope) => scope.name) }) }); newToken.value = result.token; keyName.value = ''; await load(); } catch (reason) { error.value = reason.message; } };\n const revokeKey = async (key) => { if (!confirm(`Revoke ${key.name}?`)) return; try { await api(`/api/api-keys/${key.id}`, { method: 'DELETE' }); await load(); } catch (reason) { error.value = reason.message; } };\n const setKeyName = (event) => { keyName.value = event.target.value; };\n const toggleScope = (scope) => { scope.selected = !scope.selected; };\n const toggleNotifications = async () => {\n if (notificationsEnabled.value) {\n notificationsEnabled.value = false;\n localStorage.removeItem('runner-notifications');\n notificationMessage.value = 'Notifications disabled on this device.';\n return;\n }\n if (!notificationsSupported.value) { notificationMessage.value = 'Notifications are not supported by this browser.'; return; }\n const permission = await Notification.requestPermission();\n notificationsEnabled.value = permission === 'granted';\n if (notificationsEnabled.value) { localStorage.setItem('runner-notifications', 'enabled'); notificationMessage.value = 'Notifications enabled.'; }\n else notificationMessage.value = 'Notification permission was not granted.';\n };\n onInit(() => { if (page === 'tokens') load().catch((reason) => { error.value = reason.message; }); });\n return { page, keys, keyName, newToken, error, scopeOptions, issueKey, revokeKey, setKeyName, toggleScope, notificationsEnabled, notificationMessage, toggleNotifications };\n }\n <\/script>\n </template>\n <script type=\"module\">import '@li3/web';<\/script>\n <script src=\"https://cdn.tailwindcss.com\"><\/script>\n </body>\n</html>\n";
|
|
6399
|
+
}, la = "<!doctype html>\n<html lang=\"en\" class=\"dark\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Runner settings</title>\n <script type=\"importmap\">\n { \"imports\": { \"@li3/\": \"https://cdn.li3.dev/@li3/\" } }\n <\/script>\n <link rel=\"component\" href=\"https://sodium.static.apphor.de/lucide-icon.html\" />\n <link rel=\"component\" href=\"/app-header.html\" />\n </head>\n <body data-page=\"__SETTINGS_PAGE__\" class=\"min-h-screen bg-gray-950 p-4 font-sans text-gray-100 md:p-6\">\n <template app>\n <main class=\"mx-auto max-w-6xl space-y-5 py-6\">\n <app-header title=\"Settings\" subtitle=\"Human-admin controls and automation credentials\" back=\"/runs\" back-label=\"Back to jobs\"></app-header>\n <nav class=\"flex flex-wrap gap-1 rounded-xl border border-gray-800 bg-gray-900/70 p-1\" aria-label=\"Settings navigation\">\n <a href=\"/settings/workflows\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">Workflows</a>\n <a href=\"/settings/secrets\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">Secrets</a>\n <a href=\"/settings/tokens\" bind-class=\"page === 'tokens' ? 'bg-gray-800.text-white' : ''\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">API tokens</a>\n <a href=\"/settings/notifications\" bind-class=\"page === 'notifications' ? 'bg-gray-800.text-white' : ''\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">Notifications</a>\n <a href=\"/settings/workers\" bind-class=\"page === 'workers' ? 'bg-gray-800.text-white' : ''\" class=\"rounded-lg px-3 py-2 text-sm text-gray-300 hover:bg-gray-800\">Workers</a>\n </nav>\n\n <template if=\"page === 'tokens'\">\n </template>\n <template if=\"page === 'notifications'\">\n <section class=\"rounded-2xl border border-gray-800 bg-gray-900/80 p-5\" aria-labelledby=\"notifications-title\">\n <h2 id=\"notifications-title\" class=\"text-lg font-semibold text-white\">Notifications</h2>\n <p class=\"mt-1 text-sm text-gray-400\">Receive job completion notifications on this device.</p>\n <button type=\"button\" on-click=\"toggleNotifications()\" class=\"mt-5 inline-flex items-center gap-2 rounded-lg border border-indigo-500/60 px-4 py-2.5 text-sm font-medium text-indigo-200 outline-none hover:bg-indigo-500/10 focus-visible:ring-2 focus-visible:ring-indigo-400/60\">\n <lucide-icon bind-icon=\"notificationsEnabled ? 'bell-off' : 'bell-ring'\" size=\"16\"></lucide-icon>\n {{ notificationsEnabled ? 'Disable notifications' : 'Enable notifications' }}\n </button>\n <p class=\"mt-3 text-sm text-gray-400\" role=\"status\">{{ notificationMessage }}</p>\n </section>\n </template>\n\n <template if=\"page === 'workers'\">\n <section class=\"rounded-2xl border border-gray-800 bg-gray-900/80 p-5\" aria-labelledby=\"workers-title\">\n <h2 id=\"workers-title\" class=\"text-lg font-semibold text-white\">Workers</h2>\n <p class=\"mt-1 text-sm text-gray-400\">Connected runner status, versions, tags, and load.</p>\n <div class=\"mt-5 overflow-hidden rounded-xl border border-gray-800\"><table class=\"w-full text-left text-sm\"><thead class=\"bg-gray-950 text-xs uppercase text-gray-500\"><tr><th class=\"px-4 py-3\">Worker</th><th class=\"px-4 py-3\">Version</th><th class=\"px-4 py-3\">Tags</th><th class=\"px-4 py-3\">Load</th><th class=\"px-4 py-3\">Last seen</th></tr></thead><tbody><template for=\"worker of workers\"><tr class=\"border-t border-gray-800\"><td class=\"px-4 py-3 font-mono text-gray-200\">{{ worker.workerId }} <span class=\"ml-2 rounded-full px-2 py-0.5 text-xs\" bind-class=\"worker.online ? 'bg-emerald-500/10.text-emerald-300' : 'bg-gray-800.text-gray-500'\">{{ worker.online ? 'online' : 'offline' }}</span></td><td class=\"px-4 py-3 font-mono text-gray-400\">{{ worker.version }}</td><td class=\"px-4 py-3 text-gray-400\">{{ worker.tags.join(', ') }}</td><td class=\"px-4 py-3 text-gray-400\">{{ worker.activeJobs }} / {{ worker.concurrency }}</td><td class=\"px-4 py-3 text-gray-500\">{{ worker.lastSeen }}</td></tr></template></tbody></table><p class=\"p-5 text-sm text-gray-500\" class-hidden=\"workers.length > 0\">No worker heartbeats received yet.</p></div>\n </section>\n </template>\n\n <template if=\"page === 'tokens'\">\n <section class=\"rounded-2xl border border-gray-800 bg-gray-900/80 p-5\" aria-labelledby=\"keys-title\">\n <div class=\"flex items-start justify-between gap-3\">\n <div>\n <h2 id=\"keys-title\" class=\"text-lg font-semibold text-white\">API keys</h2>\n <p class=\"mt-1 text-sm text-gray-400\">Issue narrowly scoped credentials for automation tools. Keys are shown only once.</p>\n </div>\n </div>\n <div class=\"mt-5 grid gap-3 rounded-xl border border-gray-800 bg-gray-950/50 p-4 md:grid-cols-[1fr_auto]\">\n <label class=\"sr-only\" for=\"key-name\">Key name</label>\n <input id=\"key-name\" bind-value=\"keyName\" on-input=\"setKeyName($event)\" placeholder=\"Documentation bot\" class=\"rounded-lg border border-gray-700 bg-gray-900 px-3 py-2.5 text-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/30\" />\n <button type=\"button\" on-click=\"issueKey()\" class=\"inline-flex items-center justify-center gap-2 rounded-lg bg-indigo-500 px-4 py-2.5 text-sm font-semibold text-white outline-none hover:bg-indigo-400 focus-visible:ring-2 focus-visible:ring-indigo-400/60\"><lucide-icon icon=\"key-round\" size=\"16\"></lucide-icon>Issue key</button>\n <fieldset class=\"md:col-span-2\">\n <legend class=\"mb-2 text-xs font-semibold uppercase tracking-wider text-gray-500\">Scopes</legend>\n <div class=\"space-y-2\">\n <template for=\"scope of scopeOptions\">\n <label class=\"group flex cursor-pointer items-center gap-3 text-sm text-gray-300\">\n <input type=\"checkbox\" bind-checked=\"scope.selected\" on-change=\"toggleScope(scope)\" class=\"peer sr-only\" />\n <span aria-hidden=\"true\" class=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-md border border-gray-600 bg-gray-900 text-transparent transition peer-checked:border-indigo-400 peer-checked:bg-indigo-500 peer-checked:text-white peer-focus-visible:ring-2 peer-focus-visible:ring-indigo-400/70 peer-disabled:opacity-50\">\n <svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m3 8 3 3 7-7\"></path></svg>\n </span>\n <span class=\"group-hover:text-white\">{{ scope.label }}</span>\n </label>\n </template>\n </div>\n </fieldset>\n </div>\n <template if=\"newToken\">\n <div class=\"mt-4 rounded-xl border border-amber-500/40 bg-amber-500/10 p-4\" role=\"alert\">\n <p class=\"text-sm font-semibold text-amber-200\">Copy this key now. It cannot be shown again.</p>\n <code class=\"mt-2 block select-all break-all rounded bg-gray-950 p-3 font-mono text-xs text-amber-100\">{{ newToken }}</code>\n </div>\n </template>\n <h3 class=\"mt-5 text-xs font-semibold uppercase tracking-wider text-gray-500\">Active tokens</h3>\n <ul class=\"mt-2 space-y-2\" aria-label=\"Active API keys\">\n <template for=\"key of keys\">\n <li class=\"flex items-center justify-between gap-3 rounded-xl border border-gray-800 bg-gray-950/60 px-4 py-3\">\n <div class=\"min-w-0\"><p class=\"truncate text-sm font-medium text-gray-200\">{{ key.name }}</p><p class=\"text-xs text-gray-500\">{{ key.scopes.join(', ') }} · created {{ key.created_at }}</p></div>\n <button type=\"button\" on-click=\"revokeKey(key)\" class=\"shrink-0 rounded-lg p-2 text-rose-300 outline-none hover:bg-rose-500/10 focus-visible:ring-2 focus-visible:ring-rose-400/60\" aria-label=\"Revoke {{ key.name }}\" title=\"Revoke key\"><lucide-icon icon=\"trash\" size=\"16\"></lucide-icon></button>\n </li>\n </template>\n </ul>\n </section>\n </template>\n <p class=\"text-sm text-rose-300\" role=\"alert\" class-hidden=\"!error\">{{ error }}</p>\n </main>\n <script setup>\n import { onInit, ref } from '@li3/web';\n export default function () {\n const page = document.body.dataset.page;\n const keys = ref([]);\n const workers = ref([]);\n const keyName = ref('');\n const newToken = ref('');\n const error = ref('');\n const notificationsSupported = ref('Notification' in window && 'serviceWorker' in navigator);\n const notificationsEnabled = ref(notificationsSupported.value && Notification.permission === 'granted' && localStorage.getItem('runner-notifications') === 'enabled');\n const notificationMessage = ref('');\n const scopeOptions = ref([\n { name: 'workflows:read', label: 'Read workflows', selected: true },\n { name: 'workflows:write', label: 'Modify workflows', selected: false },\n { name: 'logs:read', label: 'Read logs', selected: false },\n { name: 'artifacts:read', label: 'Read artifacts', selected: false },\n { name: 'runs:control', label: 'Control runs', selected: false },\n { name: 'runs:dispatch', label: 'Dispatch runs', selected: false },\n ]);\n const api = async (url, options = {}) => { const response = await fetch(url, { headers: { accept: 'application/json', ...(options.body ? { 'content-type': 'application/json' } : {}) }, ...options }); const body = await response.json().catch(() => ({})); if (!response.ok) throw new Error(body.error || `Request failed: ${response.status}`); return body; };\n const load = async () => { keys.value = (await api('/api/api-keys')).keys; };\n const loadWorkers = async () => { workers.value = (await api('/api/workers')).workers; };\n const issueKey = async () => { try { error.value = ''; const result = await api('/api/api-keys', { method: 'POST', body: JSON.stringify({ name: keyName.value, scopes: scopeOptions.value.filter((scope) => scope.selected).map((scope) => scope.name) }) }); newToken.value = result.token; keyName.value = ''; await load(); } catch (reason) { error.value = reason.message; } };\n const revokeKey = async (key) => { if (!confirm(`Revoke ${key.name}?`)) return; try { await api(`/api/api-keys/${key.id}`, { method: 'DELETE' }); await load(); } catch (reason) { error.value = reason.message; } };\n const setKeyName = (event) => { keyName.value = event.target.value; };\n const toggleScope = (scope) => { scope.selected = !scope.selected; };\n const toggleNotifications = async () => {\n if (notificationsEnabled.value) {\n notificationsEnabled.value = false;\n localStorage.removeItem('runner-notifications');\n notificationMessage.value = 'Notifications disabled on this device.';\n return;\n }\n if (!notificationsSupported.value) { notificationMessage.value = 'Notifications are not supported by this browser.'; return; }\n const permission = await Notification.requestPermission();\n notificationsEnabled.value = permission === 'granted';\n if (notificationsEnabled.value) { localStorage.setItem('runner-notifications', 'enabled'); notificationMessage.value = 'Notifications enabled.'; }\n else notificationMessage.value = 'Notification permission was not granted.';\n };\n onInit(() => { if (page === 'tokens') load().catch((reason) => { error.value = reason.message; }); if (page === 'workers') loadWorkers().catch((reason) => { error.value = reason.message; }); });\n return { page, keys, workers, keyName, newToken, error, scopeOptions, issueKey, revokeKey, setKeyName, toggleScope, notificationsEnabled, notificationMessage, toggleNotifications };\n }\n <\/script>\n </template>\n <script type=\"module\">import '@li3/web';<\/script>\n <script src=\"https://cdn.tailwindcss.com\"><\/script>\n </body>\n</html>\n";
|
|
6379
6400
|
//#endregion
|
|
6380
6401
|
//#region src/settings-ui.ts
|
|
6381
6402
|
function ua(e = "tokens") {
|
|
@@ -20852,6 +20873,26 @@ var SC = class {
|
|
|
20852
20873
|
"Cache-Control": "no-store",
|
|
20853
20874
|
"Content-Type": "application/json; charset=utf-8"
|
|
20854
20875
|
}), t.end(JSON.stringify(oa));
|
|
20876
|
+
if (e.method === "POST" && n.pathname === "/api/workers/heartbeat") {
|
|
20877
|
+
if (!this.isWorker(e)) {
|
|
20878
|
+
t.writeHead(403, { "Content-Type": "application/json" }).end(JSON.stringify({ error: "Unauthorized" }));
|
|
20879
|
+
return;
|
|
20880
|
+
}
|
|
20881
|
+
let n = await this.readJson(e, t);
|
|
20882
|
+
if (!n || n.workerId !== e.headers["x-runner-worker-id"]) return;
|
|
20883
|
+
await this.queue.updateWorkerPresence({
|
|
20884
|
+
id: n.workerId,
|
|
20885
|
+
version: String(n.version || "unknown"),
|
|
20886
|
+
tags: Array.isArray(n.tags) ? n.tags : [],
|
|
20887
|
+
concurrency: Number(n.concurrency || 0),
|
|
20888
|
+
activeJobs: Number(n.activeJobs || 0)
|
|
20889
|
+
}), t.writeHead(204).end();
|
|
20890
|
+
return;
|
|
20891
|
+
}
|
|
20892
|
+
if (e.method === "GET" && n.pathname === "/api/workers") return await this.hasScope(e, "workers:read") ? (t.writeHead(200, {
|
|
20893
|
+
"Cache-Control": "no-store",
|
|
20894
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
20895
|
+
}), t.end(JSON.stringify({ workers: await this.queue.listWorkerPresence() }))) : this.requireScope(e, t, "workers:read");
|
|
20855
20896
|
if (e.method === "GET" && n.pathname === "/pages/dashboard.html") return this.renderPageComponent(t, "page-dashboard", Ce);
|
|
20856
20897
|
if (e.method === "GET" && n.pathname === "/pages/run.html") return this.renderPageComponent(t, "page-run", Fe);
|
|
20857
20898
|
if (e.method === "GET" && n.pathname === "/pages/help.html") return this.renderPageComponent(t, "page-help", aa(!1), !0);
|
|
@@ -20867,7 +20908,7 @@ var SC = class {
|
|
|
20867
20908
|
}
|
|
20868
20909
|
if (e.method === "GET" && n.pathname === "/workflows") return this.requireAdmin(e, t) ? (t.writeHead(302, { Location: "/settings/workflows" }), t.end()) : void 0;
|
|
20869
20910
|
if (e.method === "GET" && n.pathname === "/settings") return this.isAdmin(e) ? (t.writeHead(302, { Location: "/settings/workflows" }), t.end()) : this.requireAdmin(e, t);
|
|
20870
|
-
let r = n.pathname.match(/^\/settings\/(workflows|secrets|tokens|notifications)$/);
|
|
20911
|
+
let r = n.pathname.match(/^\/settings\/(workflows|secrets|tokens|notifications|workers)$/);
|
|
20871
20912
|
if (e.method === "GET" && r) return this.requireAdmin(e, t) ? (r[1], this.renderAppShell(t)) : void 0;
|
|
20872
20913
|
if (n.pathname === "/api/api-keys") {
|
|
20873
20914
|
if (!this.isAdmin(e)) return this.requireAdmin(e, t);
|
|
@@ -21712,7 +21753,7 @@ async function AC(e) {
|
|
|
21712
21753
|
if (!t) {
|
|
21713
21754
|
t = !0, console.log(`\n🛑 Received ${n}. Initiating graceful shutdown...`);
|
|
21714
21755
|
try {
|
|
21715
|
-
|
|
21756
|
+
VC(), e.length > 0 && (console.log("⚙️ Waiting for active worker jobs to drain..."), await Promise.allSettled(e)), console.log("✨ Engine stopped cleanly. Goodbye!"), process.exit(0);
|
|
21716
21757
|
} catch (e) {
|
|
21717
21758
|
console.error("❌ Error during graceful shutdown:", e.message), process.exit(1);
|
|
21718
21759
|
}
|
|
@@ -21803,59 +21844,102 @@ PC("github-status", (e) => {
|
|
|
21803
21844
|
});
|
|
21804
21845
|
});
|
|
21805
21846
|
//#endregion
|
|
21806
|
-
//#region src/
|
|
21807
|
-
var IC = {
|
|
21808
|
-
|
|
21809
|
-
|
|
21810
|
-
|
|
21811
|
-
|
|
21812
|
-
|
|
21813
|
-
|
|
21847
|
+
//#region src/version.ts
|
|
21848
|
+
var IC = {
|
|
21849
|
+
name: "@cloud-cli/on",
|
|
21850
|
+
version: "0.0.0",
|
|
21851
|
+
description: "CLI entry point for the on plugin ecosystem.",
|
|
21852
|
+
type: "module",
|
|
21853
|
+
packageManager: "pnpm@12.3.4",
|
|
21854
|
+
license: "MIT",
|
|
21855
|
+
exports: { ".": {
|
|
21856
|
+
types: "./dist/index.d.ts",
|
|
21857
|
+
default: "./dist/on.js"
|
|
21858
|
+
} },
|
|
21859
|
+
files: ["dist"],
|
|
21860
|
+
main: "dist/on.js",
|
|
21861
|
+
bin: { on: "dist/on.js" },
|
|
21862
|
+
dependencies: {
|
|
21863
|
+
acorn: "^8.18.0",
|
|
21864
|
+
openai: "7.15.0",
|
|
21865
|
+
"web-push": "^3.6.7",
|
|
21866
|
+
yaml: "^2.9.0"
|
|
21867
|
+
},
|
|
21868
|
+
scripts: {
|
|
21869
|
+
ci: "pnpm build && pnpm lint && pnpm test",
|
|
21870
|
+
build: "vite build && tsc --emitDeclarationOnly --declaration",
|
|
21871
|
+
lint: "eslint .",
|
|
21872
|
+
test: "vitest run",
|
|
21873
|
+
"test:e2e": "docker build --no-cache -t on:e2e . && node tests/docker-smoke.mjs",
|
|
21874
|
+
release: "npx --yes semantic-release@24 -b main --no-ci"
|
|
21875
|
+
},
|
|
21876
|
+
devDependencies: {
|
|
21877
|
+
"@changesets/cli": "^2.31.1",
|
|
21878
|
+
"@eslint/js": "^10.0.1",
|
|
21879
|
+
"@types/node": "^26.5.1",
|
|
21880
|
+
"@types/web-push": "^3.6.4",
|
|
21881
|
+
"@typescript-eslint/eslint-plugin": "^8.70.0",
|
|
21882
|
+
"@typescript-eslint/parser": "^8.70.0",
|
|
21883
|
+
eslint: "10.8.0",
|
|
21884
|
+
marked: "^18.0.12",
|
|
21885
|
+
tsx: "4.23.13",
|
|
21886
|
+
typescript: "6.0.3",
|
|
21887
|
+
"typescript-eslint": "8.70.0",
|
|
21888
|
+
vite: "8.2.0",
|
|
21889
|
+
vitest: "4.1.11"
|
|
21890
|
+
}
|
|
21891
|
+
}.version, LC = { isStopping: !1 }, RC = /* @__PURE__ */ new Set(), zC = null, BC = null;
|
|
21892
|
+
function VC() {
|
|
21893
|
+
LC.isStopping = !0, zC?.abort(), BC?.();
|
|
21894
|
+
}
|
|
21895
|
+
function HC(e, t, n, r) {
|
|
21896
|
+
LC.isStopping = !1;
|
|
21897
|
+
let i = [UC(e, t, n, r)];
|
|
21814
21898
|
return AC(i), i;
|
|
21815
21899
|
}
|
|
21816
|
-
async function
|
|
21900
|
+
async function UC(e, t, n, r) {
|
|
21817
21901
|
let i = await kC(), a = new SC(), o = /* @__PURE__ */ new Set(), s = 0, c = null, l = () => {
|
|
21818
21902
|
s++, c?.();
|
|
21819
|
-
};
|
|
21820
|
-
|
|
21821
|
-
let
|
|
21822
|
-
for (console.log(`🚀 Worker scheduler started. Driver: ${i.name}. Concurrency: ${e}. Tags: ${r.tags.join(", ") || "(none)"}`); !
|
|
21903
|
+
}, u = process.env.WORKER_NAME || "cli";
|
|
21904
|
+
BC = l, zC = new AbortController();
|
|
21905
|
+
let d = WC(r, zC.signal, l), f = setInterval(() => void JC(r, u, e, o.size), 15e3);
|
|
21906
|
+
for (f.unref(), JC(r, u, e, o.size), console.log(`🚀 Worker scheduler started. Driver: ${i.name}. Concurrency: ${e}. Tags: ${r.tags.join(", ") || "(none)"}`); !LC.isStopping;) {
|
|
21823
21907
|
let n = s;
|
|
21824
21908
|
try {
|
|
21825
|
-
for (; o.size < e && !
|
|
21909
|
+
for (; o.size < e && !LC.isStopping;) {
|
|
21826
21910
|
let e = await t.claimNextJob(r.tags);
|
|
21827
21911
|
if (!e) break;
|
|
21828
|
-
if (
|
|
21912
|
+
if (LC.isStopping) {
|
|
21829
21913
|
await t.releaseJob(e.id);
|
|
21830
21914
|
break;
|
|
21831
21915
|
}
|
|
21832
|
-
let n
|
|
21833
|
-
|
|
21834
|
-
|
|
21835
|
-
let
|
|
21836
|
-
if (!
|
|
21837
|
-
let
|
|
21838
|
-
|
|
21839
|
-
workerId:
|
|
21916
|
+
let n;
|
|
21917
|
+
n = (async () => {
|
|
21918
|
+
qC(r, e.id);
|
|
21919
|
+
let n = await a.getRevision(e.workflow_id, e.workflow_revision);
|
|
21920
|
+
if (!n) throw await t.finishJob(e.id, "failed"), Error(`Workflow ${e.workflow_id} revision ${e.workflow_revision} was not found`);
|
|
21921
|
+
let o = new Se();
|
|
21922
|
+
o.replace(await YC(r, u, e.id)), await XC({
|
|
21923
|
+
workerId: u,
|
|
21840
21924
|
job: e,
|
|
21841
21925
|
queue: t,
|
|
21842
|
-
secrets:
|
|
21926
|
+
secrets: o,
|
|
21843
21927
|
config: r,
|
|
21844
21928
|
driver: i,
|
|
21845
|
-
workflow:
|
|
21929
|
+
workflow: n
|
|
21846
21930
|
});
|
|
21847
|
-
})().catch((e) => console.error(`[${
|
|
21848
|
-
o.delete(
|
|
21849
|
-
}), o.add(
|
|
21931
|
+
})().catch((e) => console.error(`[${u}] ⚠️ Worker execution error:`, e)).finally(() => {
|
|
21932
|
+
o.delete(n), qC(r, e.id), l();
|
|
21933
|
+
}), o.add(n);
|
|
21850
21934
|
}
|
|
21851
21935
|
} catch (e) {
|
|
21852
21936
|
console.error("⚠️ Worker scheduler claim error:", e), setTimeout(l, 5e3).unref();
|
|
21853
21937
|
}
|
|
21854
|
-
!
|
|
21938
|
+
!LC.isStopping && s === n && (await GC(n, () => s, (e) => c = e), c = null);
|
|
21855
21939
|
}
|
|
21856
|
-
|
|
21940
|
+
zC.abort(), clearInterval(f), await Promise.allSettled(o), await d, BC = null, console.log("🛑 Worker scheduler stopped cleanly.");
|
|
21857
21941
|
}
|
|
21858
|
-
async function
|
|
21942
|
+
async function WC(e, t, n) {
|
|
21859
21943
|
let r = 1e3;
|
|
21860
21944
|
for (; !t.aborted;) {
|
|
21861
21945
|
try {
|
|
@@ -21866,10 +21950,10 @@ async function UC(e, t, n) {
|
|
|
21866
21950
|
if (t.aborted || e?.name === "AbortError") break;
|
|
21867
21951
|
console.error(`⚠️ Worker event stream disconnected: ${e.message}`);
|
|
21868
21952
|
}
|
|
21869
|
-
await
|
|
21953
|
+
await KC(r, t), r = Math.min(r * 2, 3e4);
|
|
21870
21954
|
}
|
|
21871
21955
|
}
|
|
21872
|
-
function
|
|
21956
|
+
function GC(e, t, n) {
|
|
21873
21957
|
return new Promise((r) => {
|
|
21874
21958
|
if (t() !== e) return r();
|
|
21875
21959
|
let i = setTimeout(r, 6e4);
|
|
@@ -21878,7 +21962,7 @@ function WC(e, t, n) {
|
|
|
21878
21962
|
});
|
|
21879
21963
|
});
|
|
21880
21964
|
}
|
|
21881
|
-
function
|
|
21965
|
+
function KC(e, t) {
|
|
21882
21966
|
return new Promise((n) => {
|
|
21883
21967
|
if (t.aborted) return n();
|
|
21884
21968
|
let r = () => {
|
|
@@ -21889,7 +21973,7 @@ function GC(e, t) {
|
|
|
21889
21973
|
t.addEventListener("abort", r, { once: !0 });
|
|
21890
21974
|
});
|
|
21891
21975
|
}
|
|
21892
|
-
async function
|
|
21976
|
+
async function qC(e, t) {
|
|
21893
21977
|
if (e.workerToken) try {
|
|
21894
21978
|
let n = await fetch(new URL("/api/events", e.serverUrl), {
|
|
21895
21979
|
method: "POST",
|
|
@@ -21905,7 +21989,29 @@ async function KC(e, t) {
|
|
|
21905
21989
|
dr("Failed to publish job status event:", e);
|
|
21906
21990
|
}
|
|
21907
21991
|
}
|
|
21908
|
-
async function
|
|
21992
|
+
async function JC(e, t, n, r) {
|
|
21993
|
+
if (e.workerToken) try {
|
|
21994
|
+
await fetch(new URL("/api/workers/heartbeat", e.serverUrl), {
|
|
21995
|
+
method: "POST",
|
|
21996
|
+
headers: {
|
|
21997
|
+
Authorization: `Bearer ${e.workerToken}`,
|
|
21998
|
+
"Content-Type": "application/json",
|
|
21999
|
+
"X-Runner-Worker-Id": t
|
|
22000
|
+
},
|
|
22001
|
+
body: JSON.stringify({
|
|
22002
|
+
workerId: t,
|
|
22003
|
+
version: IC,
|
|
22004
|
+
tags: e.tags,
|
|
22005
|
+
concurrency: n,
|
|
22006
|
+
activeJobs: r
|
|
22007
|
+
}),
|
|
22008
|
+
signal: AbortSignal.timeout(5e3)
|
|
22009
|
+
});
|
|
22010
|
+
} catch (e) {
|
|
22011
|
+
dr("Failed to publish worker heartbeat:", e);
|
|
22012
|
+
}
|
|
22013
|
+
}
|
|
22014
|
+
async function YC(e, t, n) {
|
|
21909
22015
|
if (!e.workerToken) return {};
|
|
21910
22016
|
try {
|
|
21911
22017
|
let r = await fetch(new URL(`/api/jobs/${n}/secrets`, e.serverUrl), {
|
|
@@ -21921,7 +22027,7 @@ async function qC(e, t, n) {
|
|
|
21921
22027
|
throw console.error(`Unable to retrieve secrets for job ${n}:`, e), e;
|
|
21922
22028
|
}
|
|
21923
22029
|
}
|
|
21924
|
-
async function
|
|
22030
|
+
async function XC(e) {
|
|
21925
22031
|
let { workerId: t, job: n, config: r, secrets: a, queue: o } = e;
|
|
21926
22032
|
console.log(`\n[${t}] 📦 Claimed Job #${n.id} (Workflow: ${n.workflow_id})`);
|
|
21927
22033
|
let s = typeof n.payload == "string" ? JSON.parse(n.payload) : n.payload;
|
|
@@ -21951,14 +22057,14 @@ async function JC(e) {
|
|
|
21951
22057
|
durationMs: 0,
|
|
21952
22058
|
outputs: {},
|
|
21953
22059
|
logContent: ""
|
|
21954
|
-
})), b =
|
|
21955
|
-
await o.saveReport(n.id, b),
|
|
22060
|
+
})), b = uw(n, "running", p, f, _.env, y, s);
|
|
22061
|
+
await o.saveReport(n.id, b), qC(r, n.id);
|
|
21956
22062
|
try {
|
|
21957
|
-
Object.assign(_.env, await
|
|
22063
|
+
Object.assign(_.env, await ew(l.env, _)), Object.assign(_.env, {
|
|
21958
22064
|
CI: "true",
|
|
21959
22065
|
CI_JOB_ID: String(n.id),
|
|
21960
22066
|
CI_JOB_NAME: l.name
|
|
21961
|
-
}),
|
|
22067
|
+
}), sw(l.secretFiles, a, g), v = l.cache ? String(await mr.evaluateValue(l.cache.key, _)) : "", v && l.cache && await ow(o, "cache", `${n.workflow_id}:${v}`, l.cache.paths, g), await o.saveReport(n.id, b);
|
|
21962
22068
|
} catch (e) {
|
|
21963
22069
|
b.status = "failed", b.finishedAt = (/* @__PURE__ */ new Date()).toISOString(), b.durationMs = Date.now() - p;
|
|
21964
22070
|
let r = {
|
|
@@ -21973,7 +22079,7 @@ async function JC(e) {
|
|
|
21973
22079
|
}
|
|
21974
22080
|
let x = [...r.plugins];
|
|
21975
22081
|
for (let e of l.plugins || []) try {
|
|
21976
|
-
let t = await
|
|
22082
|
+
let t = await ew(e.secrets, _);
|
|
21977
22083
|
x.push(FC({
|
|
21978
22084
|
...e,
|
|
21979
22085
|
secrets: t
|
|
@@ -21988,24 +22094,24 @@ async function JC(e) {
|
|
|
21988
22094
|
runUrl: new URL(`/runs/${n.id}`, r.serverUrl).toString()
|
|
21989
22095
|
};
|
|
21990
22096
|
await S.triggerWorkflowStart(ee);
|
|
21991
|
-
let { cancelled: te, failed: ne } = await
|
|
22097
|
+
let { cancelled: te, failed: ne } = await ZC({
|
|
21992
22098
|
payload: s,
|
|
21993
22099
|
steps: d,
|
|
21994
22100
|
executionContext: _,
|
|
21995
22101
|
...u
|
|
21996
22102
|
}, b), re = te ? "cancelled" : ne ? "failed" : "success";
|
|
21997
22103
|
if (re === "success") try {
|
|
21998
|
-
let e = l.artifacts ? await
|
|
22104
|
+
let e = l.artifacts ? await aw(l.artifacts.paths, g) : [];
|
|
21999
22105
|
if (e.length && (await o.saveStoredFiles("artifact", String(n.id), e), b.artifacts = e.map((e) => e.path)), v && l.cache) {
|
|
22000
|
-
let e = await
|
|
22106
|
+
let e = await aw(l.cache.paths, g);
|
|
22001
22107
|
e.length && await o.saveStoredFiles("cache", `${n.workflow_id}:${v}`, e);
|
|
22002
22108
|
}
|
|
22003
22109
|
} catch (e) {
|
|
22004
22110
|
console.error(`[${t}] ⚠️ Failed to store workflow files:`, e), re = "failed";
|
|
22005
22111
|
}
|
|
22006
|
-
b.status = re, b.durationMs = Date.now() - p, b.finishedAt = (/* @__PURE__ */ new Date()).toISOString(), await o.completeJob(n.id, re, b),
|
|
22112
|
+
b.status = re, b.durationMs = Date.now() - p, b.finishedAt = (/* @__PURE__ */ new Date()).toISOString(), await o.completeJob(n.id, re, b), qC(r, n.id), console.log(`[${t}] ✅ Job #${n.id} completed as: ${re}`), await S.triggerWorkflowFinish(ee, re);
|
|
22007
22113
|
}
|
|
22008
|
-
async function
|
|
22114
|
+
async function ZC(e, t) {
|
|
22009
22115
|
let { driver: n, workerId: r, queue: i, config: a, job: o, payload: s, steps: c, executionContext: l } = e, u = t.steps, d = !1, f = !1, p = 0;
|
|
22010
22116
|
try {
|
|
22011
22117
|
for (let s = 0; s < c.length; s++) {
|
|
@@ -22020,14 +22126,14 @@ async function YC(e, t) {
|
|
|
22020
22126
|
logContent: "",
|
|
22021
22127
|
startedAt: h,
|
|
22022
22128
|
finishedAt: void 0
|
|
22023
|
-
}, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t),
|
|
22129
|
+
}, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), qC(a, o.id);
|
|
22024
22130
|
let g = {
|
|
22025
22131
|
failed: !0,
|
|
22026
22132
|
skipped: !1,
|
|
22027
22133
|
cancelled: !1,
|
|
22028
22134
|
report: null
|
|
22029
22135
|
}, _ = e.workflow?.retries ?? 0;
|
|
22030
|
-
for (let e = 1; e <= _ + 1 && (g = await
|
|
22136
|
+
for (let e = 1; e <= _ + 1 && (g = await QC({
|
|
22031
22137
|
workerId: r,
|
|
22032
22138
|
jobId: o.id,
|
|
22033
22139
|
step: m,
|
|
@@ -22055,7 +22161,7 @@ async function YC(e, t) {
|
|
|
22055
22161
|
exitCode: 1,
|
|
22056
22162
|
error: "Step failed before execution started",
|
|
22057
22163
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22058
|
-
}, p = s + 1, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t),
|
|
22164
|
+
}, p = s + 1, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), qC(a, o.id), g.skipped) break;
|
|
22059
22165
|
if (g.cancelled) {
|
|
22060
22166
|
f = !0, d = !0;
|
|
22061
22167
|
break;
|
|
@@ -22068,13 +22174,13 @@ async function YC(e, t) {
|
|
|
22068
22174
|
} catch (e) {
|
|
22069
22175
|
console.log("🛑 Step failed", e), d = !0;
|
|
22070
22176
|
}
|
|
22071
|
-
return p < c.length && (
|
|
22177
|
+
return p < c.length && (lw(c, p, u), t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), qC(a, o.id)), {
|
|
22072
22178
|
failed: d,
|
|
22073
22179
|
cancelled: f,
|
|
22074
22180
|
stepReports: u
|
|
22075
22181
|
};
|
|
22076
22182
|
}
|
|
22077
|
-
async function
|
|
22183
|
+
async function QC(e) {
|
|
22078
22184
|
let { step: t, stepIndex: n, executionContext: r } = e;
|
|
22079
22185
|
if (t.id ||= `step-${n}`, t.name ||= t.id, t.if && !await mr.evaluateConditions(t.if, r)) return dr(`⏩ Skipped step ${t.id} based on condition: ${t.if}`, r), {
|
|
22080
22186
|
failed: !1,
|
|
@@ -22083,7 +22189,7 @@ async function XC(e) {
|
|
|
22083
22189
|
report: null
|
|
22084
22190
|
};
|
|
22085
22191
|
try {
|
|
22086
|
-
let i = await
|
|
22192
|
+
let i = await ew(t.env, r), a = {
|
|
22087
22193
|
jobId: String(e.jobId),
|
|
22088
22194
|
step: t,
|
|
22089
22195
|
command: t.run,
|
|
@@ -22103,10 +22209,10 @@ async function XC(e) {
|
|
|
22103
22209
|
CI_JOB_NAME: r.env.CI_JOB_NAME || t.name || t.id || `step-${n}`
|
|
22104
22210
|
}
|
|
22105
22211
|
};
|
|
22106
|
-
return t.eval ?
|
|
22212
|
+
return t.eval ? $C({
|
|
22107
22213
|
...e,
|
|
22108
22214
|
stepContext: a
|
|
22109
|
-
}) :
|
|
22215
|
+
}) : cw({
|
|
22110
22216
|
...e,
|
|
22111
22217
|
stepContext: a
|
|
22112
22218
|
});
|
|
@@ -22129,7 +22235,7 @@ async function XC(e) {
|
|
|
22129
22235
|
};
|
|
22130
22236
|
}
|
|
22131
22237
|
}
|
|
22132
|
-
async function
|
|
22238
|
+
async function $C(e) {
|
|
22133
22239
|
let { queue: t, stepContext: n, executionContext: r } = e, { jobId: i, step: a } = n, o = Date.now(), s = a.id, c = a.name, l;
|
|
22134
22240
|
try {
|
|
22135
22241
|
let e = new Promise((e, t) => {
|
|
@@ -22179,7 +22285,7 @@ async function ZC(e) {
|
|
|
22179
22285
|
l && clearTimeout(l);
|
|
22180
22286
|
}
|
|
22181
22287
|
}
|
|
22182
|
-
async function
|
|
22288
|
+
async function ew(e, t) {
|
|
22183
22289
|
let n = {};
|
|
22184
22290
|
if (e) for (let [r, i] of Object.entries(e)) n[r] = String(await mr.evaluateValue(i, {
|
|
22185
22291
|
...t,
|
|
@@ -22190,18 +22296,18 @@ async function QC(e, t) {
|
|
|
22190
22296
|
}));
|
|
22191
22297
|
return n;
|
|
22192
22298
|
}
|
|
22193
|
-
var
|
|
22194
|
-
function
|
|
22299
|
+
var tw = 52428800;
|
|
22300
|
+
function nw(e, t) {
|
|
22195
22301
|
let n = i.resolve(e), r = i.resolve(n, t);
|
|
22196
22302
|
if (r !== n && !r.startsWith(`${n}${i.sep}`)) throw Error(`Stored file path escapes workspace: ${t}`);
|
|
22197
22303
|
return r;
|
|
22198
22304
|
}
|
|
22199
|
-
function
|
|
22305
|
+
function rw(e, t) {
|
|
22200
22306
|
let n = "^";
|
|
22201
22307
|
for (let e = 0; e < t.length; e++) t[e] === "*" && t[e + 1] === "*" ? (n += ".*", e++) : t[e] === "*" ? n += "[^/]*" : n += t[e].replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
22202
22308
|
return RegExp(`${n}$`).test(e);
|
|
22203
22309
|
}
|
|
22204
|
-
function
|
|
22310
|
+
function iw(t, n) {
|
|
22205
22311
|
let r = i.resolve(n), a = [], o = (t) => {
|
|
22206
22312
|
for (let n of e.readdirSync(t, { withFileTypes: !0 })) {
|
|
22207
22313
|
let e = i.join(t, n.name);
|
|
@@ -22209,42 +22315,42 @@ function nw(t, n) {
|
|
|
22209
22315
|
}
|
|
22210
22316
|
};
|
|
22211
22317
|
return o(r), a.filter((r) => t.some((t) => {
|
|
22212
|
-
let i =
|
|
22318
|
+
let i = nw(n, t);
|
|
22213
22319
|
if (e.existsSync(i)) {
|
|
22214
22320
|
let n = e.statSync(i);
|
|
22215
22321
|
if (n.isFile()) return r === t;
|
|
22216
22322
|
if (n.isDirectory()) return r === t || r.startsWith(`${t.replace(/\/$/, "")}/`);
|
|
22217
22323
|
}
|
|
22218
|
-
return
|
|
22324
|
+
return rw(r, t);
|
|
22219
22325
|
}));
|
|
22220
22326
|
}
|
|
22221
|
-
async function
|
|
22222
|
-
let r =
|
|
22327
|
+
async function aw(t, n) {
|
|
22328
|
+
let r = iw(t, n), i = 0;
|
|
22223
22329
|
return r.map((t) => {
|
|
22224
|
-
let r = e.readFileSync(
|
|
22225
|
-
if (r.byteLength >
|
|
22330
|
+
let r = e.readFileSync(nw(n, t));
|
|
22331
|
+
if (r.byteLength > tw || (i += r.byteLength) > tw) throw Error(`Stored files exceed ${tw} bytes`);
|
|
22226
22332
|
return {
|
|
22227
22333
|
path: t,
|
|
22228
22334
|
content: r.toString("base64")
|
|
22229
22335
|
};
|
|
22230
22336
|
});
|
|
22231
22337
|
}
|
|
22232
|
-
async function
|
|
22338
|
+
async function ow(t, n, r, a, o) {
|
|
22233
22339
|
for (let s of await t.getStoredFiles(n, r)) {
|
|
22234
|
-
if (!a.some((e) => s.path === e || s.path.startsWith(`${e.replace(/\/$/, "")}/`) ||
|
|
22235
|
-
let t =
|
|
22340
|
+
if (!a.some((e) => s.path === e || s.path.startsWith(`${e.replace(/\/$/, "")}/`) || rw(s.path, e))) continue;
|
|
22341
|
+
let t = nw(o, s.path);
|
|
22236
22342
|
e.mkdirSync(i.dirname(t), { recursive: !0 }), e.writeFileSync(t, Buffer.from(s.content, "base64"));
|
|
22237
22343
|
}
|
|
22238
22344
|
}
|
|
22239
|
-
function
|
|
22345
|
+
function sw(t, n, r) {
|
|
22240
22346
|
for (let [a, o] of Object.entries(t || {})) {
|
|
22241
22347
|
let t = n.getValue(o);
|
|
22242
22348
|
if (!t) throw Error(`Secret '${o}' is not available for file '${a}'`);
|
|
22243
|
-
let s =
|
|
22349
|
+
let s = nw(r, a);
|
|
22244
22350
|
e.mkdirSync(i.dirname(s), { recursive: !0 }), e.writeFileSync(s, t.encoding === "base64" ? Buffer.from(t.value, "base64") : t.value, { mode: 384 }), e.chmodSync(s, 384);
|
|
22245
22351
|
}
|
|
22246
22352
|
}
|
|
22247
|
-
async function
|
|
22353
|
+
async function cw(t) {
|
|
22248
22354
|
let { workerId: n, jobId: r, stepContext: i, executionContext: a, driver: o, queue: s } = t, { step: c } = i, l = c.id, u = c.name, d;
|
|
22249
22355
|
try {
|
|
22250
22356
|
d = o.execute(i);
|
|
@@ -22259,11 +22365,11 @@ async function ow(t) {
|
|
|
22259
22365
|
logFilePath: ""
|
|
22260
22366
|
};
|
|
22261
22367
|
}
|
|
22262
|
-
|
|
22368
|
+
RC.add(d);
|
|
22263
22369
|
let f = !1, p = setInterval(async () => {
|
|
22264
22370
|
await s.isCancelled(r) && (console.log(`[${n}] 🛑 Job #${r} was cancelled! Halting execution.`), f = !0, clearInterval(p), await d.cancel());
|
|
22265
22371
|
}, 3e3), m = await d.done;
|
|
22266
|
-
if (clearInterval(p),
|
|
22372
|
+
if (clearInterval(p), RC.delete(d), d.logFilePath && e.existsSync(d.logFilePath)) try {
|
|
22267
22373
|
let e = await o.readLog(d.logFilePath);
|
|
22268
22374
|
await s.saveStepLog(r, l, e);
|
|
22269
22375
|
} catch (e) {
|
|
@@ -22290,7 +22396,7 @@ async function ow(t) {
|
|
|
22290
22396
|
}
|
|
22291
22397
|
};
|
|
22292
22398
|
}
|
|
22293
|
-
function
|
|
22399
|
+
function lw(e, t, n) {
|
|
22294
22400
|
for (let r = t; r < e.length; r++) {
|
|
22295
22401
|
let t = e[r], i = t.id || `step-${r}`;
|
|
22296
22402
|
n[r] = {
|
|
@@ -22304,7 +22410,7 @@ function sw(e, t, n) {
|
|
|
22304
22410
|
};
|
|
22305
22411
|
}
|
|
22306
22412
|
}
|
|
22307
|
-
function
|
|
22413
|
+
function uw(e, t, n, r, i, a, o) {
|
|
22308
22414
|
return {
|
|
22309
22415
|
jobId: String(e.id),
|
|
22310
22416
|
parentId: String(e.parentId || ""),
|
|
@@ -22325,7 +22431,7 @@ function cw(e, t, n, r, i, a, o) {
|
|
|
22325
22431
|
}
|
|
22326
22432
|
//#endregion
|
|
22327
22433
|
//#region src/scheduler.ts
|
|
22328
|
-
function
|
|
22434
|
+
function dw(e, t, n, r) {
|
|
22329
22435
|
return e.split(",").some((e) => {
|
|
22330
22436
|
let [i, a] = e.split("/"), o = a ? Number(a) : 1;
|
|
22331
22437
|
if (!Number.isInteger(o) || o < 1) return !1;
|
|
@@ -22333,7 +22439,7 @@ function lw(e, t, n, r) {
|
|
|
22333
22439
|
return Number.isInteger(l) && Number.isInteger(u) && t >= l && t <= u && (t - l) % o === 0;
|
|
22334
22440
|
});
|
|
22335
22441
|
}
|
|
22336
|
-
function
|
|
22442
|
+
function fw(e, t, n = "UTC") {
|
|
22337
22443
|
let r = e.trim().split(/\s+/);
|
|
22338
22444
|
if (r.length !== 5) return !1;
|
|
22339
22445
|
let i = new Intl.DateTimeFormat("en-US", {
|
|
@@ -22355,16 +22461,16 @@ function uw(e, t, n = "UTC") {
|
|
|
22355
22461
|
"Thu",
|
|
22356
22462
|
"Fri",
|
|
22357
22463
|
"Sat"
|
|
22358
|
-
].indexOf(i.weekday), o =
|
|
22359
|
-
return
|
|
22464
|
+
].indexOf(i.weekday), o = dw(r[2], Number(i.day), 1, 31), s = dw(r[4].replace(/7/g, "0"), a, 0, 6);
|
|
22465
|
+
return dw(r[0], Number(i.minute), 0, 59) && dw(r[1], Number(i.hour), 0, 23) && dw(r[3], Number(i.month), 1, 12) && (r[2] === "*" || r[4] === "*" ? o && s : o || s);
|
|
22360
22466
|
}
|
|
22361
|
-
function
|
|
22467
|
+
function pw(e) {
|
|
22362
22468
|
if (!e) return 0;
|
|
22363
22469
|
let t = e.match(/^([+-]?)(\d+)(m|h)$/);
|
|
22364
22470
|
if (!t) throw Error(`Invalid solar offset: ${e}`);
|
|
22365
22471
|
return (t[1] === "-" ? -1 : 1) * Number(t[2]) * (t[3] === "h" ? 36e5 : 6e4);
|
|
22366
22472
|
}
|
|
22367
|
-
function
|
|
22473
|
+
function mw(e, t) {
|
|
22368
22474
|
let n = t.latitude, r = t.longitude, i = Date.UTC(e.getUTCFullYear(), e.getUTCMonth(), e.getUTCDate()), a = Math.floor((i - Date.UTC(e.getUTCFullYear(), 0, 0)) / 864e5), o = r / 15, s = a + ((t.event === "sunrise" ? 6 : 18) - o) / 24, c = .9856 * s - 3.289, l = c + 1.916 * Math.sin(c * Math.PI / 180) + .02 * Math.sin(2 * c * Math.PI / 180) + 282.634;
|
|
22369
22475
|
l = (l + 360) % 360;
|
|
22370
22476
|
let u = Math.atan(.91764 * Math.tan(l * Math.PI / 180)) * 180 / Math.PI;
|
|
@@ -22372,9 +22478,9 @@ function fw(e, t) {
|
|
|
22372
22478
|
let d = .39782 * Math.sin(l * Math.PI / 180), f = Math.cos(Math.asin(d)), p = (Math.cos(90.833 * Math.PI / 180) - d * Math.sin(n * Math.PI / 180)) / (f * Math.cos(n * Math.PI / 180));
|
|
22373
22479
|
if (p > 1 || p < -1) return null;
|
|
22374
22480
|
let m = (t.event === "sunrise" ? 360 - Math.acos(p) * 180 / Math.PI : Math.acos(p) * 180 / Math.PI) / 15;
|
|
22375
|
-
return m = (m + u - .06571 * s - 6.622 - o + 24) % 24, new Date(i + m * 36e5 +
|
|
22481
|
+
return m = (m + u - .06571 * s - 6.622 - o + 24) % 24, new Date(i + m * 36e5 + pw(t.offset));
|
|
22376
22482
|
}
|
|
22377
|
-
var
|
|
22483
|
+
var hw = class {
|
|
22378
22484
|
queue;
|
|
22379
22485
|
workflows;
|
|
22380
22486
|
config;
|
|
@@ -22391,9 +22497,9 @@ var pw = class {
|
|
|
22391
22497
|
async tick(e = /* @__PURE__ */ new Date()) {
|
|
22392
22498
|
let t = /* @__PURE__ */ new Date(Math.floor(e.getTime() / 6e4) * 6e4);
|
|
22393
22499
|
for (let { definition: e, revision: n } of await this.workflows.published()) {
|
|
22394
|
-
for (let [r, i] of (e.schedule || []).entries())
|
|
22500
|
+
for (let [r, i] of (e.schedule || []).entries()) fw(i.cron, t, i.timezone || "UTC") && await this.enqueue(e, n, i, `cron-${r}`, t);
|
|
22395
22501
|
for (let [r, i] of (e.solar || []).entries()) {
|
|
22396
|
-
let a =
|
|
22502
|
+
let a = mw(t, i);
|
|
22397
22503
|
a && Math.floor(a.getTime() / 6e4) === t.getTime() / 6e4 && await this.enqueue(e, n, i, `solar-${r}`, t);
|
|
22398
22504
|
}
|
|
22399
22505
|
}
|
|
@@ -22419,7 +22525,7 @@ var pw = class {
|
|
|
22419
22525
|
};
|
|
22420
22526
|
//#endregion
|
|
22421
22527
|
//#region src/logger.ts
|
|
22422
|
-
function
|
|
22528
|
+
function gw() {
|
|
22423
22529
|
for (let e of [
|
|
22424
22530
|
"log",
|
|
22425
22531
|
"info",
|
|
@@ -22434,8 +22540,8 @@ function mw() {
|
|
|
22434
22540
|
}
|
|
22435
22541
|
//#endregion
|
|
22436
22542
|
//#region src/index.ts
|
|
22437
|
-
async function
|
|
22438
|
-
|
|
22543
|
+
async function _w() {
|
|
22544
|
+
gw();
|
|
22439
22545
|
let { config: e, command: t } = await ge();
|
|
22440
22546
|
e || process.exit(1);
|
|
22441
22547
|
let n = new Se(), r = new xe(process.env.WORKER_NAME || "cli");
|
|
@@ -22450,13 +22556,13 @@ async function hw() {
|
|
|
22450
22556
|
});
|
|
22451
22557
|
break;
|
|
22452
22558
|
case "start-workers":
|
|
22453
|
-
console.log(`⚙️ Starting worker scheduler with ${e.workers} concurrent slot(s)...`), await r.init(),
|
|
22559
|
+
console.log(`⚙️ Starting worker scheduler with ${e.workers} concurrent slot(s)...`), await r.init(), HC(e.workers, r, n, e);
|
|
22454
22560
|
break;
|
|
22455
22561
|
case "start-scheduler": {
|
|
22456
22562
|
console.log("Starting workflow scheduler..."), await r.init();
|
|
22457
22563
|
let t = new SC();
|
|
22458
22564
|
await t.init();
|
|
22459
|
-
let n = new
|
|
22565
|
+
let n = new hw(r, t, e);
|
|
22460
22566
|
n.start();
|
|
22461
22567
|
let i = () => {
|
|
22462
22568
|
n.stop(), process.exit(0);
|
|
@@ -22467,6 +22573,6 @@ async function hw() {
|
|
|
22467
22573
|
default: console.error(`❌ Unknown command: '${t}'`), he(), process.exit(1);
|
|
22468
22574
|
}
|
|
22469
22575
|
}
|
|
22470
|
-
|
|
22576
|
+
_w().catch(console.error);
|
|
22471
22577
|
//#endregion
|
|
22472
22578
|
export { MC as GitHubStatusPlugin, FC as createWorkflowPlugin, PC as registerWorkflowPlugin };
|
package/dist/queue.d.ts
CHANGED
|
@@ -54,6 +54,14 @@ export declare class QueueManager {
|
|
|
54
54
|
path: string;
|
|
55
55
|
content: string;
|
|
56
56
|
}>>;
|
|
57
|
+
updateWorkerPresence(worker: {
|
|
58
|
+
id: string;
|
|
59
|
+
version: string;
|
|
60
|
+
tags: string[];
|
|
61
|
+
concurrency: number;
|
|
62
|
+
activeJobs: number;
|
|
63
|
+
}): Promise<void>;
|
|
64
|
+
listWorkerPresence(): Promise<any[]>;
|
|
57
65
|
saveAiRequest(jobId: string | number, workflowUrl: string, request: unknown): Promise<void>;
|
|
58
66
|
}
|
|
59
67
|
//# sourceMappingURL=queue.d.ts.map
|
package/dist/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvF,qBAAa,YAAY;IAGX,OAAO,CAAC,QAAQ;IAF5B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAE7B,QAAQ,EAAE,MAAM;IAE9B,IAAI;IAKV;;;OAGG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,GAAE,MAAM,EAAO,EAAE,cAAc,CAAC,EAAE,MAAM;IAoBrI;;;OAGG;IACG,YAAY,CAAC,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA6BlE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS;IAInD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;IAapF,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAiCnF;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKrD,cAAc;IAMd,YAAY;
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvF,qBAAa,YAAY;IAGX,OAAO,CAAC,QAAQ;IAF5B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAE7B,QAAQ,EAAE,MAAM;IAE9B,IAAI;IAKV;;;OAGG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,GAAE,MAAM,EAAO,EAAE,cAAc,CAAC,EAAE,MAAM;IAoBrI;;;OAGG;IACG,YAAY,CAAC,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA6BlE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS;IAInD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;IAapF,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAiCnF;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKrD,cAAc;IAMd,YAAY;IAyDlB;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAIlD;;OAEG;IACG,QAAQ,CAAC,KAAK,SAAK,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAkCrH;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxF,2DAA2D;IACrD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5F;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAUnE,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7H,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAK/G,oBAAoB,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrI,kBAAkB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAapC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlG"}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAc,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAOxF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,eAAe,CAAgB;WAE1B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;gBAK1D,OAAO,EAAE,oBAAoB;IAazC,oBAAoB,CAAC,YAAY,EAAE,mBAAmB;YAIxC,aAAa;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAc,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAOxF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,eAAe,CAAgB;WAE1B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;gBAK1D,OAAO,EAAE,oBAAoB;IAazC,oBAAoB,CAAC,YAAY,EAAE,mBAAmB;YAIxC,aAAa;IAkQ3B;;OAEG;YACW,aAAa;YA0Bb,cAAc;YASd,aAAa;YAiBb,iBAAiB;YA0BjB,WAAW;YAwBX,UAAU;YAyBV,cAAc;IA8C5B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,QAAQ;YAIF,QAAQ;YAQR,YAAY;IAO1B,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,YAAY;YAUN,QAAQ;YAYR,wBAAwB;YAcxB,kBAAkB;YAOlB,iBAAiB;YAcjB,kBAAkB;YAoBlB,oBAAoB;YASpB,qBAAqB;YAWrB,gBAAgB;YAMhB,gBAAgB;YAiBhB,kBAAkB;YASlB,gBAAgB;IAc9B;;OAEG;YACW,kBAAkB;YAclB,iBAAiB;IA2B/B,OAAO,CAAC,mBAAmB;YASb,mBAAmB;YAWnB,qBAAqB;IAWnC;;OAEG;YACW,eAAe;IAK7B,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,mBAAmB;YAcb,mBAAmB;IAwBjC;;OAEG;YACW,gBAAgB;YA+BhB,gBAAgB;YAiBhB,sBAAsB;YAetB,YAAY;YAsDZ,oBAAoB;YA4BpB,eAAe;YAkBf,cAAc;IAS5B,OAAO,CAAC,MAAM;YAMA,UAAU;IAIlB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAU5C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAS5B"}
|
package/dist/settings-ui.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function generateSettingsHtml(page?: 'tokens' | 'notifications'): string;
|
|
1
|
+
export declare function generateSettingsHtml(page?: 'tokens' | 'notifications' | 'workers'): string;
|
|
2
2
|
//# sourceMappingURL=settings-ui.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-ui.d.ts","sourceRoot":"","sources":["../src/settings-ui.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"settings-ui.d.ts","sourceRoot":"","sources":["../src/settings-ui.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,QAAQ,GAAG,eAAe,GAAG,SAAoB,GAAG,MAAM,CAEpG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,QAAsB,CAAC"}
|
package/dist/worker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,YAAY,EAOZ,WAAW,EAKZ,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,YAAY,EAOZ,WAAW,EAKZ,MAAM,YAAY,CAAC;AAUpB,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAMF;;GAEG;AACH,wBAAsB,qBAAqB,kBAK1C;AAED,wBAAgB,qBAAqB,SAIpC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,mBAK1G;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,YAAY,iBA8ErB;AAqHD;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,WAAW,iBAmI9C"}
|