@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 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
- if (data?.agentScheduleCron !== cron || data?.agentScheduleEnabled !== true) {
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 aborting.`
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
- if (plan.agent.agentScheduleCron) {
2406
+ for (const skill of plan.skills) {
2387
2407
  console.log("");
2388
- console.log(pc8.bold("1b. PATCH /api/v1/agents/:id (persist schedule on updates)"));
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
- for (const skill of plan.skills) {
2417
+ if (plan.agent.agentScheduleCron) {
2401
2418
  console.log("");
2402
- console.log(pc8.bold(`2. POST /api/v1/agents/:id/skills \u2014 "${skill.name}"`));
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
- { ...skill, code: `<${Buffer.byteLength(skill.code)} bytes of ${skill.scriptFilename}>` },
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
- console.error(
2453
- pc8.yellow(
2454
- ` \u2716 manual run not started: the agent is not enabled on the platform yet.`
2455
- )
2456
- );
2457
- console.error(
2458
- pc8.dim(
2459
- ` 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).`
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
  }