@kody-ade/kody-engine 0.4.232 → 0.4.233
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 +206 -4
- package/package.json +22 -23
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.233",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -5723,6 +5723,132 @@ var init_state2 = __esm({
|
|
|
5723
5723
|
}
|
|
5724
5724
|
});
|
|
5725
5725
|
|
|
5726
|
+
// src/goal/typeDefinitions.ts
|
|
5727
|
+
function cloneRoute(route) {
|
|
5728
|
+
return route.map((step) => ({
|
|
5729
|
+
stage: step.stage,
|
|
5730
|
+
evidence: step.evidence,
|
|
5731
|
+
duty: step.duty,
|
|
5732
|
+
...step.executable ? { executable: step.executable } : {},
|
|
5733
|
+
...step.args ? { args: structuredClone(step.args) } : {}
|
|
5734
|
+
}));
|
|
5735
|
+
}
|
|
5736
|
+
function stringArray(value) {
|
|
5737
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : null;
|
|
5738
|
+
}
|
|
5739
|
+
function routeArray(value) {
|
|
5740
|
+
if (!Array.isArray(value)) return null;
|
|
5741
|
+
const route = [];
|
|
5742
|
+
for (const item of value) {
|
|
5743
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return null;
|
|
5744
|
+
const raw = item;
|
|
5745
|
+
if (typeof raw.stage !== "string" || typeof raw.evidence !== "string" || typeof raw.duty !== "string") return null;
|
|
5746
|
+
route.push({
|
|
5747
|
+
stage: raw.stage,
|
|
5748
|
+
evidence: raw.evidence,
|
|
5749
|
+
duty: raw.duty,
|
|
5750
|
+
executable: typeof raw.executable === "string" ? raw.executable : void 0,
|
|
5751
|
+
args: raw.args && typeof raw.args === "object" && !Array.isArray(raw.args) ? { ...raw.args } : void 0
|
|
5752
|
+
});
|
|
5753
|
+
}
|
|
5754
|
+
return route;
|
|
5755
|
+
}
|
|
5756
|
+
function managedGoalTypeDefinition(type) {
|
|
5757
|
+
return Object.prototype.hasOwnProperty.call(GOAL_TYPE_DEFINITIONS, type) ? GOAL_TYPE_DEFINITIONS[type] : null;
|
|
5758
|
+
}
|
|
5759
|
+
function expandManagedGoalState(state) {
|
|
5760
|
+
const type = typeof state.extra.type === "string" ? state.extra.type : "";
|
|
5761
|
+
const definition = managedGoalTypeDefinition(type);
|
|
5762
|
+
if (!definition) return state;
|
|
5763
|
+
const destination = state.extra.destination && typeof state.extra.destination === "object" && !Array.isArray(state.extra.destination) ? { ...state.extra.destination } : {};
|
|
5764
|
+
const outcome = typeof destination.outcome === "string" ? destination.outcome : "";
|
|
5765
|
+
const evidence = stringArray(destination.evidence);
|
|
5766
|
+
const duties = stringArray(state.extra.duties);
|
|
5767
|
+
const route = routeArray(state.extra.route);
|
|
5768
|
+
const facts = state.extra.facts && typeof state.extra.facts === "object" && !Array.isArray(state.extra.facts) ? { ...state.extra.facts } : {};
|
|
5769
|
+
const blockers = stringArray(state.extra.blockers);
|
|
5770
|
+
return {
|
|
5771
|
+
...state,
|
|
5772
|
+
extra: {
|
|
5773
|
+
...state.extra,
|
|
5774
|
+
type: definition.type,
|
|
5775
|
+
destination: {
|
|
5776
|
+
...destination,
|
|
5777
|
+
outcome,
|
|
5778
|
+
evidence: evidence && evidence.length > 0 ? evidence : [...definition.evidence]
|
|
5779
|
+
},
|
|
5780
|
+
duties: duties && duties.length > 0 ? duties : [...definition.duties],
|
|
5781
|
+
route: route && route.length > 0 ? route : cloneRoute(definition.route),
|
|
5782
|
+
facts,
|
|
5783
|
+
blockers: blockers ?? []
|
|
5784
|
+
}
|
|
5785
|
+
};
|
|
5786
|
+
}
|
|
5787
|
+
var GOAL_TYPE_DEFINITIONS;
|
|
5788
|
+
var init_typeDefinitions = __esm({
|
|
5789
|
+
"src/goal/typeDefinitions.ts"() {
|
|
5790
|
+
"use strict";
|
|
5791
|
+
GOAL_TYPE_DEFINITIONS = {
|
|
5792
|
+
improve: {
|
|
5793
|
+
type: "improve",
|
|
5794
|
+
evidence: ["planReady", "changeImplemented", "changeVerified"],
|
|
5795
|
+
duties: ["plan", "fix", "review"],
|
|
5796
|
+
route: [
|
|
5797
|
+
{ stage: "plan", evidence: "planReady", duty: "plan", executable: "plan" },
|
|
5798
|
+
{ stage: "implement", evidence: "changeImplemented", duty: "fix", executable: "fix" },
|
|
5799
|
+
{ stage: "review", evidence: "changeVerified", duty: "review", executable: "review" }
|
|
5800
|
+
]
|
|
5801
|
+
},
|
|
5802
|
+
maintain: {
|
|
5803
|
+
type: "maintain",
|
|
5804
|
+
evidence: [],
|
|
5805
|
+
duties: ["cleanup", "code-health", "docs-health", "documentation-maintenance", "memory-compaction", "repo-graph", "skills-research"],
|
|
5806
|
+
route: []
|
|
5807
|
+
},
|
|
5808
|
+
monitor: {
|
|
5809
|
+
type: "monitor",
|
|
5810
|
+
evidence: [],
|
|
5811
|
+
duties: ["health-check", "pr-health-triage", "qa-sweep"],
|
|
5812
|
+
route: []
|
|
5813
|
+
},
|
|
5814
|
+
release: {
|
|
5815
|
+
type: "release",
|
|
5816
|
+
evidence: ["releasePrExists", "mainMerged", "productionDeployed"],
|
|
5817
|
+
duties: ["release", "release-merge", "vercel-production-deploy"],
|
|
5818
|
+
route: [
|
|
5819
|
+
{
|
|
5820
|
+
stage: "release",
|
|
5821
|
+
evidence: "releasePrExists",
|
|
5822
|
+
duty: "release",
|
|
5823
|
+
executable: "release-prepare",
|
|
5824
|
+
args: { issue: { fact: "issue" }, goal: { fact: "goalId" } }
|
|
5825
|
+
},
|
|
5826
|
+
{
|
|
5827
|
+
stage: "merge",
|
|
5828
|
+
evidence: "mainMerged",
|
|
5829
|
+
duty: "release-merge",
|
|
5830
|
+
executable: "release-merge",
|
|
5831
|
+
args: { pr: { fact: "releasePr" }, issue: { fact: "issue" }, goal: { fact: "goalId" } }
|
|
5832
|
+
},
|
|
5833
|
+
{
|
|
5834
|
+
stage: "publish",
|
|
5835
|
+
evidence: "productionDeployed",
|
|
5836
|
+
duty: "vercel-production-deploy",
|
|
5837
|
+
executable: "vercel-production-deploy",
|
|
5838
|
+
args: { goal: { fact: "goalId" } }
|
|
5839
|
+
}
|
|
5840
|
+
]
|
|
5841
|
+
},
|
|
5842
|
+
checklist: {
|
|
5843
|
+
type: "checklist",
|
|
5844
|
+
evidence: ["checklistComplete"],
|
|
5845
|
+
duties: ["task-verifier"],
|
|
5846
|
+
route: [{ stage: "verify", evidence: "checklistComplete", duty: "task-verifier", executable: "task-verifier" }]
|
|
5847
|
+
}
|
|
5848
|
+
};
|
|
5849
|
+
}
|
|
5850
|
+
});
|
|
5851
|
+
|
|
5726
5852
|
// src/stateBranch.ts
|
|
5727
5853
|
function is404(err) {
|
|
5728
5854
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -6335,12 +6461,64 @@ function readSimpleGoalTaskSummary(goalId, cwd) {
|
|
|
6335
6461
|
const open = issues.filter((issue) => String(issue.state ?? "").toLowerCase() === "open").length;
|
|
6336
6462
|
return { total, open };
|
|
6337
6463
|
}
|
|
6464
|
+
function ensureIssueFactIfNeeded(goal, goalId, cwd) {
|
|
6465
|
+
if (!routeNeedsIssueFact(goal)) return;
|
|
6466
|
+
const existing = normalizeIssueNumber(goal.facts.issue);
|
|
6467
|
+
if (existing !== null) {
|
|
6468
|
+
goal.facts.issue = existing;
|
|
6469
|
+
return;
|
|
6470
|
+
}
|
|
6471
|
+
goal.facts.issue = findExistingGoalIssue(goalId, cwd) ?? createGoalIssue(goal, goalId, cwd);
|
|
6472
|
+
}
|
|
6473
|
+
function routeNeedsIssueFact(goal) {
|
|
6474
|
+
return goal.route.some(
|
|
6475
|
+
(step) => Object.values(step.args ?? {}).some((value) => {
|
|
6476
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
6477
|
+
const record = value;
|
|
6478
|
+
return Object.keys(record).length === 1 && record.fact === "issue";
|
|
6479
|
+
})
|
|
6480
|
+
);
|
|
6481
|
+
}
|
|
6482
|
+
function normalizeIssueNumber(value) {
|
|
6483
|
+
if (typeof value === "number" && Number.isInteger(value) && value > 0) return value;
|
|
6484
|
+
if (typeof value === "string" && /^\d+$/.test(value)) return Number(value);
|
|
6485
|
+
return null;
|
|
6486
|
+
}
|
|
6487
|
+
function goalIssueMarker(goalId) {
|
|
6488
|
+
return `<!-- kody-managed-goal: ${goalId} -->`;
|
|
6489
|
+
}
|
|
6490
|
+
function findExistingGoalIssue(goalId, cwd) {
|
|
6491
|
+
const marker = goalIssueMarker(goalId);
|
|
6492
|
+
const raw = gh(["issue", "list", "--state", "all", "--limit", "100", "--json", "number,body"], { cwd });
|
|
6493
|
+
const issues = JSON.parse(raw);
|
|
6494
|
+
const match = issues.find((issue) => typeof issue.number === "number" && issue.body?.includes(marker));
|
|
6495
|
+
return match?.number ?? null;
|
|
6496
|
+
}
|
|
6497
|
+
function createGoalIssue(goal, goalId, cwd) {
|
|
6498
|
+
const prefix = goal.type === "release" ? "Release" : "Goal";
|
|
6499
|
+
const outcome = goal.destination.outcome.trim() || goalId;
|
|
6500
|
+
const title = `${prefix}: ${outcome}`.slice(0, 120);
|
|
6501
|
+
const body = [
|
|
6502
|
+
`Managed goal: \`${goalId}\``,
|
|
6503
|
+
"",
|
|
6504
|
+
`Finish line: ${outcome}`,
|
|
6505
|
+
"",
|
|
6506
|
+
"This issue was created by Kody so goal duties that require an issue can run end to end.",
|
|
6507
|
+
"",
|
|
6508
|
+
goalIssueMarker(goalId)
|
|
6509
|
+
].join("\n");
|
|
6510
|
+
const out = gh(["issue", "create", "--title", title, "--body-file", "-"], { input: body, cwd });
|
|
6511
|
+
const match = out.match(/\/issues\/(\d+)(?:[/?#]|$)/);
|
|
6512
|
+
if (!match) throw new Error(`gh issue create returned unexpected output: ${out}`);
|
|
6513
|
+
return Number(match[1]);
|
|
6514
|
+
}
|
|
6338
6515
|
var advanceManagedGoal;
|
|
6339
6516
|
var init_advanceManagedGoal = __esm({
|
|
6340
6517
|
"src/scripts/advanceManagedGoal.ts"() {
|
|
6341
6518
|
"use strict";
|
|
6342
6519
|
init_manager();
|
|
6343
6520
|
init_state2();
|
|
6521
|
+
init_typeDefinitions();
|
|
6344
6522
|
init_issue();
|
|
6345
6523
|
init_goalDutyScheduling();
|
|
6346
6524
|
advanceManagedGoal = async (ctx) => {
|
|
@@ -6352,6 +6530,7 @@ var init_advanceManagedGoal = __esm({
|
|
|
6352
6530
|
return;
|
|
6353
6531
|
}
|
|
6354
6532
|
ctx.data.goalOriginalStateText = serializeGoalState(goal.raw);
|
|
6533
|
+
goal.raw = expandManagedGoalState(goal.raw);
|
|
6355
6534
|
const managed = managedGoalFromState(goal.raw);
|
|
6356
6535
|
if (!managed) {
|
|
6357
6536
|
ctx.output.reason = "goal has no managed-goal contract; nothing to advance";
|
|
@@ -6363,6 +6542,17 @@ var init_advanceManagedGoal = __esm({
|
|
|
6363
6542
|
if (previousGoalIdFact === void 0) delete managed.facts.goalId;
|
|
6364
6543
|
else managed.facts.goalId = previousGoalIdFact;
|
|
6365
6544
|
};
|
|
6545
|
+
try {
|
|
6546
|
+
ensureIssueFactIfNeeded(managed, goal.id, ctx.cwd);
|
|
6547
|
+
} catch (err) {
|
|
6548
|
+
const reason = `failed to prepare goal issue fact: ${err instanceof Error ? err.message : String(err)}`;
|
|
6549
|
+
managed.stage = "blocked";
|
|
6550
|
+
if (!managed.blockers.includes(reason)) managed.blockers.push(reason);
|
|
6551
|
+
restoreGoalIdFact();
|
|
6552
|
+
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
6553
|
+
ctx.output.reason = reason;
|
|
6554
|
+
return;
|
|
6555
|
+
}
|
|
6366
6556
|
if (isDutyCadenceGoal(managed, goal.raw.extra)) {
|
|
6367
6557
|
const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
|
|
6368
6558
|
const decision2 = await planGoalDutySchedule({
|
|
@@ -16554,15 +16744,23 @@ async function runCi(argv) {
|
|
|
16554
16744
|
const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
|
|
16555
16745
|
let manualWorkflowDispatch = false;
|
|
16556
16746
|
let forceRunAction = null;
|
|
16747
|
+
let forceRunCliArgs = {};
|
|
16557
16748
|
if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs42.existsSync(dispatchEventPath)) {
|
|
16558
16749
|
try {
|
|
16559
16750
|
const evt = JSON.parse(fs42.readFileSync(dispatchEventPath, "utf-8"));
|
|
16560
16751
|
const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
|
|
16561
16752
|
const sessionInput = String(evt?.inputs?.sessionId ?? "");
|
|
16562
16753
|
const dutyInput = String(evt?.inputs?.duty ?? evt?.inputs?.executable ?? "").trim();
|
|
16754
|
+
const messageInput = String(evt?.inputs?.message ?? "").trim();
|
|
16563
16755
|
const noTarget = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
|
|
16564
|
-
if (noTarget && dutyInput)
|
|
16565
|
-
|
|
16756
|
+
if (noTarget && dutyInput) {
|
|
16757
|
+
forceRunAction = dutyInput;
|
|
16758
|
+
if (dutyInput === "goal-manager" && messageInput) {
|
|
16759
|
+
forceRunCliArgs = { goal: messageInput };
|
|
16760
|
+
}
|
|
16761
|
+
} else {
|
|
16762
|
+
manualWorkflowDispatch = noTarget;
|
|
16763
|
+
}
|
|
16566
16764
|
} catch {
|
|
16567
16765
|
manualWorkflowDispatch = false;
|
|
16568
16766
|
}
|
|
@@ -16575,6 +16773,10 @@ async function runCi(argv) {
|
|
|
16575
16773
|
`);
|
|
16576
16774
|
return 64;
|
|
16577
16775
|
}
|
|
16776
|
+
if (route.executable === "goal-manager" && typeof forceRunCliArgs.goal !== "string") {
|
|
16777
|
+
process.stderr.write("[kody] manual goal-manager run requires message goal id\n");
|
|
16778
|
+
return 64;
|
|
16779
|
+
}
|
|
16578
16780
|
process.stdout.write(`\u2192 kody: manual one-shot run of duty action ${route.action} (${route.duty})
|
|
16579
16781
|
|
|
16580
16782
|
`);
|
|
@@ -16611,7 +16813,7 @@ async function runCi(argv) {
|
|
|
16611
16813
|
action: route.action,
|
|
16612
16814
|
duty: route.duty,
|
|
16613
16815
|
executable: route.executable,
|
|
16614
|
-
cliArgs: route.cliArgs,
|
|
16816
|
+
cliArgs: { ...route.cliArgs, ...forceRunCliArgs },
|
|
16615
16817
|
flavor: "instant",
|
|
16616
16818
|
force: true
|
|
16617
16819
|
},
|
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.233",
|
|
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",
|
|
@@ -12,26 +12,6 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"kody:run": "tsx bin/kody.ts",
|
|
17
|
-
"serve": "tsx bin/kody.ts serve",
|
|
18
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
19
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
20
|
-
"build": "tsup && node scripts/copy-assets.cjs",
|
|
21
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
22
|
-
"pretest": "pnpm check:modularity",
|
|
23
|
-
"test": "vitest run tests/unit tests/int --coverage",
|
|
24
|
-
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
25
|
-
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
26
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
27
|
-
"test:all": "vitest run tests --no-coverage",
|
|
28
|
-
"typecheck": "tsc --noEmit",
|
|
29
|
-
"lint": "biome check",
|
|
30
|
-
"lint:fix": "biome check --write",
|
|
31
|
-
"format": "biome format --write",
|
|
32
|
-
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
|
|
33
|
-
"prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build"
|
|
34
|
-
},
|
|
35
15
|
"dependencies": {
|
|
36
16
|
"@actions/cache": "^6.0.0",
|
|
37
17
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -55,5 +35,24 @@
|
|
|
55
35
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
56
36
|
},
|
|
57
37
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
58
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
59
|
-
|
|
38
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"kody:run": "tsx bin/kody.ts",
|
|
41
|
+
"serve": "tsx bin/kody.ts serve",
|
|
42
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
43
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
44
|
+
"build": "tsup && node scripts/copy-assets.cjs",
|
|
45
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
46
|
+
"pretest": "pnpm check:modularity",
|
|
47
|
+
"test": "vitest run tests/unit tests/int --coverage",
|
|
48
|
+
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
49
|
+
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
50
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
51
|
+
"test:all": "vitest run tests --no-coverage",
|
|
52
|
+
"typecheck": "tsc --noEmit",
|
|
53
|
+
"lint": "biome check",
|
|
54
|
+
"lint:fix": "biome check --write",
|
|
55
|
+
"format": "biome format --write",
|
|
56
|
+
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
|
|
57
|
+
}
|
|
58
|
+
}
|