@kody-ade/kody-engine 0.4.281 → 0.4.283
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 +278 -83
- 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.283",
|
|
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",
|
|
@@ -724,10 +724,10 @@ function parseStateConfig(raw, github) {
|
|
|
724
724
|
const pathRaw = typeof raw.statePath === "string" ? raw.statePath : nested.path;
|
|
725
725
|
const stateRepo = typeof repoRaw === "string" && repoRaw.trim().length > 0 ? repoRaw.trim() : `https://github.com/${String(github.owner)}/kody-state`;
|
|
726
726
|
parseStateRepoSlug(stateRepo);
|
|
727
|
-
const
|
|
727
|
+
const statePath = typeof pathRaw === "string" && pathRaw.trim().length > 0 ? pathRaw.trim() : String(github.repo);
|
|
728
728
|
return {
|
|
729
729
|
repo: stateRepo,
|
|
730
|
-
path: normalizeStatePath(
|
|
730
|
+
path: normalizeStatePath(statePath)
|
|
731
731
|
};
|
|
732
732
|
}
|
|
733
733
|
function parseAccessConfig(raw) {
|
|
@@ -6520,11 +6520,6 @@ function planManagedGoalTick(goal) {
|
|
|
6520
6520
|
delete goal.facts.pendingEvidence;
|
|
6521
6521
|
return { kind: "done" };
|
|
6522
6522
|
}
|
|
6523
|
-
const pending = goal.facts.pendingEvidence;
|
|
6524
|
-
if (pending === missing) {
|
|
6525
|
-
const stage = typeof goal.stage === "string" ? goal.stage : "waiting";
|
|
6526
|
-
return { kind: "wait", evidence: missing, stage, reason: `waiting for evidence: ${missing}` };
|
|
6527
|
-
}
|
|
6528
6523
|
const step = goal.route.find((candidate) => candidate.evidence === missing);
|
|
6529
6524
|
if (!step) {
|
|
6530
6525
|
if (isSimpleGoal(goal) && missing === SIMPLE_GOAL_EVIDENCE) {
|
|
@@ -6745,7 +6740,7 @@ function goalRunLogPath(goalId, data) {
|
|
|
6745
6740
|
return `logs/goals/${safePathSegment(goalId)}/runs/${startedAt}-${runId}.jsonl`;
|
|
6746
6741
|
}
|
|
6747
6742
|
function goalStateLogPath(goalId) {
|
|
6748
|
-
return `
|
|
6743
|
+
return `todos/${safePathSegment(goalId)}.md`;
|
|
6749
6744
|
}
|
|
6750
6745
|
function goalRunLogSnapshot(goalId, goalState, goal) {
|
|
6751
6746
|
const requiredEvidence = [...goal.destination.evidence];
|
|
@@ -6984,9 +6979,9 @@ function linkContext(stateRepo) {
|
|
|
6984
6979
|
const server = process.env.GITHUB_SERVER_URL?.trim() || "https://github.com";
|
|
6985
6980
|
if (runId && repository) links.workflowRun = `${server}/${repository}/actions/runs/${runId}`;
|
|
6986
6981
|
const repo = stringValue(stateRepo?.repo);
|
|
6987
|
-
const
|
|
6982
|
+
const goalStatePath2 = stringValue(stateRepo?.goalStatePath);
|
|
6988
6983
|
const logPath = stringValue(stateRepo?.logPath);
|
|
6989
|
-
if (repo &&
|
|
6984
|
+
if (repo && goalStatePath2) links.goalState = githubBlobUrl(repo, goalStatePath2);
|
|
6990
6985
|
if (repo && logPath) links.log = githubBlobUrl(repo, logPath);
|
|
6991
6986
|
return Object.keys(links).length > 0 ? links : void 0;
|
|
6992
6987
|
}
|
|
@@ -7084,24 +7079,227 @@ var init_runLog = __esm({
|
|
|
7084
7079
|
}
|
|
7085
7080
|
});
|
|
7086
7081
|
|
|
7082
|
+
// src/goal/managedTodoState.ts
|
|
7083
|
+
function parseTodoGoalState(goalId, filePath, raw) {
|
|
7084
|
+
const frontmatter = parseFrontmatter(raw);
|
|
7085
|
+
const description = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(itemsBlockRe(), "").trim();
|
|
7086
|
+
const items = parseItems(raw);
|
|
7087
|
+
const destination = recordField(frontmatter.destination);
|
|
7088
|
+
const evidence = stringArray(destination.evidence).length > 0 ? stringArray(destination.evidence) : stringArray(frontmatter.evidence).length > 0 ? stringArray(frontmatter.evidence) : items.map((item) => stringField2(recordField(item.meta).evidence) || item.id).filter(Boolean);
|
|
7089
|
+
const facts = {
|
|
7090
|
+
...recordField(frontmatter.facts),
|
|
7091
|
+
...Object.fromEntries(items.map((item) => [stringField2(recordField(item.meta).evidence) || item.id, item.completed]))
|
|
7092
|
+
};
|
|
7093
|
+
return parseGoalState(filePath, {
|
|
7094
|
+
...frontmatter,
|
|
7095
|
+
id: goalId,
|
|
7096
|
+
state: frontmatter.state ?? "active",
|
|
7097
|
+
destination: {
|
|
7098
|
+
...destination,
|
|
7099
|
+
outcome: description || stringField2(destination.outcome),
|
|
7100
|
+
evidence
|
|
7101
|
+
},
|
|
7102
|
+
capabilities: stringArray(frontmatter.capabilities).length > 0 ? stringArray(frontmatter.capabilities) : items.map((item) => stringField2(recordField(item.meta).capability)).filter(Boolean),
|
|
7103
|
+
route: Array.isArray(frontmatter.route) ? frontmatter.route : routeFromItems(items),
|
|
7104
|
+
facts,
|
|
7105
|
+
blockers: stringArray(frontmatter.blockers)
|
|
7106
|
+
});
|
|
7107
|
+
}
|
|
7108
|
+
function isManagedTodoRaw(raw) {
|
|
7109
|
+
return isManagedTodoFrontmatter(parseFrontmatter(raw));
|
|
7110
|
+
}
|
|
7111
|
+
function serializeTodoGoalState(goalId, state, previousRaw) {
|
|
7112
|
+
const raw = JSON.parse(serializeGoalState(state));
|
|
7113
|
+
const destination = recordField(raw.destination);
|
|
7114
|
+
const outcome = stringField2(destination.outcome);
|
|
7115
|
+
const evidence = stringArray(destination.evidence);
|
|
7116
|
+
const route = Array.isArray(raw.route) ? raw.route : [];
|
|
7117
|
+
const facts = recordField(raw.facts);
|
|
7118
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7119
|
+
const createdAt = stringField2(raw.createdAt) || stringField2(raw.startedAt) || now;
|
|
7120
|
+
const routeByEvidence = new Map(route.map((step) => [stringField2(step.evidence), step]));
|
|
7121
|
+
const previousItems = new Map(parseItems(previousRaw ?? "").map((item) => [item.id, item]));
|
|
7122
|
+
const items = evidence.length > 0 ? evidence.map((key) => itemFromEvidence(key, routeByEvidence.get(key), facts, createdAt, now, previousItems.get(key))) : stringArray(raw.capabilities).map(
|
|
7123
|
+
(capability) => itemFromCapability(capability, createdAt, previousItems.get(capability))
|
|
7124
|
+
);
|
|
7125
|
+
delete raw.destination;
|
|
7126
|
+
raw.id = goalId;
|
|
7127
|
+
raw.title = goalId;
|
|
7128
|
+
raw.createdAt = createdAt;
|
|
7129
|
+
raw.managed = true;
|
|
7130
|
+
raw.managedModel = raw.scheduleMode === "agentLoop" || raw.type === "agentLoop" ? "agentLoop" : "agentGoal";
|
|
7131
|
+
raw.evidence = evidence;
|
|
7132
|
+
return [
|
|
7133
|
+
"---",
|
|
7134
|
+
...Object.entries(raw).filter(([, value]) => value !== void 0).map(([key, value]) => `${key}: ${serializeFrontmatterValue(value)}`),
|
|
7135
|
+
"---",
|
|
7136
|
+
"",
|
|
7137
|
+
outcome,
|
|
7138
|
+
"",
|
|
7139
|
+
"<!-- kody-todo-items-json",
|
|
7140
|
+
JSON.stringify(items, null, 2),
|
|
7141
|
+
"-->",
|
|
7142
|
+
""
|
|
7143
|
+
].join("\n");
|
|
7144
|
+
}
|
|
7145
|
+
function isManagedTodoFrontmatter(frontmatter) {
|
|
7146
|
+
return frontmatter.managed === true || frontmatter.managed === "true" || frontmatter.managedModel === "agentGoal" || frontmatter.managedModel === "agentLoop";
|
|
7147
|
+
}
|
|
7148
|
+
function itemFromEvidence(evidence, step, facts, createdAt, now, prior) {
|
|
7149
|
+
const completed = facts[evidence] === true;
|
|
7150
|
+
return {
|
|
7151
|
+
id: evidence,
|
|
7152
|
+
title: (prior?.title ?? stringField2(step?.stage)) || evidence,
|
|
7153
|
+
body: prior?.body ?? "",
|
|
7154
|
+
assignee: prior?.assignee ?? null,
|
|
7155
|
+
completed,
|
|
7156
|
+
createdAt: prior?.createdAt ?? createdAt,
|
|
7157
|
+
completedAt: completed ? prior?.completedAt ?? now : null,
|
|
7158
|
+
meta: {
|
|
7159
|
+
...prior?.meta ?? {},
|
|
7160
|
+
evidence,
|
|
7161
|
+
...step ? {
|
|
7162
|
+
stage: stringField2(step.stage),
|
|
7163
|
+
capability: stringField2(step.capability),
|
|
7164
|
+
...step.args && typeof step.args === "object" ? { args: step.args } : {},
|
|
7165
|
+
...step.saveReport === true ? { saveReport: true } : {}
|
|
7166
|
+
} : {}
|
|
7167
|
+
}
|
|
7168
|
+
};
|
|
7169
|
+
}
|
|
7170
|
+
function itemFromCapability(capability, createdAt, prior) {
|
|
7171
|
+
return {
|
|
7172
|
+
id: capability,
|
|
7173
|
+
title: prior?.title ?? capability,
|
|
7174
|
+
body: prior?.body ?? "",
|
|
7175
|
+
assignee: prior?.assignee ?? null,
|
|
7176
|
+
completed: prior?.completed ?? false,
|
|
7177
|
+
createdAt: prior?.createdAt ?? createdAt,
|
|
7178
|
+
completedAt: prior?.completedAt ?? null,
|
|
7179
|
+
meta: { ...prior?.meta ?? {}, capability }
|
|
7180
|
+
};
|
|
7181
|
+
}
|
|
7182
|
+
function routeFromItems(items) {
|
|
7183
|
+
return items.flatMap((item) => {
|
|
7184
|
+
const meta = recordField(item.meta);
|
|
7185
|
+
const evidence = stringField2(meta.evidence) || item.id;
|
|
7186
|
+
const stage = stringField2(meta.stage);
|
|
7187
|
+
const capability = stringField2(meta.capability);
|
|
7188
|
+
if (!evidence || !stage || !capability) return [];
|
|
7189
|
+
return [{ evidence, stage, capability, ...meta.args ? { args: meta.args } : {}, ...meta.saveReport === true ? { saveReport: true } : {} }];
|
|
7190
|
+
});
|
|
7191
|
+
}
|
|
7192
|
+
function parseFrontmatter(raw) {
|
|
7193
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
|
|
7194
|
+
if (!match) return {};
|
|
7195
|
+
const parsed = {};
|
|
7196
|
+
for (const rawLine of (match[1] ?? "").split(/\r?\n/)) {
|
|
7197
|
+
const line = rawLine.trim();
|
|
7198
|
+
if (!line || line.startsWith("#")) continue;
|
|
7199
|
+
const colon = line.indexOf(":");
|
|
7200
|
+
if (colon === -1) continue;
|
|
7201
|
+
parsed[line.slice(0, colon).trim()] = parseFrontmatterValue(line.slice(colon + 1).trim());
|
|
7202
|
+
}
|
|
7203
|
+
return parsed;
|
|
7204
|
+
}
|
|
7205
|
+
function parseFrontmatterValue(raw) {
|
|
7206
|
+
let value = raw;
|
|
7207
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
7208
|
+
value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
7209
|
+
}
|
|
7210
|
+
if (value === "true") return true;
|
|
7211
|
+
if (value === "false") return false;
|
|
7212
|
+
if (value === "null") return null;
|
|
7213
|
+
if (value.startsWith("{") || value.startsWith("[") || /^-?\d+(\.\d+)?$/.test(value)) {
|
|
7214
|
+
try {
|
|
7215
|
+
return JSON.parse(value);
|
|
7216
|
+
} catch {
|
|
7217
|
+
}
|
|
7218
|
+
}
|
|
7219
|
+
return value;
|
|
7220
|
+
}
|
|
7221
|
+
function serializeFrontmatterValue(value) {
|
|
7222
|
+
if (typeof value === "string") return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
7223
|
+
return `"${JSON.stringify(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
7224
|
+
}
|
|
7225
|
+
function itemsBlockRe() {
|
|
7226
|
+
return /<!--\s*kody-todo-items-json\s*\r?\n([\s\S]*?)\r?\n-->/;
|
|
7227
|
+
}
|
|
7228
|
+
function parseItems(raw) {
|
|
7229
|
+
const match = itemsBlockRe().exec(raw);
|
|
7230
|
+
if (!match) return [];
|
|
7231
|
+
try {
|
|
7232
|
+
const parsed = JSON.parse(match[1] ?? "[]");
|
|
7233
|
+
return Array.isArray(parsed) ? parsed.filter((item) => item && typeof item === "object") : [];
|
|
7234
|
+
} catch {
|
|
7235
|
+
return [];
|
|
7236
|
+
}
|
|
7237
|
+
}
|
|
7238
|
+
function recordField(value) {
|
|
7239
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7240
|
+
}
|
|
7241
|
+
function stringField2(value) {
|
|
7242
|
+
return typeof value === "string" ? value : "";
|
|
7243
|
+
}
|
|
7244
|
+
function stringArray(value) {
|
|
7245
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
7246
|
+
}
|
|
7247
|
+
var init_managedTodoState = __esm({
|
|
7248
|
+
"src/goal/managedTodoState.ts"() {
|
|
7249
|
+
"use strict";
|
|
7250
|
+
init_state2();
|
|
7251
|
+
}
|
|
7252
|
+
});
|
|
7253
|
+
|
|
7087
7254
|
// src/goal/stateStore.ts
|
|
7088
|
-
function
|
|
7255
|
+
function goalStatePath(goalId) {
|
|
7256
|
+
return `todos/${goalId}.md`;
|
|
7257
|
+
}
|
|
7258
|
+
function legacyGoalStatePath(goalId) {
|
|
7089
7259
|
return `goals/instances/${goalId}/state.json`;
|
|
7090
7260
|
}
|
|
7091
7261
|
function fetchGoalState(config, goalId, cwd) {
|
|
7092
|
-
const filePath =
|
|
7262
|
+
const filePath = goalStatePath(goalId);
|
|
7093
7263
|
const loaded = readStateText(config, cwd, filePath);
|
|
7094
|
-
if (
|
|
7095
|
-
|
|
7264
|
+
if (loaded) {
|
|
7265
|
+
if (!isManagedTodoRaw(loaded.content)) return null;
|
|
7266
|
+
return parseTodoGoalState(goalId, loaded.path, loaded.content);
|
|
7267
|
+
}
|
|
7268
|
+
const legacyPath = legacyGoalStatePath(goalId);
|
|
7269
|
+
const legacy = readStateText(config, cwd, legacyPath);
|
|
7270
|
+
if (!legacy) return null;
|
|
7271
|
+
return parseGoalState(legacy.path, JSON.parse(legacy.content));
|
|
7096
7272
|
}
|
|
7097
7273
|
function putGoalState(config, goalId, state, message = `chore(goals): update ${goalId}`, cwd) {
|
|
7098
|
-
|
|
7274
|
+
const previous = readStateText(config, cwd, goalStatePath(goalId));
|
|
7275
|
+
if (previous && !isManagedTodoRaw(previous.content)) {
|
|
7276
|
+
throw new Error(`Cannot overwrite regular todo list ${goalId} as managed goal`);
|
|
7277
|
+
}
|
|
7278
|
+
upsertStateText(config, cwd, goalStatePath(goalId), serializeTodoGoalState(goalId, state, previous?.content), message);
|
|
7279
|
+
}
|
|
7280
|
+
function listGoalStateIds(config, cwd) {
|
|
7281
|
+
const ids = /* @__PURE__ */ new Set();
|
|
7282
|
+
const todoFileIds = /* @__PURE__ */ new Set();
|
|
7283
|
+
for (const entry of listStateDirectory(config, cwd, "todos")) {
|
|
7284
|
+
if (entry.type !== "file" || !entry.name?.endsWith(".md")) continue;
|
|
7285
|
+
const id = entry.name.slice(0, -3);
|
|
7286
|
+
todoFileIds.add(id);
|
|
7287
|
+
const loaded = readStateText(config, cwd, goalStatePath(id));
|
|
7288
|
+
if (loaded && isManagedTodoRaw(loaded.content)) ids.add(id);
|
|
7289
|
+
}
|
|
7290
|
+
for (const entry of listStateDirectory(config, cwd, "goals/instances")) {
|
|
7291
|
+
if (entry.type !== "dir" || !entry.name) continue;
|
|
7292
|
+
if (todoFileIds.has(entry.name)) continue;
|
|
7293
|
+
ids.add(entry.name);
|
|
7294
|
+
}
|
|
7295
|
+
return [...ids].sort();
|
|
7099
7296
|
}
|
|
7100
7297
|
var init_stateStore = __esm({
|
|
7101
7298
|
"src/goal/stateStore.ts"() {
|
|
7102
7299
|
"use strict";
|
|
7103
7300
|
init_stateRepo();
|
|
7104
7301
|
init_state2();
|
|
7302
|
+
init_managedTodoState();
|
|
7105
7303
|
}
|
|
7106
7304
|
});
|
|
7107
7305
|
|
|
@@ -7156,10 +7354,9 @@ function hasExplicitStateRepo(config) {
|
|
|
7156
7354
|
return !!state && typeof state.repo === "string" && state.repo.trim().length > 0 && typeof state.path === "string" && state.path.trim().length > 0;
|
|
7157
7355
|
}
|
|
7158
7356
|
function findActiveTargetInstance(config, cwd, loopGoalId, targetId) {
|
|
7159
|
-
const entries = listStateDirectory(config, cwd, "goals/instances");
|
|
7160
7357
|
const candidates = [];
|
|
7161
|
-
for (const
|
|
7162
|
-
const id =
|
|
7358
|
+
for (const entryId of listGoalStateIds(config, cwd)) {
|
|
7359
|
+
const id = entryId.trim();
|
|
7163
7360
|
if (!id || id === loopGoalId || id === targetId || !id.startsWith(`${targetId}-`)) continue;
|
|
7164
7361
|
assertSafeGoalId(id, "goal instance");
|
|
7165
7362
|
const state = fetchGoalState(config, id, cwd);
|
|
@@ -7261,7 +7458,6 @@ var init_targetLoopResolution = __esm({
|
|
|
7261
7458
|
"src/goal/targetLoopResolution.ts"() {
|
|
7262
7459
|
"use strict";
|
|
7263
7460
|
init_companyStore();
|
|
7264
|
-
init_stateRepo();
|
|
7265
7461
|
init_stateStore();
|
|
7266
7462
|
}
|
|
7267
7463
|
});
|
|
@@ -7276,7 +7472,7 @@ function cloneRoute(route) {
|
|
|
7276
7472
|
...step.args ? { args: structuredClone(step.args) } : {}
|
|
7277
7473
|
}));
|
|
7278
7474
|
}
|
|
7279
|
-
function
|
|
7475
|
+
function stringArray2(value) {
|
|
7280
7476
|
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : null;
|
|
7281
7477
|
}
|
|
7282
7478
|
function routeArray(value) {
|
|
@@ -7306,11 +7502,11 @@ function expandManagedGoalState(state) {
|
|
|
7306
7502
|
if (!definition) return state;
|
|
7307
7503
|
const destination = state.extra.destination && typeof state.extra.destination === "object" && !Array.isArray(state.extra.destination) ? { ...state.extra.destination } : {};
|
|
7308
7504
|
const outcome = typeof destination.outcome === "string" ? destination.outcome : "";
|
|
7309
|
-
const evidence =
|
|
7310
|
-
const capabilities =
|
|
7505
|
+
const evidence = stringArray2(destination.evidence);
|
|
7506
|
+
const capabilities = stringArray2(state.extra.capabilities);
|
|
7311
7507
|
const route = routeArray(state.extra.route);
|
|
7312
7508
|
const facts = state.extra.facts && typeof state.extra.facts === "object" && !Array.isArray(state.extra.facts) ? { ...state.extra.facts } : {};
|
|
7313
|
-
const blockers =
|
|
7509
|
+
const blockers = stringArray2(state.extra.blockers);
|
|
7314
7510
|
return {
|
|
7315
7511
|
...state,
|
|
7316
7512
|
extra: {
|
|
@@ -8517,7 +8713,7 @@ function parseAction(value) {
|
|
|
8517
8713
|
function parseCreateManagedGoal(input) {
|
|
8518
8714
|
const route = Array.isArray(input.route) ? input.route.map(parseRouteStep) : [];
|
|
8519
8715
|
if (route.length === 0) throw new Error("createManagedGoal requires route");
|
|
8520
|
-
const evidence =
|
|
8716
|
+
const evidence = stringArray3(input.evidence);
|
|
8521
8717
|
if (evidence.length === 0) throw new Error("createManagedGoal requires evidence");
|
|
8522
8718
|
return {
|
|
8523
8719
|
kind: "createManagedGoal",
|
|
@@ -8556,9 +8752,9 @@ function parseUpdateIntentPortfolio(input) {
|
|
|
8556
8752
|
return {
|
|
8557
8753
|
kind: "updateIntentPortfolio",
|
|
8558
8754
|
intentId: slug(input.intentId, "intentId"),
|
|
8559
|
-
goals:
|
|
8560
|
-
loops:
|
|
8561
|
-
capabilities:
|
|
8755
|
+
goals: stringArray3(input.goals).filter(isSlug),
|
|
8756
|
+
loops: stringArray3(input.loops).filter(isSlug),
|
|
8757
|
+
capabilities: stringArray3(input.capabilities).filter(isSlug),
|
|
8562
8758
|
reason: requiredString(input.reason, "reason")
|
|
8563
8759
|
};
|
|
8564
8760
|
}
|
|
@@ -8592,12 +8788,12 @@ function requiredString(value, field) {
|
|
|
8592
8788
|
if (typeof value !== "string" || !value.trim()) throw new Error(`${field} is required`);
|
|
8593
8789
|
return value.trim();
|
|
8594
8790
|
}
|
|
8595
|
-
function
|
|
8791
|
+
function stringArray3(value) {
|
|
8596
8792
|
if (!Array.isArray(value)) return [];
|
|
8597
8793
|
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
8598
8794
|
}
|
|
8599
8795
|
function nonEmptyStringArray(value, field) {
|
|
8600
|
-
const values =
|
|
8796
|
+
const values = stringArray3(value);
|
|
8601
8797
|
if (values.length === 0) throw new Error(`${field} must not be empty`);
|
|
8602
8798
|
return values;
|
|
8603
8799
|
}
|
|
@@ -8629,15 +8825,15 @@ function normalizeCompanyIntent(path50, raw) {
|
|
|
8629
8825
|
throw new Error(`${path50}: intent must be JSON object`);
|
|
8630
8826
|
}
|
|
8631
8827
|
const input = raw;
|
|
8632
|
-
const id =
|
|
8828
|
+
const id = stringField3(input.id);
|
|
8633
8829
|
if (!id || !isCompanyIntentId(id)) throw new Error(`${path50}: invalid intent id`);
|
|
8634
|
-
const createdAt =
|
|
8635
|
-
const updatedAt =
|
|
8830
|
+
const createdAt = stringField3(input.createdAt) || nowIso();
|
|
8831
|
+
const updatedAt = stringField3(input.updatedAt) || createdAt;
|
|
8636
8832
|
return {
|
|
8637
8833
|
version: 1,
|
|
8638
8834
|
id,
|
|
8639
8835
|
status: oneOf2(input.status, ["active", "paused", "archived"], "active"),
|
|
8640
|
-
for:
|
|
8836
|
+
for: stringField3(input.for),
|
|
8641
8837
|
priority: numberField(input.priority, 100),
|
|
8642
8838
|
posture: oneOf2(
|
|
8643
8839
|
input.posture,
|
|
@@ -8645,21 +8841,21 @@ function normalizeCompanyIntent(path50, raw) {
|
|
|
8645
8841
|
"balanced"
|
|
8646
8842
|
),
|
|
8647
8843
|
scope: {
|
|
8648
|
-
repos:
|
|
8649
|
-
areas:
|
|
8844
|
+
repos: stringArray4(recordField2(input.scope)?.repos),
|
|
8845
|
+
areas: stringArray4(recordField2(input.scope)?.areas)
|
|
8650
8846
|
},
|
|
8651
|
-
principles:
|
|
8652
|
-
metrics:
|
|
8847
|
+
principles: stringArray4(input.principles),
|
|
8848
|
+
metrics: stringArray4(input.metrics),
|
|
8653
8849
|
policy: {
|
|
8654
|
-
release: normalizeReleasePolicy(
|
|
8655
|
-
automation: normalizeAutomationPolicy(
|
|
8850
|
+
release: normalizeReleasePolicy(recordField2(recordField2(input.policy)?.release)),
|
|
8851
|
+
automation: normalizeAutomationPolicy(recordField2(recordField2(input.policy)?.automation))
|
|
8656
8852
|
},
|
|
8657
8853
|
portfolio: {
|
|
8658
|
-
goals:
|
|
8659
|
-
loops:
|
|
8660
|
-
capabilities:
|
|
8854
|
+
goals: stringArray4(recordField2(input.portfolio)?.goals).filter(isCompanyIntentId),
|
|
8855
|
+
loops: stringArray4(recordField2(input.portfolio)?.loops).filter(isCompanyIntentId),
|
|
8856
|
+
capabilities: stringArray4(recordField2(input.portfolio)?.capabilities).filter(isCompanyIntentId)
|
|
8661
8857
|
},
|
|
8662
|
-
manager: normalizeManager(
|
|
8858
|
+
manager: normalizeManager(recordField2(input.manager)),
|
|
8663
8859
|
createdAt,
|
|
8664
8860
|
updatedAt
|
|
8665
8861
|
};
|
|
@@ -8695,20 +8891,18 @@ function appendCompanyIntentDecision(config, cwd, intentId, entry) {
|
|
|
8695
8891
|
appendStateLine(config, cwd, `intents/${intentId}/decisions.jsonl`, JSON.stringify(entry), `chore(intents): log ${intentId} decision`);
|
|
8696
8892
|
}
|
|
8697
8893
|
function listCompanyPortfolio(config, cwd) {
|
|
8698
|
-
const entries = listStateDirectory(config, cwd, "goals/instances");
|
|
8699
8894
|
const goals = [];
|
|
8700
|
-
for (const
|
|
8701
|
-
if (
|
|
8702
|
-
const
|
|
8703
|
-
if (!
|
|
8704
|
-
const
|
|
8705
|
-
const destination = recordField(state.extra.destination);
|
|
8895
|
+
for (const id of listGoalStateIds(config, cwd)) {
|
|
8896
|
+
if (!isCompanyIntentId(id)) continue;
|
|
8897
|
+
const state = fetchGoalState(config, id, cwd);
|
|
8898
|
+
if (!state) continue;
|
|
8899
|
+
const destination = recordField2(state.extra.destination);
|
|
8706
8900
|
goals.push({
|
|
8707
|
-
id
|
|
8901
|
+
id,
|
|
8708
8902
|
state: state.state,
|
|
8709
|
-
type:
|
|
8710
|
-
outcome:
|
|
8711
|
-
capabilities:
|
|
8903
|
+
type: stringField3(state.extra.type) || void 0,
|
|
8904
|
+
outcome: stringField3(destination?.outcome) || void 0,
|
|
8905
|
+
capabilities: stringArray4(state.extra.capabilities),
|
|
8712
8906
|
isLoop: state.extra.scheduleMode === "agentLoop" || state.extra.type === "agentLoop",
|
|
8713
8907
|
updatedAt: state.updatedAt
|
|
8714
8908
|
});
|
|
@@ -8717,21 +8911,21 @@ function listCompanyPortfolio(config, cwd) {
|
|
|
8717
8911
|
}
|
|
8718
8912
|
function writeCompanyGoalState(config, cwd, id, state, message) {
|
|
8719
8913
|
assertIntentId(id);
|
|
8720
|
-
|
|
8914
|
+
putGoalState(config, id, state, message, cwd);
|
|
8721
8915
|
}
|
|
8722
8916
|
function assertIntentId(id) {
|
|
8723
8917
|
if (!isCompanyIntentId(id)) throw new Error(`invalid intent/portfolio id: ${id}`);
|
|
8724
8918
|
}
|
|
8725
|
-
function
|
|
8919
|
+
function stringField3(value) {
|
|
8726
8920
|
return typeof value === "string" ? value.trim() : "";
|
|
8727
8921
|
}
|
|
8728
8922
|
function numberField(value, fallback) {
|
|
8729
8923
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
8730
8924
|
}
|
|
8731
|
-
function
|
|
8925
|
+
function recordField2(value) {
|
|
8732
8926
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
8733
8927
|
}
|
|
8734
|
-
function
|
|
8928
|
+
function stringArray4(value) {
|
|
8735
8929
|
if (!Array.isArray(value)) return [];
|
|
8736
8930
|
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
8737
8931
|
}
|
|
@@ -8752,7 +8946,7 @@ function normalizeAutomationPolicy(raw) {
|
|
|
8752
8946
|
authority: "full-auto",
|
|
8753
8947
|
maxConcurrentGoals: Math.max(1, Math.floor(numberField(raw?.maxConcurrentGoals, 1))),
|
|
8754
8948
|
maxDailyActions: Math.max(1, Math.floor(numberField(raw?.maxDailyActions, 6))),
|
|
8755
|
-
requiresHumanFor:
|
|
8949
|
+
requiresHumanFor: stringArray4(raw?.requiresHumanFor)
|
|
8756
8950
|
};
|
|
8757
8951
|
}
|
|
8758
8952
|
function normalizeManager(raw) {
|
|
@@ -8769,6 +8963,7 @@ var init_companyIntent = __esm({
|
|
|
8769
8963
|
"src/companyIntent.ts"() {
|
|
8770
8964
|
"use strict";
|
|
8771
8965
|
init_state2();
|
|
8966
|
+
init_stateStore();
|
|
8772
8967
|
init_stateRepo();
|
|
8773
8968
|
SLUG_RE2 = /^[a-z][a-z0-9-]{0,63}$/;
|
|
8774
8969
|
}
|
|
@@ -9115,7 +9310,7 @@ function capabilityEvidenceOutput(evidence) {
|
|
|
9115
9310
|
function goalReportBody(goalId, state, snapshot, latestEvent, evidenceItems) {
|
|
9116
9311
|
const outputs = evidenceItems.map(capabilityEvidenceOutput);
|
|
9117
9312
|
const latestOutput = outputs.at(-1);
|
|
9118
|
-
const facts =
|
|
9313
|
+
const facts = recordField3(snapshot, "facts") ?? recordField3(state.extra, "facts") ?? {};
|
|
9119
9314
|
const blockers = uniqueStrings2([
|
|
9120
9315
|
...stringArrayField(snapshot, "blockers"),
|
|
9121
9316
|
...stringArrayField(latestEvent, "blockers"),
|
|
@@ -9134,12 +9329,12 @@ function goalReportBody(goalId, state, snapshot, latestEvent, evidenceItems) {
|
|
|
9134
9329
|
"",
|
|
9135
9330
|
"## Status",
|
|
9136
9331
|
`- State: ${state.state}`,
|
|
9137
|
-
`- Stage: ${
|
|
9332
|
+
`- Stage: ${stringField4(snapshot, "stage") ?? stringField4(state.extra, "stage") ?? "unknown"}`,
|
|
9138
9333
|
`- Next step: ${nextStepFromEvent(state, snapshot, latestOutput, latestEvent)}`,
|
|
9139
9334
|
`- Updated: ${state.updatedAt ?? state.createdAt ?? state.startedAt ?? "unknown"}`,
|
|
9140
9335
|
"",
|
|
9141
9336
|
"## Decision",
|
|
9142
|
-
`- Event: ${
|
|
9337
|
+
`- Event: ${stringField4(latestEvent, "event") ?? "unknown"}`,
|
|
9143
9338
|
`- Reason: ${decisionReason(state, latestEvent, latestOutput, missingEvidence, blockers)}`,
|
|
9144
9339
|
`- Required evidence: ${listOrNone(stringArrayField(snapshot, "requiredEvidence"))}`,
|
|
9145
9340
|
`- Satisfied evidence: ${listOrNone(stringArrayField(snapshot, "satisfiedEvidence"))}`,
|
|
@@ -9167,9 +9362,9 @@ function capabilityEvidenceMarkdown(outputs) {
|
|
|
9167
9362
|
function decisionReason(state, latestEvent, latestOutput, missingEvidence, blockers) {
|
|
9168
9363
|
if (state.state === "done") return "destination evidence satisfied";
|
|
9169
9364
|
if (blockers.length > 0) return blockers[0] ?? "blocked";
|
|
9170
|
-
const eventReason =
|
|
9365
|
+
const eventReason = stringField4(latestEvent, "reason") ?? stringField4(recordField3(latestEvent, "decision"), "reason");
|
|
9171
9366
|
if (eventReason) return eventReason;
|
|
9172
|
-
const summary =
|
|
9367
|
+
const summary = stringField4(latestOutput, "summary");
|
|
9173
9368
|
if (summary) return summary;
|
|
9174
9369
|
if (missingEvidence.length > 0) return `waiting for ${missingEvidence[0]}`;
|
|
9175
9370
|
return "waiting for more evidence";
|
|
@@ -9177,33 +9372,33 @@ function decisionReason(state, latestEvent, latestOutput, missingEvidence, block
|
|
|
9177
9372
|
function evidenceOutputMarkdown(index, output) {
|
|
9178
9373
|
return [
|
|
9179
9374
|
`### Output ${index}`,
|
|
9180
|
-
`- Status: ${
|
|
9181
|
-
`- Summary: ${
|
|
9375
|
+
`- Status: ${stringField4(output, "status") ?? "unknown"}`,
|
|
9376
|
+
`- Summary: ${stringField4(output, "summary") ?? "no summary"}`,
|
|
9182
9377
|
`- Sources: ${listOrNone(stringArrayField(output, "sources"))}`,
|
|
9183
|
-
`- Evidence values: ${inlineJson(
|
|
9378
|
+
`- Evidence values: ${inlineJson(recordField3(output, "evidence") ?? {})}`,
|
|
9184
9379
|
`- Missing evidence: ${listOrNone(stringArrayField(output, "missingEvidence"))}`,
|
|
9185
9380
|
`- Blockers: ${listOrNone(stringArrayField(output, "blockers"))}`,
|
|
9186
9381
|
""
|
|
9187
9382
|
];
|
|
9188
9383
|
}
|
|
9189
9384
|
function dispatchContextMarkdown(latestEvent) {
|
|
9190
|
-
const context =
|
|
9385
|
+
const context = recordField3(latestEvent, "dispatchContext");
|
|
9191
9386
|
if (!context) return ["- none"];
|
|
9192
|
-
const githubActor =
|
|
9193
|
-
const githubActorRole =
|
|
9194
|
-
const target = dispatchTargetLabel(
|
|
9387
|
+
const githubActor = stringField4(context, "githubActor");
|
|
9388
|
+
const githubActorRole = stringField4(context, "githubActorRole");
|
|
9389
|
+
const target = dispatchTargetLabel(recordField3(context, "target"));
|
|
9195
9390
|
return [
|
|
9196
|
-
`- Triggered by: ${
|
|
9197
|
-
`- Mode: ${
|
|
9391
|
+
`- Triggered by: ${stringField4(context, "triggeredBy") ?? "unknown"}`,
|
|
9392
|
+
`- Mode: ${stringField4(context, "dispatchMode") ?? "unknown"}`,
|
|
9198
9393
|
`- GitHub actor: ${githubActor ? `${githubActor}${githubActorRole ? ` (${githubActorRole})` : ""}` : "none"}`,
|
|
9199
|
-
`- Decided by: ${
|
|
9200
|
-
`- Dispatched by: ${
|
|
9394
|
+
`- Decided by: ${stringField4(context, "decidedBy") ?? "unknown"}`,
|
|
9395
|
+
`- Dispatched by: ${stringField4(context, "dispatchedBy") ?? "unknown"}`,
|
|
9201
9396
|
`- Target: ${target ?? "none"}`
|
|
9202
9397
|
];
|
|
9203
9398
|
}
|
|
9204
9399
|
function dispatchTargetLabel(target) {
|
|
9205
|
-
const type =
|
|
9206
|
-
const id =
|
|
9400
|
+
const type = stringField4(target, "type");
|
|
9401
|
+
const id = stringField4(target, "id");
|
|
9207
9402
|
if (type && id) return `${type} ${id}`;
|
|
9208
9403
|
return id ?? type;
|
|
9209
9404
|
}
|
|
@@ -9226,11 +9421,11 @@ function listOrNone(values) {
|
|
|
9226
9421
|
function uniqueStrings2(values) {
|
|
9227
9422
|
return [...new Set(values)].sort();
|
|
9228
9423
|
}
|
|
9229
|
-
function
|
|
9424
|
+
function stringField4(record2, key) {
|
|
9230
9425
|
const value = record2?.[key];
|
|
9231
9426
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
9232
9427
|
}
|
|
9233
|
-
function
|
|
9428
|
+
function recordField3(record2, key) {
|
|
9234
9429
|
const value = record2?.[key];
|
|
9235
9430
|
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : void 0;
|
|
9236
9431
|
}
|
|
@@ -9263,7 +9458,7 @@ ${artifact.path ?? ""}`;
|
|
|
9263
9458
|
}
|
|
9264
9459
|
function nextStepFromEvent(state, goalAfter, capabilityOutput, latestEvent) {
|
|
9265
9460
|
if (state.state === "done") return "done";
|
|
9266
|
-
const decisionKind =
|
|
9461
|
+
const decisionKind = stringField4(recordField3(latestEvent, "decision"), "kind") ?? stringField4(latestEvent, "status");
|
|
9267
9462
|
if (decisionKind === "done") return "done";
|
|
9268
9463
|
if (decisionKind === "dispatch") return "dispatch";
|
|
9269
9464
|
if (decisionKind === "blocked" || decisionKind === "reject-evidence") return "block";
|
|
@@ -15504,12 +15699,12 @@ async function loadGithubStateConfig(opts) {
|
|
|
15504
15699
|
const pathRaw = typeof raw.statePath === "string" ? raw.statePath : nestedState.path;
|
|
15505
15700
|
const stateRepo = typeof repoRaw === "string" && repoRaw.trim().length > 0 ? repoRaw.trim() : `https://github.com/${github.owner}/kody-state`;
|
|
15506
15701
|
parseStateRepoSlug(stateRepo);
|
|
15507
|
-
const
|
|
15702
|
+
const statePath = typeof pathRaw === "string" && pathRaw.trim().length > 0 ? pathRaw.trim() : github.repo;
|
|
15508
15703
|
return {
|
|
15509
15704
|
github,
|
|
15510
15705
|
state: {
|
|
15511
15706
|
repo: stateRepo,
|
|
15512
|
-
path: normalizeStatePath(
|
|
15707
|
+
path: normalizeStatePath(statePath)
|
|
15513
15708
|
}
|
|
15514
15709
|
};
|
|
15515
15710
|
}
|
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.283",
|
|
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",
|