@kynver-app/runtime 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -2
- package/dist/cli.js +199 -38
- package/dist/cli.js.map +4 -4
- package/dist/index.js +199 -38
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -125,20 +125,112 @@ function saveUserConfig(config) {
|
|
|
125
125
|
writeFileSync2(CONFIG_FILE, `${JSON.stringify(config, null, 2)}
|
|
126
126
|
`, { mode: 384 });
|
|
127
127
|
}
|
|
128
|
-
function
|
|
128
|
+
function loadCredentialsFile() {
|
|
129
|
+
if (!existsSync2(CREDENTIALS_FILE)) return {};
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(readFileSync2(CREDENTIALS_FILE, "utf8"));
|
|
132
|
+
} catch {
|
|
133
|
+
return {};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function saveCredentialsFile(parsed) {
|
|
129
137
|
mkdirSync2(CONFIG_DIR, { recursive: true });
|
|
130
|
-
writeFileSync2(CREDENTIALS_FILE, `${JSON.stringify(
|
|
138
|
+
writeFileSync2(CREDENTIALS_FILE, `${JSON.stringify(parsed, null, 2)}
|
|
131
139
|
`, { mode: 384 });
|
|
132
140
|
}
|
|
141
|
+
function loadApiKey() {
|
|
142
|
+
if (process.env.KYNVER_API_KEY) return process.env.KYNVER_API_KEY;
|
|
143
|
+
return loadCredentialsFile().apiKey;
|
|
144
|
+
}
|
|
145
|
+
function saveApiKey(apiKey) {
|
|
146
|
+
saveCredentialsFile({ ...loadCredentialsFile(), apiKey });
|
|
147
|
+
}
|
|
148
|
+
function loadRunnerToken(agentOsId) {
|
|
149
|
+
const creds = loadCredentialsFile();
|
|
150
|
+
if (!creds.runnerToken) return void 0;
|
|
151
|
+
if (agentOsId && creds.runnerTokenAgentOsId && creds.runnerTokenAgentOsId !== agentOsId) {
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
return creds.runnerToken;
|
|
155
|
+
}
|
|
156
|
+
function saveRunnerToken(agentOsId, token) {
|
|
157
|
+
saveCredentialsFile({
|
|
158
|
+
...loadCredentialsFile(),
|
|
159
|
+
runnerToken: token,
|
|
160
|
+
runnerTokenAgentOsId: agentOsId
|
|
161
|
+
});
|
|
162
|
+
}
|
|
133
163
|
function resolveBaseUrl(argsBaseUrl) {
|
|
134
164
|
const baseUrl = argsBaseUrl || process.env.KYNVER_API_URL || process.env.OPENCLAW_CRON_FIRE_BASE_URL || loadUserConfig().apiBaseUrl;
|
|
135
165
|
if (!baseUrl) failConfig("requires --base-url, KYNVER_API_URL, OPENCLAW_CRON_FIRE_BASE_URL, or ~/.kynver/config.json apiBaseUrl");
|
|
136
166
|
return trimTrailingSlash(String(baseUrl));
|
|
137
167
|
}
|
|
138
|
-
function resolveCallbackSecret(argsSecret) {
|
|
139
|
-
const
|
|
140
|
-
if (
|
|
141
|
-
|
|
168
|
+
function resolveCallbackSecret(argsSecret, agentOsId) {
|
|
169
|
+
const scoped = argsSecret || loadRunnerToken(agentOsId) || loadRunnerToken(loadUserConfig().agentOsId);
|
|
170
|
+
if (scoped) return String(scoped);
|
|
171
|
+
const globalSecret = process.env.KYNVER_RUNTIME_SECRET || process.env.OPENCLAW_CRON_SECRET;
|
|
172
|
+
if (globalSecret) {
|
|
173
|
+
console.warn(
|
|
174
|
+
"[kynver] using deployment-level callback secret; run `kynver runner credential --agent-os-id <id>` for a scoped token"
|
|
175
|
+
);
|
|
176
|
+
return String(globalSecret);
|
|
177
|
+
}
|
|
178
|
+
failConfig(
|
|
179
|
+
"requires --secret, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, or (legacy) KYNVER_RUNTIME_SECRET / OPENCLAW_CRON_SECRET"
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
async function fetchRunnerCredential(agentOsId, opts) {
|
|
183
|
+
const apiKey = opts?.apiKey || loadApiKey();
|
|
184
|
+
if (!apiKey) throw new Error("API key required \u2014 run `kynver login` first");
|
|
185
|
+
const base = resolveBaseUrl(opts?.baseUrl);
|
|
186
|
+
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/runner-credentials`;
|
|
187
|
+
const res = await fetch(url, {
|
|
188
|
+
method: "POST",
|
|
189
|
+
headers: {
|
|
190
|
+
"Content-Type": "application/json",
|
|
191
|
+
Authorization: `Bearer ${apiKey}`
|
|
192
|
+
},
|
|
193
|
+
body: JSON.stringify({})
|
|
194
|
+
});
|
|
195
|
+
const text = await res.text();
|
|
196
|
+
let parsed = null;
|
|
197
|
+
try {
|
|
198
|
+
parsed = JSON.parse(text);
|
|
199
|
+
} catch {
|
|
200
|
+
parsed = null;
|
|
201
|
+
}
|
|
202
|
+
if (!res.ok || !parsed?.token) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
`runner credential mint failed (${res.status}): ${parsed?.error ?? text.slice(0, 200)}`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
return parsed.token;
|
|
208
|
+
}
|
|
209
|
+
async function mintRunnerCredential(args) {
|
|
210
|
+
const agentOsId = (args.agentOsId ? String(args.agentOsId) : loadUserConfig().agentOsId) || "";
|
|
211
|
+
if (!agentOsId) failConfig("runner credential requires --agent-os-id or agentOsId in ~/.kynver/config.json");
|
|
212
|
+
try {
|
|
213
|
+
const token = await fetchRunnerCredential(agentOsId, {
|
|
214
|
+
baseUrl: args.baseUrl ? String(args.baseUrl) : void 0
|
|
215
|
+
});
|
|
216
|
+
saveRunnerToken(agentOsId, token);
|
|
217
|
+
console.log(
|
|
218
|
+
JSON.stringify(
|
|
219
|
+
{
|
|
220
|
+
ok: true,
|
|
221
|
+
agentOsId,
|
|
222
|
+
credentialsPath: CREDENTIALS_FILE,
|
|
223
|
+
tokenPrefix: `${token.slice(0, 12)}\u2026`,
|
|
224
|
+
note: "Scoped runner token saved; callbacks use X-Kynver-Runner-Token."
|
|
225
|
+
},
|
|
226
|
+
null,
|
|
227
|
+
2
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
} catch (err) {
|
|
231
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
142
234
|
}
|
|
143
235
|
function failConfig(message) {
|
|
144
236
|
console.error(message);
|
|
@@ -173,13 +265,28 @@ async function runSetup(args) {
|
|
|
173
265
|
workerProvider: typeof args.provider === "string" ? args.provider : existing.workerProvider || "claude"
|
|
174
266
|
};
|
|
175
267
|
saveUserConfig(config);
|
|
268
|
+
let runnerCredentialNote;
|
|
269
|
+
const apiKey = loadApiKey();
|
|
270
|
+
const agentOsId = config.agentOsId;
|
|
271
|
+
if (apiKey && agentOsId) {
|
|
272
|
+
try {
|
|
273
|
+
const token = await fetchRunnerCredential(agentOsId, {
|
|
274
|
+
baseUrl: typeof args.apiBaseUrl === "string" ? args.apiBaseUrl : config.apiBaseUrl,
|
|
275
|
+
apiKey
|
|
276
|
+
});
|
|
277
|
+
saveRunnerToken(agentOsId, token);
|
|
278
|
+
runnerCredentialNote = "Scoped runner token minted and saved to ~/.kynver/credentials.";
|
|
279
|
+
} catch {
|
|
280
|
+
runnerCredentialNote = "Runner token not minted (server offline or master secret unset). Run `kynver runner credential` after deploy.";
|
|
281
|
+
}
|
|
282
|
+
}
|
|
176
283
|
console.log(
|
|
177
284
|
JSON.stringify(
|
|
178
285
|
{
|
|
179
286
|
ok: true,
|
|
180
287
|
configPath: CONFIG_FILE,
|
|
181
288
|
config,
|
|
182
|
-
note: "Set worker limit once with --max-workers N (or omit to auto-size from RAM).
|
|
289
|
+
note: runnerCredentialNote ?? "Set worker limit once with --max-workers N (or omit to auto-size from RAM). Run `kynver login` + `kynver runner credential` for scoped callbacks."
|
|
183
290
|
},
|
|
184
291
|
null,
|
|
185
292
|
2
|
|
@@ -193,15 +300,27 @@ async function runLogin(args) {
|
|
|
193
300
|
console.log(JSON.stringify({ ok: true, credentialsPath: CREDENTIALS_FILE }, null, 2));
|
|
194
301
|
}
|
|
195
302
|
|
|
303
|
+
// src/callback-headers.ts
|
|
304
|
+
function buildHarnessCallbackHeaders(secret) {
|
|
305
|
+
const trimmed = String(secret).trim();
|
|
306
|
+
if (trimmed.startsWith("krc1.")) {
|
|
307
|
+
return {
|
|
308
|
+
"Content-Type": "application/json",
|
|
309
|
+
"X-Kynver-Runner-Token": trimmed
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
"Content-Type": "application/json",
|
|
314
|
+
"X-OpenClaw-Cron-Secret": trimmed,
|
|
315
|
+
"X-Kynver-Runtime-Secret": trimmed
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
196
319
|
// src/callbacks.ts
|
|
197
320
|
async function postJson(url, secret, body) {
|
|
198
321
|
const res = await fetch(url, {
|
|
199
322
|
method: "POST",
|
|
200
|
-
headers:
|
|
201
|
-
"Content-Type": "application/json",
|
|
202
|
-
"X-OpenClaw-Cron-Secret": String(secret),
|
|
203
|
-
"X-Kynver-Runtime-Secret": String(secret)
|
|
204
|
-
},
|
|
323
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
205
324
|
body: JSON.stringify(body)
|
|
206
325
|
});
|
|
207
326
|
let response = null;
|
|
@@ -215,10 +334,7 @@ async function postJson(url, secret, body) {
|
|
|
215
334
|
async function getJson(url, secret) {
|
|
216
335
|
const res = await fetch(url, {
|
|
217
336
|
method: "GET",
|
|
218
|
-
headers:
|
|
219
|
-
"X-OpenClaw-Cron-Secret": String(secret),
|
|
220
|
-
"X-Kynver-Runtime-Secret": String(secret)
|
|
221
|
-
}
|
|
337
|
+
headers: buildHarnessCallbackHeaders(secret)
|
|
222
338
|
});
|
|
223
339
|
let response = null;
|
|
224
340
|
try {
|
|
@@ -236,12 +352,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
|
236
352
|
var DEFAULT_MAX_USED_PERCENT = 80;
|
|
237
353
|
var DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
238
354
|
function observeRunnerDiskGate(input = {}) {
|
|
239
|
-
const
|
|
355
|
+
const path15 = input.diskPath?.trim() || "/";
|
|
240
356
|
const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
|
|
241
357
|
const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
|
|
242
358
|
const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
|
|
243
359
|
const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
|
|
244
|
-
const stats = statfsSync(
|
|
360
|
+
const stats = statfsSync(path15);
|
|
245
361
|
const freeBytes = Number(stats.bavail) * Number(stats.bsize);
|
|
246
362
|
const totalBytes = Number(stats.blocks) * Number(stats.bsize);
|
|
247
363
|
const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
|
|
@@ -261,7 +377,7 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
261
377
|
}
|
|
262
378
|
return {
|
|
263
379
|
ok,
|
|
264
|
-
path:
|
|
380
|
+
path: path15,
|
|
265
381
|
freeBytes,
|
|
266
382
|
totalBytes,
|
|
267
383
|
usedPercent,
|
|
@@ -867,6 +983,7 @@ function spawnWorkerProcess(run, opts) {
|
|
|
867
983
|
ownedPaths: opts.ownedPaths,
|
|
868
984
|
...opts.agentOsId ? { agentOsId: String(opts.agentOsId) } : {},
|
|
869
985
|
...opts.taskId ? { taskId: String(opts.taskId) } : {},
|
|
986
|
+
...opts.planId ? { planId: String(opts.planId) } : {},
|
|
870
987
|
...opts.leaseOwner ? { leaseOwner: String(opts.leaseOwner) } : {},
|
|
871
988
|
...opts.dispatched ? { dispatched: true } : {},
|
|
872
989
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -933,7 +1050,7 @@ async function dispatchRun(args) {
|
|
|
933
1050
|
const run = loadRun(String(required(String(args.run || ""), "--run")));
|
|
934
1051
|
const agentOsId = String(required(String(args.agentOsId || ""), "--agent-os-id"));
|
|
935
1052
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
936
|
-
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0);
|
|
1053
|
+
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0, agentOsId);
|
|
937
1054
|
const execute = args.execute === true || args.execute === "true";
|
|
938
1055
|
const dryRun = !execute;
|
|
939
1056
|
const leaseOwner = `openclaw-harness:${run.id}`;
|
|
@@ -1007,6 +1124,7 @@ async function dispatchRun(args) {
|
|
|
1007
1124
|
const task = decision.task;
|
|
1008
1125
|
const name = safeSlug(`t-${task.id}-a${task.attempt}`);
|
|
1009
1126
|
try {
|
|
1127
|
+
const planId = task.planId ? String(task.planId) : void 0;
|
|
1010
1128
|
const worker = spawnWorkerProcess(run, {
|
|
1011
1129
|
name,
|
|
1012
1130
|
task: buildDispatchTaskText(task, agentOsId),
|
|
@@ -1014,6 +1132,7 @@ async function dispatchRun(args) {
|
|
|
1014
1132
|
model: args.model ? String(args.model) : void 0,
|
|
1015
1133
|
agentOsId,
|
|
1016
1134
|
taskId: String(task.id),
|
|
1135
|
+
planId,
|
|
1017
1136
|
leaseOwner,
|
|
1018
1137
|
dispatched: true
|
|
1019
1138
|
});
|
|
@@ -1159,7 +1278,7 @@ async function sweepRun(args) {
|
|
|
1159
1278
|
const run = loadRun(String(required(String(args.run || ""), "--run")));
|
|
1160
1279
|
const agentOsId = String(required(String(args.agentOsId || ""), "--agent-os-id"));
|
|
1161
1280
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
1162
|
-
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0);
|
|
1281
|
+
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0, agentOsId);
|
|
1163
1282
|
const leaseOwner = `openclaw-harness:${run.id}`;
|
|
1164
1283
|
const releasedLocalOrphans = [];
|
|
1165
1284
|
for (const name of Object.keys(run.workers || {})) {
|
|
@@ -1220,7 +1339,7 @@ async function tryCompleteWorker(args) {
|
|
|
1220
1339
|
return { ok: true, skipped: true, reason: "worker-not-finished" };
|
|
1221
1340
|
}
|
|
1222
1341
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
1223
|
-
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0);
|
|
1342
|
+
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0, agentOsId);
|
|
1224
1343
|
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/harness/completion`;
|
|
1225
1344
|
const body = {
|
|
1226
1345
|
source: "openclaw-harness",
|
|
@@ -1234,11 +1353,7 @@ async function tryCompleteWorker(args) {
|
|
|
1234
1353
|
};
|
|
1235
1354
|
const res = await fetch(url, {
|
|
1236
1355
|
method: "POST",
|
|
1237
|
-
headers:
|
|
1238
|
-
"Content-Type": "application/json",
|
|
1239
|
-
"X-OpenClaw-Cron-Secret": secret,
|
|
1240
|
-
"X-Kynver-Runtime-Secret": secret
|
|
1241
|
-
},
|
|
1356
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
1242
1357
|
body: JSON.stringify(body)
|
|
1243
1358
|
});
|
|
1244
1359
|
let parsed = null;
|
|
@@ -1374,16 +1489,61 @@ function stopWorker(args) {
|
|
|
1374
1489
|
|
|
1375
1490
|
// src/cli.ts
|
|
1376
1491
|
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
1377
|
-
import
|
|
1492
|
+
import path14 from "node:path";
|
|
1378
1493
|
import { fileURLToPath } from "node:url";
|
|
1379
1494
|
|
|
1380
1495
|
// src/pipeline-tick.ts
|
|
1496
|
+
import path13 from "node:path";
|
|
1497
|
+
|
|
1498
|
+
// src/plan-progress-daemon-sync.ts
|
|
1381
1499
|
import path12 from "node:path";
|
|
1382
1500
|
|
|
1501
|
+
// src/plan-progress-sync.ts
|
|
1502
|
+
async function syncPlanProgress(args) {
|
|
1503
|
+
const base = resolveBaseUrl(args.baseUrl);
|
|
1504
|
+
const secret = resolveCallbackSecret(args.secret);
|
|
1505
|
+
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(args.agentOsId)}/tasks/${encodeURIComponent(args.taskId)}/plan-progress-sync`;
|
|
1506
|
+
const res = await postJson(url, secret, {
|
|
1507
|
+
phase: args.phase,
|
|
1508
|
+
taskId: args.taskId,
|
|
1509
|
+
blocker: args.blocker,
|
|
1510
|
+
artifact: args.artifact
|
|
1511
|
+
});
|
|
1512
|
+
return { ok: res.ok, status: res.status, response: res.response };
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// src/plan-progress-daemon-sync.ts
|
|
1516
|
+
async function syncActiveWorkerPlanProgress(runId, args) {
|
|
1517
|
+
const run = loadRun(runId);
|
|
1518
|
+
const agentOsId = String(args.agentOsId || "");
|
|
1519
|
+
if (!agentOsId) return [];
|
|
1520
|
+
const outcomes = [];
|
|
1521
|
+
for (const name of Object.keys(run.workers || {})) {
|
|
1522
|
+
const worker = readJson(
|
|
1523
|
+
path12.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
1524
|
+
null
|
|
1525
|
+
);
|
|
1526
|
+
if (!worker?.dispatched || !worker.taskId) continue;
|
|
1527
|
+
const status = computeWorkerStatus(worker);
|
|
1528
|
+
if (status.heartbeatBlocker) {
|
|
1529
|
+
const res = await syncPlanProgress({
|
|
1530
|
+
agentOsId,
|
|
1531
|
+
taskId: worker.taskId,
|
|
1532
|
+
phase: "heartbeat_blocker",
|
|
1533
|
+
blocker: status.heartbeatBlocker,
|
|
1534
|
+
baseUrl: args.baseUrl ? String(args.baseUrl) : void 0,
|
|
1535
|
+
secret: args.secret ? String(args.secret) : void 0
|
|
1536
|
+
});
|
|
1537
|
+
outcomes.push({ worker: name, phase: "heartbeat_blocker", ok: res.ok });
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
return outcomes;
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1383
1543
|
// src/workspace-runtime-config.ts
|
|
1384
1544
|
async function fetchWorkspaceRuntimePreferences(agentOsId, args) {
|
|
1385
1545
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
1386
|
-
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0);
|
|
1546
|
+
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0, agentOsId);
|
|
1387
1547
|
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/runtime`;
|
|
1388
1548
|
try {
|
|
1389
1549
|
const res = await getJson(url, secret);
|
|
@@ -1407,7 +1567,7 @@ async function completeFinishedWorkers(runId, args) {
|
|
|
1407
1567
|
const outcomes = [];
|
|
1408
1568
|
for (const name of Object.keys(run.workers || {})) {
|
|
1409
1569
|
const worker = readJson(
|
|
1410
|
-
|
|
1570
|
+
path13.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
1411
1571
|
null
|
|
1412
1572
|
);
|
|
1413
1573
|
if (!worker?.dispatched || !worker.taskId) continue;
|
|
@@ -1426,7 +1586,7 @@ async function completeFinishedWorkers(runId, args) {
|
|
|
1426
1586
|
}
|
|
1427
1587
|
async function postOperatorTick(agentOsId, runId, resourceGate, args) {
|
|
1428
1588
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
1429
|
-
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0);
|
|
1589
|
+
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0, agentOsId);
|
|
1430
1590
|
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/operator/tick`;
|
|
1431
1591
|
const res = await postJson(url, secret, {
|
|
1432
1592
|
agentOsId,
|
|
@@ -1442,6 +1602,7 @@ async function runPipelineTick(args) {
|
|
|
1442
1602
|
const execute = args.execute !== false && args.execute !== "false";
|
|
1443
1603
|
runStatus({ run: runId });
|
|
1444
1604
|
const completedWorkers = await completeFinishedWorkers(runId, args);
|
|
1605
|
+
const planProgressSync = await syncActiveWorkerPlanProgress(runId, args);
|
|
1445
1606
|
const workspacePrefs = await fetchWorkspaceRuntimePreferences(agentOsId, args);
|
|
1446
1607
|
const resourceGate = observeRunnerResourceGate({
|
|
1447
1608
|
runId,
|
|
@@ -1481,6 +1642,7 @@ async function runPipelineTick(args) {
|
|
|
1481
1642
|
execute,
|
|
1482
1643
|
resourceGate,
|
|
1483
1644
|
completedWorkers,
|
|
1645
|
+
planProgressSync,
|
|
1484
1646
|
operatorTick,
|
|
1485
1647
|
sweep,
|
|
1486
1648
|
dispatch,
|
|
@@ -1548,7 +1710,7 @@ async function emitPlanProgress(args) {
|
|
|
1548
1710
|
evidence.push(parseEvidenceArg(rawEvidence));
|
|
1549
1711
|
}
|
|
1550
1712
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
1551
|
-
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0);
|
|
1713
|
+
const secret = resolveCallbackSecret(args.secret ? String(args.secret) : void 0, agentOsId);
|
|
1552
1714
|
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/plans/${encodeURIComponent(planId)}/progress-events`;
|
|
1553
1715
|
const cfg = loadUserConfig();
|
|
1554
1716
|
const provider = cfg.workerProvider ? `provider:${cfg.workerProvider}` : void 0;
|
|
@@ -1567,10 +1729,7 @@ async function emitPlanProgress(args) {
|
|
|
1567
1729
|
};
|
|
1568
1730
|
const res = await fetch(url, {
|
|
1569
1731
|
method: "POST",
|
|
1570
|
-
headers:
|
|
1571
|
-
"Content-Type": "application/json",
|
|
1572
|
-
"X-OpenClaw-Cron-Secret": secret
|
|
1573
|
-
},
|
|
1732
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
1574
1733
|
body: JSON.stringify(body)
|
|
1575
1734
|
});
|
|
1576
1735
|
const text = await res.text();
|
|
@@ -1636,6 +1795,7 @@ function usage(code = 0) {
|
|
|
1636
1795
|
[
|
|
1637
1796
|
"Usage:",
|
|
1638
1797
|
" kynver login --api-key KEY",
|
|
1798
|
+
" kynver runner credential [--agent-os-id ID] [--base-url URL]",
|
|
1639
1799
|
" kynver setup [--api-base-url URL] [--agent-os-id ID] [--agent-os-slug SLUG] [--repo PATH] [--max-workers N] [--provider claude|cursor]",
|
|
1640
1800
|
" kynver daemon --run RUN_ID --agent-os-id AOS_ID [--execute] [--interval-ms MS]",
|
|
1641
1801
|
" kynver run create --repo /path/repo [--name name] [--base origin/main]",
|
|
@@ -1659,7 +1819,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1659
1819
|
const scope = argv.shift();
|
|
1660
1820
|
let action;
|
|
1661
1821
|
let rest;
|
|
1662
|
-
if (scope === "run" || scope === "worker" || scope === "plan") {
|
|
1822
|
+
if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner") {
|
|
1663
1823
|
action = argv.shift();
|
|
1664
1824
|
rest = argv;
|
|
1665
1825
|
} else {
|
|
@@ -1670,6 +1830,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1670
1830
|
mkdirSync5(runsDir, { recursive: true });
|
|
1671
1831
|
mkdirSync5(worktreesDir, { recursive: true });
|
|
1672
1832
|
if (scope === "login") return void await runLogin(args);
|
|
1833
|
+
if (scope === "runner" && action === "credential") return void await mintRunnerCredential(args);
|
|
1673
1834
|
if (scope === "setup") return void await runSetup(args);
|
|
1674
1835
|
if (scope === "daemon") return void await runDaemon(args);
|
|
1675
1836
|
if (scope === "plan" && action === "progress") return void await emitPlanProgress(args);
|
|
@@ -1686,7 +1847,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1686
1847
|
if (scope === "worker" && action === "complete") return void await completeWorker(args);
|
|
1687
1848
|
unknownCommand(scope, action);
|
|
1688
1849
|
}
|
|
1689
|
-
var isCliEntry = process.argv[1] &&
|
|
1850
|
+
var isCliEntry = process.argv[1] && path14.resolve(process.argv[1]) === path14.resolve(fileURLToPath(import.meta.url));
|
|
1690
1851
|
if (isCliEntry) {
|
|
1691
1852
|
void main().catch((error) => {
|
|
1692
1853
|
console.error(error);
|