@kohala/devkit 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/CHANGELOG.md +23 -0
- package/dist/cli/index.js +77 -27
- package/dist/cli/index.js.map +1 -1
- package/docs/DEPLOY.md +8 -0
- package/docs/MANIFEST.md +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @kohala/devkit
|
|
2
2
|
|
|
3
|
+
## 0.1.7
|
|
4
|
+
|
|
5
|
+
- **BUG-006 fixed: `kohala deploy --run` no longer misreports every 409 as
|
|
6
|
+
"agent not enabled".** The platform returns two distinct 409s for a manual
|
|
7
|
+
run: agent disabled, and `nothing_to_run` (no script bound to an active
|
|
8
|
+
cron schedule — the case a fresh schedule-less scaffold always hits, even
|
|
9
|
+
after enabling the agent). The CLI now tells them apart and gives the
|
|
10
|
+
right fix for each: enable the agent in the dashboard, or add a
|
|
11
|
+
`schedule` to kohala.json so deploy binds the scripts. Verified live that
|
|
12
|
+
enabling an agent survives redeploys (the upsert does not reset it).
|
|
13
|
+
DEPLOY.md documents both cases.
|
|
14
|
+
|
|
15
|
+
## 0.1.6
|
|
16
|
+
|
|
17
|
+
- **BUG-077 fixed: a deployed agent with a manifest schedule can now actually
|
|
18
|
+
run.** Setting `agentScheduleCron` (0.1.5 / BUG-069) enabled the schedule
|
|
19
|
+
but bound no script to it — `agentScheduleEntries` stayed null and every
|
|
20
|
+
run 409'd with `nothing_to_run`. Deploy now sets the schedule *after*
|
|
21
|
+
uploading the skills and binds every skill script to the cron via
|
|
22
|
+
`agentScheduleEntries` (`{scriptFilename, schedule}` per skill), then
|
|
23
|
+
verifies the cron, the enabled flag, and every binding round-tripped —
|
|
24
|
+
failing loudly if any script would be left unbound.
|
|
25
|
+
|
|
3
26
|
## 0.1.5
|
|
4
27
|
|
|
5
28
|
- **BUG-069 fixed: the manifest `schedule` now actually lands on the
|
package/dist/cli/index.js
CHANGED
|
@@ -2258,6 +2258,11 @@ function buildDeployPlan(manifest, agentDir) {
|
|
|
2258
2258
|
code: fs12.readFileSync(scriptPath, "utf8")
|
|
2259
2259
|
};
|
|
2260
2260
|
});
|
|
2261
|
+
if (manifest.schedule && skills.length === 0) {
|
|
2262
|
+
throw new Error(
|
|
2263
|
+
`Manifest has a schedule ("${manifest.schedule}") but no skills \u2014 the platform would have nothing to run on that schedule (every run fails with nothing_to_run). Add at least one skill or remove the schedule.`
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2261
2266
|
return {
|
|
2262
2267
|
agent: {
|
|
2263
2268
|
name: manifest.name,
|
|
@@ -2283,6 +2288,12 @@ var DeployError = class extends Error {
|
|
|
2283
2288
|
}
|
|
2284
2289
|
status;
|
|
2285
2290
|
};
|
|
2291
|
+
function classifyManualRun409(error) {
|
|
2292
|
+
if (error.status !== 409) return "other";
|
|
2293
|
+
if (/nothing_to_run|would execute nothing/i.test(error.message)) return "nothing_to_run";
|
|
2294
|
+
if (/not enabled/i.test(error.message)) return "disabled";
|
|
2295
|
+
return "other";
|
|
2296
|
+
}
|
|
2286
2297
|
var KohalaClient = class {
|
|
2287
2298
|
constructor(apiKey, baseUrl = DEFAULT_BASE_URL) {
|
|
2288
2299
|
this.apiKey = apiKey;
|
|
@@ -2348,15 +2359,24 @@ var KohalaClient = class {
|
|
|
2348
2359
|
* schedule explicitly and verifies it round-tripped. Never called without
|
|
2349
2360
|
* a schedule — deploy is additive and must not disable existing schedules.
|
|
2350
2361
|
*/
|
|
2351
|
-
async setSchedule(agentId, cron) {
|
|
2362
|
+
async setSchedule(agentId, cron, scriptFilenames) {
|
|
2363
|
+
const entries = scriptFilenames.map((scriptFilename) => ({
|
|
2364
|
+
scriptFilename,
|
|
2365
|
+
schedule: cron
|
|
2366
|
+
}));
|
|
2352
2367
|
const data = await this.request("PATCH", `/api/v1/agents/${agentId}`, {
|
|
2353
2368
|
agentScheduleCron: cron,
|
|
2354
|
-
agentScheduleEnabled: true
|
|
2369
|
+
agentScheduleEnabled: true,
|
|
2370
|
+
agentScheduleEntries: entries
|
|
2355
2371
|
});
|
|
2356
|
-
|
|
2372
|
+
const boundFilenames = new Set(
|
|
2373
|
+
(data?.agentScheduleEntries ?? []).filter((entry) => entry.schedule === cron).map((entry) => entry.scriptFilename)
|
|
2374
|
+
);
|
|
2375
|
+
const allBound = scriptFilenames.length > 0 && scriptFilenames.every((filename) => boundFilenames.has(filename));
|
|
2376
|
+
if (data?.agentScheduleCron !== cron || data?.agentScheduleEnabled !== true || !allBound) {
|
|
2357
2377
|
throw new DeployError(
|
|
2358
2378
|
500,
|
|
2359
|
-
`Platform did not persist the schedule "${cron}" (got agentScheduleCron=${JSON.stringify(data?.agentScheduleCron)}, agentScheduleEnabled=${JSON.stringify(data?.agentScheduleEnabled)}) \u2014
|
|
2379
|
+
`Platform did not persist the schedule "${cron}" (got agentScheduleCron=${JSON.stringify(data?.agentScheduleCron)}, agentScheduleEnabled=${JSON.stringify(data?.agentScheduleEnabled)}, agentScheduleEntries=${JSON.stringify(data?.agentScheduleEntries ?? null)}) \u2014 the deployed agent's scripts would not be bound to the schedule. Aborting.`
|
|
2360
2380
|
);
|
|
2361
2381
|
}
|
|
2362
2382
|
}
|
|
@@ -2383,26 +2403,34 @@ function registerDeployCommand(program2) {
|
|
|
2383
2403
|
console.log("");
|
|
2384
2404
|
console.log(pc8.bold("1. POST /api/v1/agents (idempotent on name)"));
|
|
2385
2405
|
console.log(JSON.stringify(plan.agent, null, 2));
|
|
2386
|
-
|
|
2406
|
+
for (const skill of plan.skills) {
|
|
2387
2407
|
console.log("");
|
|
2388
|
-
console.log(pc8.bold(
|
|
2408
|
+
console.log(pc8.bold(`2. POST /api/v1/agents/:id/skills \u2014 "${skill.name}"`));
|
|
2389
2409
|
console.log(
|
|
2390
2410
|
JSON.stringify(
|
|
2391
|
-
{
|
|
2392
|
-
agentScheduleCron: plan.agent.agentScheduleCron,
|
|
2393
|
-
agentScheduleEnabled: true
|
|
2394
|
-
},
|
|
2411
|
+
{ ...skill, code: `<${Buffer.byteLength(skill.code)} bytes of ${skill.scriptFilename}>` },
|
|
2395
2412
|
null,
|
|
2396
2413
|
2
|
|
2397
2414
|
)
|
|
2398
2415
|
);
|
|
2399
2416
|
}
|
|
2400
|
-
|
|
2417
|
+
if (plan.agent.agentScheduleCron) {
|
|
2401
2418
|
console.log("");
|
|
2402
|
-
console.log(
|
|
2419
|
+
console.log(
|
|
2420
|
+
pc8.bold(
|
|
2421
|
+
"2b. PATCH /api/v1/agents/:id (persist schedule + bind scripts, after skills upload)"
|
|
2422
|
+
)
|
|
2423
|
+
);
|
|
2403
2424
|
console.log(
|
|
2404
2425
|
JSON.stringify(
|
|
2405
|
-
{
|
|
2426
|
+
{
|
|
2427
|
+
agentScheduleCron: plan.agent.agentScheduleCron,
|
|
2428
|
+
agentScheduleEnabled: true,
|
|
2429
|
+
agentScheduleEntries: plan.skills.map((skill) => ({
|
|
2430
|
+
scriptFilename: skill.scriptFilename,
|
|
2431
|
+
schedule: plan.agent.agentScheduleCron
|
|
2432
|
+
}))
|
|
2433
|
+
},
|
|
2406
2434
|
null,
|
|
2407
2435
|
2
|
|
2408
2436
|
)
|
|
@@ -2429,14 +2457,19 @@ function registerDeployCommand(program2) {
|
|
|
2429
2457
|
console.log(
|
|
2430
2458
|
pc8.green(` \u2714 agent ${upserted.created ? "created" : "updated"} (id ${upserted.id})`)
|
|
2431
2459
|
);
|
|
2432
|
-
if (plan.agent.agentScheduleCron) {
|
|
2433
|
-
await client.setSchedule(upserted.id, plan.agent.agentScheduleCron);
|
|
2434
|
-
console.log(pc8.green(` \u2714 schedule set (${plan.agent.agentScheduleCron})`));
|
|
2435
|
-
}
|
|
2436
2460
|
for (const skill of plan.skills) {
|
|
2437
2461
|
await client.upsertSkill(upserted.id, skill);
|
|
2438
2462
|
console.log(pc8.green(` \u2714 skill "${skill.name}" uploaded (${skill.scriptFilename})`));
|
|
2439
2463
|
}
|
|
2464
|
+
if (plan.agent.agentScheduleCron) {
|
|
2465
|
+
const filenames = plan.skills.map((skill) => skill.scriptFilename);
|
|
2466
|
+
await client.setSchedule(upserted.id, plan.agent.agentScheduleCron, filenames);
|
|
2467
|
+
console.log(
|
|
2468
|
+
pc8.green(
|
|
2469
|
+
` \u2714 schedule set (${plan.agent.agentScheduleCron}, bound: ${filenames.join(", ")})`
|
|
2470
|
+
)
|
|
2471
|
+
);
|
|
2472
|
+
}
|
|
2440
2473
|
await client.setQuota(upserted.id, plan.quota);
|
|
2441
2474
|
console.log(
|
|
2442
2475
|
pc8.green(
|
|
@@ -2449,16 +2482,33 @@ function registerDeployCommand(program2) {
|
|
|
2449
2482
|
console.log(pc8.green(` \u2714 manual run triggered: ${runUrl}`));
|
|
2450
2483
|
} catch (error) {
|
|
2451
2484
|
if (error instanceof DeployError && error.status === 409) {
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2485
|
+
const reason = classifyManualRun409(error);
|
|
2486
|
+
if (reason === "nothing_to_run") {
|
|
2487
|
+
console.error(
|
|
2488
|
+
pc8.yellow(
|
|
2489
|
+
` \u2716 manual run not started: no script is bound to an active schedule, so a run would execute nothing.`
|
|
2490
|
+
)
|
|
2491
|
+
);
|
|
2492
|
+
console.error(
|
|
2493
|
+
pc8.dim(
|
|
2494
|
+
` Deploy itself succeeded. The platform only runs scripts bound to a cron schedule: add e.g. "schedule": "0 9 * * *" to kohala.json, then re-run \`kohala deploy ${agent} --run\` \u2014 deploy binds every skill script to it.`
|
|
2495
|
+
)
|
|
2496
|
+
);
|
|
2497
|
+
} else if (reason === "disabled") {
|
|
2498
|
+
console.error(
|
|
2499
|
+
pc8.yellow(
|
|
2500
|
+
` \u2716 manual run not started: the agent is not enabled on the platform yet.`
|
|
2501
|
+
)
|
|
2502
|
+
);
|
|
2503
|
+
console.error(
|
|
2504
|
+
pc8.dim(
|
|
2505
|
+
` Deploy itself succeeded. Enable "${manifest.name}" in your kohala.ai dashboard, then re-run \`kohala deploy ${agent} --run\` (or trigger a run from the dashboard). Enabling survives redeploys.`
|
|
2506
|
+
)
|
|
2507
|
+
);
|
|
2508
|
+
} else {
|
|
2509
|
+
console.error(pc8.yellow(` \u2716 manual run not started (409).`));
|
|
2510
|
+
console.error(pc8.dim(` ${error.message}`));
|
|
2511
|
+
}
|
|
2462
2512
|
process.exitCode = 1;
|
|
2463
2513
|
return;
|
|
2464
2514
|
}
|