@kody-ade/kody-engine 0.4.204-next.3 → 0.4.204-next.4
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/bin/kody.js +74 -1
- package/dist/executables/types.ts +8 -0
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -1483,7 +1483,7 @@ var init_loadCoverageRules = __esm({
|
|
|
1483
1483
|
// package.json
|
|
1484
1484
|
var package_default = {
|
|
1485
1485
|
name: "@kody-ade/kody-engine",
|
|
1486
|
-
version: "0.4.204-next.
|
|
1486
|
+
version: "0.4.204-next.4",
|
|
1487
1487
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
1488
1488
|
license: "MIT",
|
|
1489
1489
|
type: "module",
|
|
@@ -4023,6 +4023,7 @@ var VALID_PHASES = /* @__PURE__ */ new Set(["research", "planning", "implementin
|
|
|
4023
4023
|
var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
|
|
4024
4024
|
"name",
|
|
4025
4025
|
"staff",
|
|
4026
|
+
"every",
|
|
4026
4027
|
"describe",
|
|
4027
4028
|
"role",
|
|
4028
4029
|
"kind",
|
|
@@ -4104,6 +4105,8 @@ function loadProfile(profilePath) {
|
|
|
4104
4105
|
describe: typeof r.describe === "string" ? r.describe : "",
|
|
4105
4106
|
// Optional persona to run as. Empty/blank string → undefined (no persona).
|
|
4106
4107
|
staff: typeof r.staff === "string" && r.staff.trim() ? r.staff.trim() : void 0,
|
|
4108
|
+
// Optional recurrence cadence (scheduled duty). Blank → undefined (on-demand).
|
|
4109
|
+
every: typeof r.every === "string" && r.every.trim() ? r.every.trim() : void 0,
|
|
4107
4110
|
role,
|
|
4108
4111
|
kind,
|
|
4109
4112
|
schedule: typeof r.schedule === "string" ? r.schedule : void 0,
|
|
@@ -8537,6 +8540,56 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
|
|
|
8537
8540
|
} catch (err) {
|
|
8538
8541
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8539
8542
|
process.stderr.write(`[jobs] tick ${slug} crashed: ${msg}
|
|
8543
|
+
`);
|
|
8544
|
+
results.push({ slug, exitCode: 99, reason: msg });
|
|
8545
|
+
}
|
|
8546
|
+
}
|
|
8547
|
+
const folderSlugs = listFolderDutySlugs(path29.join(ctx.cwd, jobsDir));
|
|
8548
|
+
for (const slug of folderSlugs) {
|
|
8549
|
+
let every;
|
|
8550
|
+
let staff;
|
|
8551
|
+
try {
|
|
8552
|
+
const profile = loadProfile(path29.join(ctx.cwd, jobsDir, slug, "profile.json"));
|
|
8553
|
+
every = profile.every;
|
|
8554
|
+
staff = profile.staff;
|
|
8555
|
+
} catch (err) {
|
|
8556
|
+
process.stderr.write(`[jobs] \u23ED skip folder-duty ${slug}: profile load failed: ${String(err)}
|
|
8557
|
+
`);
|
|
8558
|
+
continue;
|
|
8559
|
+
}
|
|
8560
|
+
if (!every) continue;
|
|
8561
|
+
if (!staff || staff.trim().length === 0) {
|
|
8562
|
+
process.stderr.write(`[jobs] \u23ED skip ${slug}: scheduled duty has no staff
|
|
8563
|
+
`);
|
|
8564
|
+
results.push({ slug, exitCode: 0, skipped: true, reason: "no staff assigned" });
|
|
8565
|
+
continue;
|
|
8566
|
+
}
|
|
8567
|
+
const decision = await decideShouldFire(every, slug, backend, now);
|
|
8568
|
+
if (decision.skip) {
|
|
8569
|
+
process.stdout.write(`[jobs] \u23ED skip ${slug}: ${decision.reason}
|
|
8570
|
+
`);
|
|
8571
|
+
results.push({ slug, exitCode: 0, skipped: true, reason: decision.reason });
|
|
8572
|
+
continue;
|
|
8573
|
+
}
|
|
8574
|
+
await stampFired(backend, slug, now);
|
|
8575
|
+
process.stdout.write(`[jobs] \u2192 run scheduled duty ${slug} (one-shot, as ${staff})
|
|
8576
|
+
`);
|
|
8577
|
+
try {
|
|
8578
|
+
const out = await runExecutable(slug, {
|
|
8579
|
+
cliArgs: {},
|
|
8580
|
+
cwd: ctx.cwd,
|
|
8581
|
+
config: ctx.config,
|
|
8582
|
+
verbose: ctx.verbose,
|
|
8583
|
+
quiet: ctx.quiet
|
|
8584
|
+
});
|
|
8585
|
+
results.push({ slug, exitCode: out.exitCode, reason: out.reason });
|
|
8586
|
+
if (out.exitCode !== 0) {
|
|
8587
|
+
process.stderr.write(`[jobs] scheduled duty ${slug} failed (exit ${out.exitCode}): ${out.reason ?? ""}
|
|
8588
|
+
`);
|
|
8589
|
+
}
|
|
8590
|
+
} catch (err) {
|
|
8591
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8592
|
+
process.stderr.write(`[jobs] scheduled duty ${slug} crashed: ${msg}
|
|
8540
8593
|
`);
|
|
8541
8594
|
results.push({ slug, exitCode: 99, reason: msg });
|
|
8542
8595
|
}
|
|
@@ -8613,6 +8666,26 @@ function listJobSlugs(absDir) {
|
|
|
8613
8666
|
}
|
|
8614
8667
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name.replace(/\.md$/, "")).filter((slug) => slug.length > 0 && !slug.startsWith("_") && !slug.startsWith(".")).sort();
|
|
8615
8668
|
}
|
|
8669
|
+
function listFolderDutySlugs(absDir) {
|
|
8670
|
+
if (!fs32.existsSync(absDir)) return [];
|
|
8671
|
+
let entries;
|
|
8672
|
+
try {
|
|
8673
|
+
entries = fs32.readdirSync(absDir, { withFileTypes: true });
|
|
8674
|
+
} catch {
|
|
8675
|
+
return [];
|
|
8676
|
+
}
|
|
8677
|
+
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => fs32.existsSync(path29.join(absDir, e.name, "profile.json"))).map((e) => e.name).sort();
|
|
8678
|
+
}
|
|
8679
|
+
async function stampFired(backend, slug, now) {
|
|
8680
|
+
try {
|
|
8681
|
+
const loaded = await backend.load(slug);
|
|
8682
|
+
const nextData = { ...loaded.state.data ?? {}, lastFiredAt: new Date(now).toISOString() };
|
|
8683
|
+
await backend.save(loaded, { ...loaded.state, data: nextData });
|
|
8684
|
+
} catch (err) {
|
|
8685
|
+
process.stderr.write(`[jobs] failed to stamp lastFiredAt for ${slug}: ${String(err)}
|
|
8686
|
+
`);
|
|
8687
|
+
}
|
|
8688
|
+
}
|
|
8616
8689
|
|
|
8617
8690
|
// src/scripts/dispatchJobTicks.ts
|
|
8618
8691
|
init_issue();
|
|
@@ -49,6 +49,14 @@ export interface Profile {
|
|
|
49
49
|
* `schedule:`). Scheduled profiles must declare a `schedule` cron string.
|
|
50
50
|
*/
|
|
51
51
|
kind: "oneshot" | "scheduled"
|
|
52
|
+
/**
|
|
53
|
+
* Recurrence cadence for a duty that runs on a timer (unified successor to a
|
|
54
|
+
* markdown duty's `every:` frontmatter). One of the ScheduleEvery values
|
|
55
|
+
* ("15m".."7d" | "manual"). Present → the duty-scheduler fires a one-shot run
|
|
56
|
+
* when due (no target). Absent → on-demand only (runs against an issue/PR).
|
|
57
|
+
* This is what makes "scheduled" just a field on the one duty shape.
|
|
58
|
+
*/
|
|
59
|
+
every?: string
|
|
52
60
|
/** Cron expression for scheduled profiles (e.g. "0 8 * * MON"). */
|
|
53
61
|
schedule?: string
|
|
54
62
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.204-next.
|
|
3
|
+
"version": "0.4.204-next.4",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|