@kody-ade/kody-engine 0.4.392 → 0.4.394

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 +98 -36
  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.391",
18
+ version: "0.4.394",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -3931,6 +3931,32 @@ function createStateBackendFromEnv(env = process.env, client) {
3931
3931
  meta,
3932
3932
  updatedAt
3933
3933
  });
3934
+ },
3935
+ async listIntents(tenantId) {
3936
+ const result = await transport.query(anyApi.intents.list, { tenantId: requireTenant(tenantId) });
3937
+ return Array.isArray(result) ? result : [];
3938
+ },
3939
+ async getIntent(tenantId, intentId) {
3940
+ const result = await transport.query(anyApi.intents.get, {
3941
+ tenantId: requireTenant(tenantId),
3942
+ intentId: requireNonEmpty(intentId, "intentId")
3943
+ });
3944
+ return result ?? null;
3945
+ },
3946
+ async saveIntent(tenantId, intentId, intent, updatedAt) {
3947
+ await transport.mutation(anyApi.intents.save, {
3948
+ tenantId: requireTenant(tenantId),
3949
+ intentId: requireNonEmpty(intentId, "intentId"),
3950
+ intent,
3951
+ updatedAt
3952
+ });
3953
+ },
3954
+ async appendIntentDecision(tenantId, intentId, decision) {
3955
+ await transport.mutation(anyApi.intents.appendDecision, {
3956
+ tenantId: requireTenant(tenantId),
3957
+ intentId: requireNonEmpty(intentId, "intentId"),
3958
+ decision
3959
+ });
3934
3960
  }
3935
3961
  };
3936
3962
  }
@@ -8900,13 +8926,24 @@ async function fetchGoalStateAsync(config, goalId, cwd) {
8900
8926
  if (backendRequired()) throw new Error("Convex backend is required for goal state in GitHub Actions");
8901
8927
  return fetchGoalStateLegacy(config, goalId, cwd);
8902
8928
  }
