@kody-ade/kody-engine 0.4.245 → 0.4.247
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 +167 -2
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.247",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative agentAction profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -146,7 +146,7 @@ var init_claudeBinary = __esm({
|
|
|
146
146
|
// src/issue.ts
|
|
147
147
|
import { execFileSync } from "child_process";
|
|
148
148
|
function ghToken() {
|
|
149
|
-
return process.env.
|
|
149
|
+
return process.env.GITHUB_TOKEN?.trim() || process.env.KODY_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || process.env.GH_PAT?.trim();
|
|
150
150
|
}
|
|
151
151
|
function gh(args, options) {
|
|
152
152
|
const token = ghToken();
|
|
@@ -658,6 +658,14 @@ function parseGoalActivations(raw) {
|
|
|
658
658
|
const idPrefix = parseSlug(r.idPrefix, "company.activeGoals.idPrefix");
|
|
659
659
|
if (idPrefix) entry.idPrefix = idPrefix;
|
|
660
660
|
}
|
|
661
|
+
if (r.preferredRunTime !== void 0) {
|
|
662
|
+
const preferredRunTime = parsePreferredRunTime(r.preferredRunTime);
|
|
663
|
+
if (!preferredRunTime)
|
|
664
|
+
throw new Error(
|
|
665
|
+
`kody.config.json: company.activeGoals preferredRunTime must be { "time": "HH:MM", "timezone": "Area/Name" }`
|
|
666
|
+
);
|
|
667
|
+
entry.preferredRunTime = preferredRunTime;
|
|
668
|
+
}
|
|
661
669
|
const facts = recordValue(r.facts);
|
|
662
670
|
if (r.facts !== void 0 && !facts)
|
|
663
671
|
throw new Error(`kody.config.json: company.activeGoals facts must be an object`);
|
|
@@ -666,6 +674,13 @@ function parseGoalActivations(raw) {
|
|
|
666
674
|
}
|
|
667
675
|
return out;
|
|
668
676
|
}
|
|
677
|
+
function parsePreferredRunTime(raw) {
|
|
678
|
+
const r = recordValue(raw);
|
|
679
|
+
if (!r) return null;
|
|
680
|
+
if (typeof r.time !== "string" || !/^([01]\d|2[0-3]):[0-5]\d$/.test(r.time.trim())) return null;
|
|
681
|
+
if (typeof r.timezone !== "string" || !r.timezone.trim()) return null;
|
|
682
|
+
return { time: r.time.trim(), timezone: r.timezone.trim() };
|
|
683
|
+
}
|
|
669
684
|
function parseSlugArray(raw, field) {
|
|
670
685
|
if (!Array.isArray(raw)) throw new Error(`kody.config.json: ${field} must be an array of strings`);
|
|
671
686
|
const out = [];
|
|
@@ -5958,6 +5973,20 @@ function asRoute(value) {
|
|
|
5958
5973
|
}
|
|
5959
5974
|
return route;
|
|
5960
5975
|
}
|
|
5976
|
+
function asPreferredRunTime(value) {
|
|
5977
|
+
const raw = asRecord(value);
|
|
5978
|
+
if (!raw) return void 0;
|
|
5979
|
+
if (typeof raw.time !== "string" || !/^([01]\d|2[0-3]):[0-5]\d$/.test(raw.time)) return void 0;
|
|
5980
|
+
if (typeof raw.timezone !== "string" || raw.timezone.trim().length === 0) return void 0;
|
|
5981
|
+
return { time: raw.time, timezone: raw.timezone };
|
|
5982
|
+
}
|
|
5983
|
+
function asLoopTarget(value) {
|
|
5984
|
+
const raw = asRecord(value);
|
|
5985
|
+
if (!raw) return void 0;
|
|
5986
|
+
if (raw.type !== "goal" && raw.type !== "agentResponsibility") return void 0;
|
|
5987
|
+
if (typeof raw.id !== "string" || raw.id.trim().length === 0) return void 0;
|
|
5988
|
+
return { type: raw.type, id: raw.id };
|
|
5989
|
+
}
|
|
5961
5990
|
function managedGoalFromState(state) {
|
|
5962
5991
|
const extra = state.extra;
|
|
5963
5992
|
const destination = asRecord(extra.destination);
|
|
@@ -5974,6 +6003,9 @@ function managedGoalFromState(state) {
|
|
|
5974
6003
|
destination: { outcome: destination.outcome, evidence },
|
|
5975
6004
|
agentResponsibilities,
|
|
5976
6005
|
route,
|
|
6006
|
+
schedule: typeof extra.schedule === "string" ? extra.schedule : void 0,
|
|
6007
|
+
preferredRunTime: asPreferredRunTime(extra.preferredRunTime),
|
|
6008
|
+
loopTarget: asLoopTarget(extra.loopTarget),
|
|
5977
6009
|
stage: typeof extra.stage === "string" ? extra.stage : void 0,
|
|
5978
6010
|
facts,
|
|
5979
6011
|
blockers
|
|
@@ -6572,6 +6604,41 @@ import * as path25 from "path";
|
|
|
6572
6604
|
function isAgentResponsibilityCadenceGoal(goal, extra) {
|
|
6573
6605
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.agentResponsibilities.length > 0;
|
|
6574
6606
|
}
|
|
6607
|
+
function isGoalTargetLoop(goal) {
|
|
6608
|
+
return goal.type === "agentLoop" && goal.loopTarget?.type === "goal" && goal.loopTarget.id.trim().length > 0;
|
|
6609
|
+
}
|
|
6610
|
+
function planGoalTargetLoopSchedule(opts) {
|
|
6611
|
+
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
6612
|
+
const at = now.toISOString();
|
|
6613
|
+
const targetId = opts.goal.loopTarget?.type === "goal" ? opts.goal.loopTarget.id.trim() : "";
|
|
6614
|
+
if (!targetId) {
|
|
6615
|
+
const reason = "goal target loop missing target goal";
|
|
6616
|
+
return targetLoopDecision("blocked", reason, at);
|
|
6617
|
+
}
|
|
6618
|
+
const preferred = opts.goal.preferredRunTime;
|
|
6619
|
+
if (preferred) {
|
|
6620
|
+
const gate = preferredRunTimeGate(preferred, now, opts.previousScheduleState);
|
|
6621
|
+
if (!gate.ok) return targetLoopDecision("idle", gate.reason, at);
|
|
6622
|
+
}
|
|
6623
|
+
return {
|
|
6624
|
+
kind: "dispatch",
|
|
6625
|
+
reason: `dispatch goal ${targetId}`,
|
|
6626
|
+
dispatch: { action: "goal-manager", agentAction: "goal-manager", cliArgs: { goal: targetId } },
|
|
6627
|
+
scheduleState: {
|
|
6628
|
+
mode: "agentLoop",
|
|
6629
|
+
lastGoalTickAt: at,
|
|
6630
|
+
lastDecision: {
|
|
6631
|
+
kind: "dispatch",
|
|
6632
|
+
targetType: "goal",
|
|
6633
|
+
targetId,
|
|
6634
|
+
agentAction: "goal-manager",
|
|
6635
|
+
reason: preferred ? `preferred time ${preferred.time} ${preferred.timezone}` : "ready target loop tick",
|
|
6636
|
+
at
|
|
6637
|
+
},
|
|
6638
|
+
agentResponsibilities: {}
|
|
6639
|
+
}
|
|
6640
|
+
};
|
|
6641
|
+
}
|
|
6575
6642
|
async function planGoalAgentResponsibilitySchedule(opts) {
|
|
6576
6643
|
const jobsDir = opts.jobsDir ?? ".kody/agent-responsibilities";
|
|
6577
6644
|
const jobsRoot = path25.join(opts.cwd, jobsDir);
|
|
@@ -6695,6 +6762,64 @@ function validIso(value) {
|
|
|
6695
6762
|
function markAgentResponsibilitySelected(status, now) {
|
|
6696
6763
|
return { ...status, lastFiredAt: now.toISOString() };
|
|
6697
6764
|
}
|
|
6765
|
+
function targetLoopDecision(kind, reason, at) {
|
|
6766
|
+
return {
|
|
6767
|
+
kind,
|
|
6768
|
+
reason,
|
|
6769
|
+
scheduleState: {
|
|
6770
|
+
mode: "agentLoop",
|
|
6771
|
+
lastGoalTickAt: at,
|
|
6772
|
+
lastDecision: { kind, reason, at },
|
|
6773
|
+
agentResponsibilities: {}
|
|
6774
|
+
}
|
|
6775
|
+
};
|
|
6776
|
+
}
|
|
6777
|
+
function preferredRunTimeGate(preferred, now, previous) {
|
|
6778
|
+
const current = zonedTimeParts(now, preferred.timezone);
|
|
6779
|
+
if (!current) return { ok: false, reason: `invalid preferred timezone: ${preferred.timezone}` };
|
|
6780
|
+
const preferredMinute = preferredTimeToMinute(preferred.time);
|
|
6781
|
+
if (preferredMinute === null) return { ok: false, reason: `invalid preferred time: ${preferred.time}` };
|
|
6782
|
+
const currentMinute = current.hour * 60 + current.minute;
|
|
6783
|
+
if (currentMinute < preferredMinute) {
|
|
6784
|
+
return { ok: false, reason: `waiting preferred time ${preferred.time} ${preferred.timezone}` };
|
|
6785
|
+
}
|
|
6786
|
+
const lastDispatchAt = previous?.lastDecision.kind === "dispatch" ? previous.lastDecision.at : void 0;
|
|
6787
|
+
if (lastDispatchAt) {
|
|
6788
|
+
const last = zonedTimeParts(new Date(lastDispatchAt), preferred.timezone);
|
|
6789
|
+
if (last?.date === current.date) {
|
|
6790
|
+
return { ok: false, reason: `already dispatched today at preferred time ${preferred.time} ${preferred.timezone}` };
|
|
6791
|
+
}
|
|
6792
|
+
}
|
|
6793
|
+
return { ok: true };
|
|
6794
|
+
}
|
|
6795
|
+
function preferredTimeToMinute(value) {
|
|
6796
|
+
const match = value.match(/^([01]\d|2[0-3]):([0-5]\d)$/);
|
|
6797
|
+
if (!match) return null;
|
|
6798
|
+
return Number(match[1]) * 60 + Number(match[2]);
|
|
6799
|
+
}
|
|
6800
|
+
function zonedTimeParts(date, timezone) {
|
|
6801
|
+
try {
|
|
6802
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
6803
|
+
timeZone: timezone,
|
|
6804
|
+
year: "numeric",
|
|
6805
|
+
month: "2-digit",
|
|
6806
|
+
day: "2-digit",
|
|
6807
|
+
hour: "2-digit",
|
|
6808
|
+
minute: "2-digit",
|
|
6809
|
+
hourCycle: "h23"
|
|
6810
|
+
}).formatToParts(date);
|
|
6811
|
+
const get = (type) => parts.find((part) => part.type === type)?.value;
|
|
6812
|
+
const year = get("year");
|
|
6813
|
+
const month = get("month");
|
|
6814
|
+
const day = get("day");
|
|
6815
|
+
const hour = get("hour");
|
|
6816
|
+
const minute = get("minute");
|
|
6817
|
+
if (!year || !month || !day || !hour || !minute) return null;
|
|
6818
|
+
return { date: `${year}-${month}-${day}`, hour: Number(hour), minute: Number(minute) };
|
|
6819
|
+
} catch {
|
|
6820
|
+
return null;
|
|
6821
|
+
}
|
|
6822
|
+
}
|
|
6698
6823
|
var init_goalAgentResponsibilityScheduling = __esm({
|
|
6699
6824
|
"src/scripts/goalAgentResponsibilityScheduling.ts"() {
|
|
6700
6825
|
"use strict";
|
|
@@ -6806,6 +6931,23 @@ var init_advanceManagedGoal = __esm({
|
|
|
6806
6931
|
ctx.output.reason = reason;
|
|
6807
6932
|
return;
|
|
6808
6933
|
}
|
|
6934
|
+
if (isGoalTargetLoop(managed)) {
|
|
6935
|
+
const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
|
|
6936
|
+
const decision2 = planGoalTargetLoopSchedule({ goal: managed, previousScheduleState });
|
|
6937
|
+
restoreGoalIdFact();
|
|
6938
|
+
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
6939
|
+
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
6940
|
+
ctx.data.managedGoalDecision = decision2;
|
|
6941
|
+
if (decision2.kind === "dispatch" && decision2.dispatch) {
|
|
6942
|
+
ctx.output.nextDispatch = {
|
|
6943
|
+
action: decision2.dispatch.action,
|
|
6944
|
+
agentAction: decision2.dispatch.agentAction,
|
|
6945
|
+
cliArgs: decision2.dispatch.cliArgs
|
|
6946
|
+
};
|
|
6947
|
+
}
|
|
6948
|
+
ctx.output.reason = decision2.reason;
|
|
6949
|
+
return;
|
|
6950
|
+
}
|
|
6809
6951
|
if (isAgentResponsibilityCadenceGoal(managed, goal.raw.extra)) {
|
|
6810
6952
|
const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
|
|
6811
6953
|
const decision2 = await planGoalAgentResponsibilitySchedule({
|
|
@@ -17308,12 +17450,34 @@ function unpackAllSecrets(env = process.env) {
|
|
|
17308
17450
|
}
|
|
17309
17451
|
return count;
|
|
17310
17452
|
}
|
|
17453
|
+
function recoverCheckoutToken(env = process.env, cwd = process.cwd()) {
|
|
17454
|
+
if (env.GITHUB_TOKEN?.trim()) return env.GITHUB_TOKEN.trim();
|
|
17455
|
+
let header = "";
|
|
17456
|
+
try {
|
|
17457
|
+
header = execFileSync25("git", ["config", "--local", "--get", "http.https://github.com/.extraheader"], {
|
|
17458
|
+
cwd,
|
|
17459
|
+
encoding: "utf-8",
|
|
17460
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
17461
|
+
}).trim();
|
|
17462
|
+
} catch {
|
|
17463
|
+
return void 0;
|
|
17464
|
+
}
|
|
17465
|
+
const match = /^AUTHORIZATION:\s+basic\s+(.+)$/i.exec(header);
|
|
17466
|
+
if (!match) return void 0;
|
|
17467
|
+
const decoded = Buffer.from(match[1], "base64").toString("utf-8");
|
|
17468
|
+
const token = decoded.includes(":") ? decoded.slice(decoded.indexOf(":") + 1).trim() : decoded.trim();
|
|
17469
|
+
if (!token) return void 0;
|
|
17470
|
+
env.GITHUB_TOKEN = token;
|
|
17471
|
+
process.stdout.write("\u2192 kody: GITHUB_TOKEN recovered from actions/checkout credentials\n");
|
|
17472
|
+
return token;
|
|
17473
|
+
}
|
|
17311
17474
|
async function resolveAuthToken(env = process.env) {
|
|
17312
17475
|
const creds = readAppCreds(env);
|
|
17313
17476
|
if (creds) {
|
|
17314
17477
|
try {
|
|
17315
17478
|
const minted = await mintAppInstallationToken(creds);
|
|
17316
17479
|
env.GH_TOKEN = minted;
|
|
17480
|
+
recoverCheckoutToken(env);
|
|
17317
17481
|
process.stdout.write("\u2192 kody: GH_TOKEN minted from GitHub App (KODY_APP_ID/KODY_APP_PRIVATE_KEY)\n");
|
|
17318
17482
|
return minted;
|
|
17319
17483
|
} catch (err) {
|
|
@@ -17330,6 +17494,7 @@ async function resolveAuthToken(env = process.env) {
|
|
|
17330
17494
|
const picked = sources.find(([, v]) => !!v);
|
|
17331
17495
|
const token = picked?.[1];
|
|
17332
17496
|
if (token && !env.GH_TOKEN) env.GH_TOKEN = token;
|
|
17497
|
+
recoverCheckoutToken(env);
|
|
17333
17498
|
if (token) {
|
|
17334
17499
|
process.stdout.write(`\u2192 kody: GH_TOKEN sourced from env.${picked[0]}
|
|
17335
17500
|
`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.247",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative agentAction profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|