@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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +278 -83
  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.281",
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 statePath2 = typeof pathRaw === "string" && pathRaw.trim().length > 0 ? pathRaw.trim() : String(github.repo);
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(statePath2)
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 `goals/instances/${safePathSegment(goalId)}/state.json`;
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 goalStatePath = stringValue(stateRepo?.goalStatePath);
6982
+ const goalStatePath2 = stringValue(stateRepo?.goalStatePath);
6988
6983
  const logPath = stringValue(stateRepo?.logPath);
6989
- if (repo && goalStatePath) links.goalState = githubBlobUrl(repo, goalStatePath);
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 statePath(goalId) {
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 = statePath(goalId);
7262
+ const filePath = goalStatePath(goalId);
7093
7263
  const loaded = readStateText(config, cwd, filePath);
7094
- if (!loaded) return null;
7095
- return parseGoalState(loaded.path, JSON.parse(loaded.content));
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
- upsertStateText(config, cwd, statePath(goalId), serializeGoalState(state), message);
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 entry of entries) {
7162
- const id = typeof entry.name === "string" ? entry.name.trim() : "";
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 stringArray(value) {
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 = stringArray(destination.evidence);
7310
- const capabilities = stringArray(state.extra.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 = stringArray(state.extra.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 = stringArray2(input.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: stringArray2(input.goals).filter(isSlug),
8560
- loops: stringArray2(input.loops).filter(isSlug),
8561
- capabilities: stringArray2(input.capabilities).filter(isSlug),
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 stringArray2(value) {
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 = stringArray2(value);
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 = stringField2(input.id);
8828
+ const id = stringField3(input.id);
8633
8829
  if (!id || !isCompanyIntentId(id)) throw new Error(`${path50}: invalid intent id`);
8634
- const createdAt = stringField2(input.createdAt) || nowIso();
8635
- const updatedAt = stringField2(input.updatedAt) || createdAt;
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: stringField2(input.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: stringArray3(recordField(input.scope)?.repos),
8649
- areas: stringArray3(recordField(input.scope)?.areas)
8844
+ repos: stringArray4(recordField2(input.scope)?.repos),
8845
+ areas: stringArray4(recordField2(input.scope)?.areas)
8650
8846
  },
8651
- principles: stringArray3(input.principles),
8652
- metrics: stringArray3(input.metrics),
8847
+ principles: stringArray4(input.principles),
8848
+ metrics: stringArray4(input.metrics),
8653
8849
  policy: {
8654
- release: normalizeReleasePolicy(recordField(recordField(input.policy)?.release)),
8655
- automation: normalizeAutomationPolicy(recordField(recordField(input.policy)?.automation))
8850
+ release: normalizeReleasePolicy(recordField2(recordField2(input.policy)?.release)),
8851
+ automation: normalizeAutomationPolicy(recordField2(recordField2(input.policy)?.automation))
8656
8852
  },
8657
8853
  portfolio: {
8658
- goals: stringArray3(recordField(input.portfolio)?.goals).filter(isCompanyIntentId),
8659
- loops: stringArray3(recordField(input.portfolio)?.loops).filter(isCompanyIntentId),
8660
- capabilities: stringArray3(recordField(input.portfolio)?.capabilities).filter(isCompanyIntentId)
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(recordField(input.manager)),
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 entry of entries) {
8701
- if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
8702
- const file = readStateText(config, cwd, `goals/instances/${entry.name}/state.json`);
8703
- if (!file) continue;
8704
- const state = parseGoalState(file.path, JSON.parse(file.content));
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: entry.name,
8901
+ id,
8708
8902
  state: state.state,
8709
- type: stringField2(state.extra.type) || void 0,
8710
- outcome: stringField2(destination?.outcome) || void 0,
8711
- capabilities: stringArray3(state.extra.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
- upsertStateText(config, cwd, `goals/instances/${id}/state.json`, serializeGoalState(state), message);
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 stringField2(value) {
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 recordField(value) {
8925
+ function recordField2(value) {
8732
8926
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
8733
8927
  }
8734
- function stringArray3(value) {
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: stringArray3(raw?.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 = recordField2(snapshot, "facts") ?? recordField2(state.extra, "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: ${stringField3(snapshot, "stage") ?? stringField3(state.extra, "stage") ?? "unknown"}`,
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: ${stringField3(latestEvent, "event") ?? "unknown"}`,
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 = stringField3(latestEvent, "reason") ?? stringField3(recordField2(latestEvent, "decision"), "reason");
9365
+ const eventReason = stringField4(latestEvent, "reason") ?? stringField4(recordField3(latestEvent, "decision"), "reason");
9171
9366
  if (eventReason) return eventReason;
9172
- const summary = stringField3(latestOutput, "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: ${stringField3(output, "status") ?? "unknown"}`,
9181
- `- Summary: ${stringField3(output, "summary") ?? "no 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(recordField2(output, "evidence") ?? {})}`,
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 = recordField2(latestEvent, "dispatchContext");
9385
+ const context = recordField3(latestEvent, "dispatchContext");
9191
9386
  if (!context) return ["- none"];
9192
- const githubActor = stringField3(context, "githubActor");
9193
- const githubActorRole = stringField3(context, "githubActorRole");
9194
- const target = dispatchTargetLabel(recordField2(context, "target"));
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: ${stringField3(context, "triggeredBy") ?? "unknown"}`,
9197
- `- Mode: ${stringField3(context, "dispatchMode") ?? "unknown"}`,
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: ${stringField3(context, "decidedBy") ?? "unknown"}`,
9200
- `- Dispatched by: ${stringField3(context, "dispatchedBy") ?? "unknown"}`,
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 = stringField3(target, "type");
9206
- const id = stringField3(target, "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 stringField3(record2, key) {
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 recordField2(record2, key) {
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 = stringField3(recordField2(latestEvent, "decision"), "kind") ?? stringField3(latestEvent, "status");
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 statePath2 = typeof pathRaw === "string" && pathRaw.trim().length > 0 ? pathRaw.trim() : github.repo;
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(statePath2)
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.281",
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",