8903
- function fetchGoalState(config, goalId, cwd) {
8904
- return fetchGoalStateLegacy(config, goalId, cwd);
8905
- }
8906
- function putGoalState(config, goalId, state, message = `chore(goals): update ${goalId}`, cwd) {
8929
+ async function putGoalStateAsync(config, goalId, state, message = `chore(goals): update ${goalId}`, cwd) {
8930
+ const tenantId = backendTenant(config);
8931
+ if (backendEnabled(config) && tenantId) {
8932
+ const backend = createStateBackendFromEnv();
8933
+ const previous = await backend.getGoal(tenantId, goalId);
8934
+ await backend.saveGoal(tenantId, goalId, state, state.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString(), previous?.updatedAt);
8935
+ return;
8936
+ }
8937
+ if (backendRequired()) throw new Error("Convex backend is required for goal state in GitHub Actions");
8907
8938
  putGoalStateLegacy(config, goalId, state, message, cwd);
8908
8939
  }
8909
- function listGoalStateIds(config, cwd) {
8940
+ async function listGoalStateIdsAsync(config, cwd) {
8941
+ const tenantId = backendTenant(config);
8942
+ if (backendEnabled(config) && tenantId) {
8943
+ const docs = await createStateBackendFromEnv().listGoals(tenantId);
8944
+ return docs.map((doc) => doc.goalId).filter(Boolean).sort();
8945
+ }
8946
+ if (backendRequired()) throw new Error("Convex backend is required for goal state in GitHub Actions");
8910
8947
  return listGoalStateIdsLegacy(config, cwd);
8911
8948
  }
8912
8949
  var init_stateStore = __esm({
@@ -8922,11 +8959,11 @@ var init_stateStore = __esm({
8922
8959
  // src/goal/targetLoopResolution.ts
8923
8960
  import * as fs27 from "fs";
8924
8961
  import * as path25 from "path";
8925
- function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
8962
+ async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
8926
8963
  const targetId = loopGoal.loopTarget?.id.trim() ?? "";
8927
8964
  assertSafeGoalId(targetId, "loop target");
8928
8965
  if (!hasExplicitStateRepo(config)) return null;
8929
- const activeInstance = findActiveTargetInstance(config, cwd, loopGoalId, targetId);
8966
+ const activeInstance = await findActiveTargetInstance(config, cwd, loopGoalId, targetId);
8930
8967
  if (activeInstance) {
8931
8968
  return {
8932
8969
  targetId: activeInstance.id,
@@ -8934,21 +8971,21 @@ function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
8934
8971
  reason: "active target instance"
8935
8972
  };
8936
8973
  }
8937
- const directTarget = fetchGoalState(config, targetId, cwd);
8974
+ const directTarget = await fetchGoalStateAsync(config, targetId, cwd);
8938
8975
  if (directTarget?.state === "active") {
8939
8976
  return { targetId, templateId: targetId, reason: "active target goal" };
8940
8977
  }
8941
8978
  return null;
8942
8979
  }
8943
- function resolveGoalLoopTarget(config, cwd, loopGoalId, loopGoal, now) {
8980
+ async function resolveGoalLoopTarget(config, cwd, loopGoalId, loopGoal, now) {
8944
8981
  const targetId = loopGoal.loopTarget?.id.trim() ?? "";
8945
8982
  assertSafeGoalId(targetId, "loop target");
8946
8983
  if (!hasExplicitStateRepo(config)) {
8947
8984
  return { targetId, templateId: targetId, reason: "literal target; state repo not configured" };
8948
8985
  }
8949
- const activeTarget = resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal);
8986
+ const activeTarget = await resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal);
8950
8987
  if (activeTarget) return activeTarget;
8951
- const directTarget = fetchGoalState(config, targetId, cwd);
8988
+ const directTarget = await fetchGoalStateAsync(config, targetId, cwd);
8952
8989
  const template = loadGoalTemplate(cwd, targetId);
8953
8990
  if (!template) {
8954
8991
  if (directTarget) {
@@ -8956,9 +8993,9 @@ function resolveGoalLoopTarget(config, cwd, loopGoalId, loopGoal, now) {
8956
8993
  }
8957
8994
  return { targetId, templateId: targetId, reason: "literal target; no target state or template found" };
8958
8995
  }
8959
- const instanceId = chooseTargetInstanceId(config, cwd, targetId, loopGoal.preferredRunTime?.timezone, now);
8996
+ const instanceId = await chooseTargetInstanceId(config, cwd, targetId, loopGoal.preferredRunTime?.timezone, now);
8960
8997
  const instance = buildGoalTargetInstance(template, targetId, now);
8961
- putGoalState(config, instanceId, instance, `chore(goals): create ${instanceId}`, cwd);
8998
+ await putGoalStateAsync(config, instanceId, instance, `chore(goals): create ${instanceId}`, cwd);
8962
8999
  return {
8963
9000
  targetId: instanceId,
8964
9001
  templateId: targetId,
@@ -8978,13 +9015,13 @@ function hasExplicitStateRepo(config) {
8978
9015
  const state = config.state;
8979
9016
  return !!state && typeof state.repo === "string" && state.repo.trim().length > 0 && typeof state.path === "string" && state.path.trim().length > 0;
8980
9017
  }
8981
- function findActiveTargetInstance(config, cwd, loopGoalId, targetId) {
9018
+ async function findActiveTargetInstance(config, cwd, loopGoalId, targetId) {
8982
9019
  const candidates = [];
8983
- for (const entryId of listGoalStateIds(config, cwd)) {
9020
+ for (const entryId of await listGoalStateIdsAsync(config, cwd)) {
8984
9021
  const id = entryId.trim();
8985
9022
  if (!id || id === loopGoalId || id === targetId || !id.startsWith(`${targetId}-`)) continue;
8986
9023
  assertSafeGoalId(id, "goal instance");
8987
- const state = fetchGoalState(config, id, cwd);
9024
+ const state = await fetchGoalStateAsync(config, id, cwd);
8988
9025
  if (!state || state.state !== "active") continue;
8989
9026
  if (!isTargetInstanceState(id, state, targetId)) continue;
8990
9027
  candidates.push({ id, state });
@@ -9022,12 +9059,12 @@ function readJsonObject(filePath) {
9022
9059
  }
9023
9060
  return parsed;
9024
9061
  }
9025
- function chooseTargetInstanceId(config, cwd, targetId, timezone, now) {
9062
+ async function chooseTargetInstanceId(config, cwd, targetId, timezone, now) {
9026
9063
  const base = `${targetId}-${zonedDate(now, timezone ?? "UTC")}`;
9027
9064
  for (let index = 1; index <= 20; index += 1) {
9028
9065
  const id = index === 1 ? base : `${base}-${index}`;
9029
9066
  assertSafeGoalId(id, "goal instance");
9030
- const existing = fetchGoalState(config, id, cwd);
9067
+ const existing = await fetchGoalStateAsync(config, id, cwd);
9031
9068
  if (!existing || existing.state === "active") return id;
9032
9069
  }
9033
9070
  throw new Error(`could not allocate goal target instance id for ${targetId}`);
@@ -10266,7 +10303,7 @@ function scalarFacts(facts) {
10266
10303
  )
10267
10304
  );
10268
10305
  }
10269
- function autonomyBlockReason(ctx, goalId, goal, goalState, dispatch2, options = {}) {
10306
+ async function autonomyBlockReason(ctx, goalId, goal, goalState, dispatch2, options = {}) {
10270
10307
  if (ctx.data.jobForce === true) return null;
10271
10308
  const selfKind = managedModelKind(goal);
10272
10309
  const selfMode = selfKind === "Goal" ? firstTrustOverride(ctx, subjectCandidates("goal", goalId, goalState)) : null;
@@ -10282,7 +10319,7 @@ function autonomyBlockReason(ctx, goalId, goal, goalState, dispatch2, options =
10282
10319
  }
10283
10320
  const targetGoal = dispatch2.action === "goal-manager" && typeof dispatch2.cliArgs.goal === "string" ? dispatch2.cliArgs.goal : null;
10284
10321
  if (targetGoal && targetGoal !== goalId && options.checkTargets !== false) {
10285
- const target = fetchGoalState(ctx.config, targetGoal, ctx.cwd);
10322
+ const target = await fetchGoalStateAsync(ctx.config, targetGoal, ctx.cwd);
10286
10323
  const targetManaged = target ? managedGoalFromState(expandManagedGoalState(target)) : null;
10287
10324
  const targetIsGoal = targetManaged ? managedModelKind(targetManaged) === "Goal" : false;
10288
10325
  const targetMode = targetManaged && targetIsGoal ? firstTrustOverride(ctx, subjectCandidates("goal", targetGoal, target)) : null;
@@ -10616,7 +10653,7 @@ var init_advanceManagedGoal = __esm({
10616
10653
  const beforeSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
10617
10654
  const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
10618
10655
  const now = goalLoopNow();
10619
- const activeTarget = isGoalTargetLoop(managed) ? resolveActiveGoalLoopTarget(ctx.config, ctx.cwd, goal.id, managed) : null;
10656
+ const activeTarget = isGoalTargetLoop(managed) ? await resolveActiveGoalLoopTarget(ctx.config, ctx.cwd, goal.id, managed) : null;
10620
10657
  const allowSameDayTargetDispatch = isGoalTargetLoop(managed) && (!!activeTarget || previousDispatchWasTargetInstance(managed, previousScheduleState));
10621
10658
  let decision2 = planTargetLoopSchedule({
10622
10659
  goal: managed,
@@ -10625,7 +10662,7 @@ var init_advanceManagedGoal = __esm({
10625
10662
  allowSameDayTargetDispatch
10626
10663
  });
10627
10664
  let targetResolution;
10628
- const selfAutonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch, { checkTargets: false }) : null;
10665
+ const selfAutonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? await autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch, { checkTargets: false }) : null;
10629
10666
  if (selfAutonomyBlock) {
10630
10667
  restoreGoalIdFact();
10631
10668
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
@@ -10637,7 +10674,7 @@ var init_advanceManagedGoal = __esm({
10637
10674
  return;
10638
10675
  }
10639
10676
  if (decision2.kind === "dispatch" && decision2.dispatch && isGoalTargetLoop(managed)) {
10640
- targetResolution = resolveGoalLoopTarget(ctx.config, ctx.cwd, goal.id, managed, now);
10677
+ targetResolution = await resolveGoalLoopTarget(ctx.config, ctx.cwd, goal.id, managed, now);
10641
10678
  decision2 = planTargetLoopSchedule({
10642
10679
  goal: managed,
10643
10680
  previousScheduleState,
@@ -10648,7 +10685,7 @@ var init_advanceManagedGoal = __esm({
10648
10685
  }
10649
10686
  restoreGoalIdFact();
10650
10687
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
10651
- const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
10688
+ const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? await autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
10652
10689
  if (autonomyBlock) {
10653
10690
  const waitDecision = scheduleWaitDecision(previousScheduleState, decision2, autonomyBlock);
10654
10691
  goal.raw.extra.scheduleState = waitDecision.scheduleState;
@@ -10713,7 +10750,7 @@ var init_advanceManagedGoal = __esm({
10713
10750
  });
10714
10751
  restoreGoalIdFact();
10715
10752
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
10716
- const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
10753
+ const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? await autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
10717
10754
  if (autonomyBlock) {
10718
10755
  const waitDecision = scheduleWaitDecision(previousScheduleState, decision2, autonomyBlock);
10719
10756
  goal.raw.extra.scheduleState = waitDecision.scheduleState;
@@ -10783,7 +10820,7 @@ var init_advanceManagedGoal = __esm({
10783
10820
  ...decision.implementation ? { implementation: decision.implementation } : {},
10784
10821
  cliArgs: decision.cliArgs
10785
10822
  };
10786
- const autonomyBlock = autonomyBlockReason(ctx, goal.id, managed, goal.raw, planned);
10823
+ const autonomyBlock = await autonomyBlockReason(ctx, goal.id, managed, goal.raw, planned);
10787
10824
  if (autonomyBlock) {
10788
10825
  stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
10789
10826
  ctx.output.reason = autonomyBlock;
@@ -11592,7 +11629,7 @@ var init_applyCapabilityReports = __esm({
11592
11629
  if (evidenceItems.length === 0) return;
11593
11630
  const evidenceByGoal = groupGoalEvidence(evidenceItems);
11594
11631
  for (const [goalId, goalEvidence] of evidenceByGoal) {
11595
- const prior = fetchGoalState(ctx.config, goalId, ctx.cwd);
11632
+ const prior = await fetchGoalStateAsync(ctx.config, goalId, ctx.cwd);
11596
11633
  if (!prior) {
11597
11634
  stageGoalRunLogEvent(ctx.data, goalId, {
11598
11635
  source: "goal-loop",
@@ -11667,7 +11704,7 @@ var init_applyCapabilityReports = __esm({
11667
11704
  const nextForOutput = changed ? { ...next, updatedAt: nowIso() } : next;
11668
11705
  try {
11669
11706
  if (changed) {
11670
- putGoalState(ctx.config, goalId, nextForOutput, describeMessage(goalId, goalEvidence), ctx.cwd);
11707
+ await putGoalStateAsync(ctx.config, goalId, nextForOutput, describeMessage(goalId, goalEvidence), ctx.cwd);
11671
11708
  }
11672
11709
  refreshReportOrFail(ctx, goalId, nextForOutput, goalEvidence);
11673
11710
  if (changed && ctx.output.exitCode === 0 && !ctx.output.nextDispatch && shouldResumeManagedGoal(goalId, nextForOutput)) {
@@ -12015,7 +12052,7 @@ var init_commitGoalState = __esm({
12015
12052
  return;
12016
12053
  }
12017
12054
  try {
12018
- putGoalState(ctx.config, goal.id, updated, describeCommitMessage(goal), ctx.cwd);
12055
+ await putGoalStateAsync(ctx.config, goal.id, updated, describeCommitMessage(goal), ctx.cwd);
12019
12056
  refreshReportOrFail2(ctx, goal.id, updated);
12020
12057
  } catch (err) {
12021
12058
  process.stderr.write(
@@ -12723,7 +12760,7 @@ ${markdown}`, ctx.cwd);
12723
12760
  extra: { version: 1, ...managedGoal }
12724
12761
  };
12725
12762
  try {
12726
- putGoalState(ctx.config, goalId, goalState, `chore(goals): activate ${goalId}`, ctx.cwd);
12763
+ await putGoalStateAsync(ctx.config, goalId, goalState, `chore(goals): activate ${goalId}`, ctx.cwd);
12727
12764
  } catch (err) {
12728
12765
  process.stderr.write(
12729
12766
  `[createQaGoal] failed to persist goal state to state repo: ${err instanceof Error ? err.message : String(err)}
@@ -14999,11 +15036,35 @@ function listCompanyIntents(config, cwd) {
14999
15036
  }
15000
15037
  return records.sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
15001
15038
  }
15002
- function listCompanyPortfolio(config, cwd) {
15039
+ function backendTenant2(config) {
15040
+ const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
15041
+ const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
15042
+ return owner && repo ? `${owner}/${repo}` : null;
15043
+ }
15044
+ function backendEnabled2(config) {
15045
+ return Boolean(process.env.CONVEX_URL?.trim() && process.env.KODY_SERVICE_KEY?.trim() && backendTenant2(config));
15046
+ }
15047
+ function backendRequired2() {
15048
+ return process.env.GITHUB_ACTIONS === "true";
15049
+ }
15050
+ async function listCompanyIntentsAsync(config, cwd) {
15051
+ const tenantId = backendTenant2(config);
15052
+ if (backendEnabled2(config) && tenantId) {
15053
+ const records = await createStateBackendFromEnv().listIntents(tenantId);
15054
+ return records.filter((record) => isCompanyIntentId(record.intentId)).map((record) => ({
15055
+ id: record.intentId,
15056
+ path: `convex:intents/${record.intentId}`,
15057
+ intent: normalizeCompanyIntent(`convex:intents/${record.intentId}`, record.intent)
15058
+ })).sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
15059
+ }
15060
+ if (backendRequired2()) throw new Error("Convex backend is required for company intents in GitHub Actions");
15061
+ return listCompanyIntents(config, cwd);
15062
+ }
15063
+ async function listCompanyPortfolio(config, cwd) {
15003
15064
  const goals = [];
15004
- for (const id of listGoalStateIds(config, cwd)) {
15065
+ for (const id of await listGoalStateIdsAsync(config, cwd)) {
15005
15066
  if (!isCompanyIntentId(id)) continue;
15006
- const state = fetchGoalState(config, id, cwd);
15067
+ const state = await fetchGoalStateAsync(config, id, cwd);
15007
15068
  if (!state) continue;
15008
15069
  const destination = recordField5(state.extra.destination);
15009
15070
  goals.push({
@@ -15064,6 +15125,7 @@ var init_companyIntent = __esm({
15064
15125
  "use strict";
15065
15126
  init_state2();
15066
15127
  init_stateStore();
15128
+ init_state_backend();
15067
15129
  init_stateRepo();
15068
15130
  SLUG_RE = /^[a-z][a-z0-9-]{0,63}$/;
15069
15131
  }
@@ -15076,7 +15138,7 @@ var init_loadCompanyIntents = __esm({
15076
15138
  "use strict";
15077
15139
  init_companyIntent();
15078
15140
  loadCompanyIntents = async (ctx) => {
15079
- const intents = listCompanyIntents(ctx.config, ctx.cwd);
15141
+ const intents = await listCompanyIntentsAsync(ctx.config, ctx.cwd);
15080
15142
  const active = intents.filter((record) => record.intent.status === "active");
15081
15143
  ctx.data.companyIntents = intents;
15082
15144
  ctx.data.companyActiveIntents = active;
@@ -15099,7 +15161,7 @@ var init_loadCompanyPortfolio = __esm({
15099
15161
  "use strict";
15100
15162
  init_companyIntent();
15101
15163
  loadCompanyPortfolio = async (ctx) => {
15102
- const portfolio = listCompanyPortfolio(ctx.config, ctx.cwd);
15164
+ const portfolio = await listCompanyPortfolio(ctx.config, ctx.cwd);
15103
15165
  ctx.data.companyPortfolio = portfolio;
15104
15166
  ctx.data.companyPortfolioJson = JSON.stringify(portfolio, null, 2);
15105
15167
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.392",
3
+ "version": "0.4.394",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",