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