@kody-ade/kody-engine 0.4.352 → 0.4.354

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 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.352",
18
+ version: "0.4.354",
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",
@@ -2436,6 +2436,53 @@ var init_registry = __esm({
2436
2436
  }
2437
2437
  });
2438
2438
 
2439
+ // src/trustPolicy.ts
2440
+ function trustSubjectKey(subject) {
2441
+ return `${subject.kind}:${subject.id}`;
2442
+ }
2443
+ function parseTrustMode(rawJson, subject) {
2444
+ return parseTrustModeOverride(rawJson, subject) ?? "ask";
2445
+ }
2446
+ function parseTrustModeOverride(rawJson, subject) {
2447
+ const key = trustSubjectKey(subject);
2448
+ try {
2449
+ const parsed = JSON.parse(rawJson);
2450
+ const rawMode = subject.kind === "capability" ? parsed?.capabilities?.[subject.id]?.mode : parsed?.subjects?.[key]?.mode;
2451
+ if (rawMode === "auto" || rawMode === "ask") return rawMode;
2452
+ return null;
2453
+ } catch {
2454
+ return null;
2455
+ }
2456
+ }
2457
+ function readTrustMode(stateOrRepoSlug, repoSlugOrSubject, maybeSubject) {
2458
+ const mode = typeof stateOrRepoSlug === "string" ? readTrustModeOverride(stateOrRepoSlug, repoSlugOrSubject) : readTrustModeOverride(stateOrRepoSlug, repoSlugOrSubject, maybeSubject);
2459
+ return mode ?? "ask";
2460
+ }
2461
+ function readTrustModeOverride(stateOrRepoSlug, repoSlugOrSubject, maybeSubject) {
2462
+ const state = typeof stateOrRepoSlug === "string" ? void 0 : stateOrRepoSlug;
2463
+ const repoSlug = typeof stateOrRepoSlug === "string" ? stateOrRepoSlug : typeof repoSlugOrSubject === "string" ? repoSlugOrSubject : "";
2464
+ const subject = typeof stateOrRepoSlug === "string" ? repoSlugOrSubject : maybeSubject;
2465
+ if (!subject?.id) return null;
2466
+ try {
2467
+ const loaded = readStateText({ state: state ?? defaultStateForRepoSlug(repoSlug) }, void 0, TRUST_FILE_PATH);
2468
+ return loaded ? parseTrustModeOverride(loaded.content, subject) : null;
2469
+ } catch {
2470
+ return null;
2471
+ }
2472
+ }
2473
+ function defaultStateForRepoSlug(repoSlug) {
2474
+ const [owner, repo] = repoSlug.split("/");
2475
+ return { repo: `${owner}/kody-state`, path: repo ?? repoSlug };
2476
+ }
2477
+ var TRUST_FILE_PATH;
2478
+ var init_trustPolicy = __esm({
2479
+ "src/trustPolicy.ts"() {
2480
+ "use strict";
2481
+ init_stateRepo();
2482
+ TRUST_FILE_PATH = "state/trust.json";
2483
+ }
2484
+ });
2485
+
2439
2486
  // src/capabilityMcp.ts
2440
2487
  var capabilityMcp_exports = {};
2441
2488
  __export(capabilityMcp_exports, {
@@ -2581,28 +2628,14 @@ function readLedger(label) {
2581
2628
  }
2582
2629
  }
2583
2630
  function parseCapabilityTrustMode(rawJson, capabilitySlug) {
2584
- try {
2585
- const parsed = JSON.parse(rawJson);
2586
- return parsed?.capabilities?.[capabilitySlug]?.mode === "auto" ? "auto" : "ask";
2587
- } catch {
2588
- return "ask";
2589
- }
2590
- }
2591
- function defaultStateForRepoSlug(repoSlug) {
2592
- const [owner, repo] = repoSlug.split("/");
2593
- return { repo: `${owner}/kody-state`, path: repo ?? repoSlug };
2631
+ return parseTrustMode(rawJson, { kind: "capability", id: capabilitySlug });
2594
2632
  }
2595
2633
  function readCapabilityTrustMode(stateOrRepoSlug, repoSlugOrCapabilitySlug, maybeCapabilitySlug) {
2596
2634
  const state = typeof stateOrRepoSlug === "string" ? void 0 : stateOrRepoSlug;
2597
2635
  const repoSlug = typeof stateOrRepoSlug === "string" ? stateOrRepoSlug : repoSlugOrCapabilitySlug ?? "";
2598
2636
  const capabilitySlug = typeof stateOrRepoSlug === "string" ? repoSlugOrCapabilitySlug : maybeCapabilitySlug;
2599
2637
  if (!capabilitySlug) return "ask";
2600
- try {
2601
- const loaded = readStateText({ state: state ?? defaultStateForRepoSlug(repoSlug) }, void 0, TRUST_FILE_PATH);
2602
- return loaded ? parseCapabilityTrustMode(loaded.content, capabilitySlug) : "ask";
2603
- } catch {
2604
- return "ask";
2605
- }
2638
+ return readTrustMode(state, repoSlug, { kind: "capability", id: capabilitySlug });
2606
2639
  }
2607
2640
  function readThread(repoSlug, number, limit = 10) {
2608
2641
  const meta = JSON.parse(gh(["api", `repos/${repoSlug}/issues/${number}`]));
@@ -2932,17 +2965,16 @@ function buildCapabilityMcpServer(opts) {
2932
2965
  });
2933
2966
  return { server };
2934
2967
  }
2935
- var FAIL_CONCLUSIONS, RUNNING_STATUSES, TRUST_FILE_PATH, THREAD_BODY_MAX, CHECK_FAIL_CONCLUSIONS, DEFAULT_IGNORE_CHECKS, trackMarker, commentMarker, GATE_EXEMPT_CAPABILITIES, CAPABILITY_MCP_TOOL_NAMES;
2968
+ var FAIL_CONCLUSIONS, RUNNING_STATUSES, THREAD_BODY_MAX, CHECK_FAIL_CONCLUSIONS, DEFAULT_IGNORE_CHECKS, trackMarker, commentMarker, GATE_EXEMPT_CAPABILITIES, CAPABILITY_MCP_TOOL_NAMES;
2936
2969
  var init_capabilityMcp = __esm({
2937
2970
  "src/capabilityMcp.ts"() {
2938
2971
  "use strict";
2939
2972
  init_dashboardCmsMcp();
2940
2973
  init_issue();
2941
2974
  init_registry();
2942
- init_stateRepo();
2975
+ init_trustPolicy();
2943
2976
  FAIL_CONCLUSIONS = /* @__PURE__ */ new Set(["FAILURE", "TIMED_OUT", "ACTION_REQUIRED", "STARTUP_FAILURE", "CANCELLED"]);
2944
2977
  RUNNING_STATUSES = /* @__PURE__ */ new Set(["IN_PROGRESS", "QUEUED", "PENDING", "WAITING", "REQUESTED"]);
2945
- TRUST_FILE_PATH = "state/trust.json";
2946
2978
  THREAD_BODY_MAX = 4e3;
2947
2979
  CHECK_FAIL_CONCLUSIONS = /* @__PURE__ */ new Set(["FAILURE", "TIMED_OUT", "STARTUP_FAILURE", "ACTION_REQUIRED"]);
2948
2980
  DEFAULT_IGNORE_CHECKS = ["run", "kody", "capability-tick", "agent-ask", "chat"];
@@ -9335,14 +9367,16 @@ function scalarFacts(facts) {
9335
9367
  )
9336
9368
  );
9337
9369
  }
9338
- function autonomyBlockReason(ctx, goalId, goal, dispatch2) {
9370
+ function autonomyBlockReason(ctx, goalId, goal, goalState, dispatch2) {
9339
9371
  if (ctx.data.jobForce === true) return null;
9340
- if (goal.runWithoutApproval !== true) {
9372
+ const selfMode = firstTrustOverride(ctx, subjectCandidates(managedModelSubjectKind(goal), goalId, goalState));
9373
+ if (selfMode === "ask" || selfMode !== "auto" && goal.runWithoutApproval !== true) {
9341
9374
  return `Run without approval is off for ${managedModelKind(goal)} ${goalId}`;
9342
9375
  }
9343
9376
  if (dispatch2.workflow) {
9344
- const workflow = readWorkflowDefinition(ctx.config, ctx.cwd, dispatch2.workflow);
9345
- if (workflow && workflow.runWithoutApproval !== true) {
9377
+ const workflowMode = firstTrustOverride(ctx, [{ kind: "workflow", id: dispatch2.workflow }]);
9378
+ const workflow = workflowMode === "auto" ? null : readWorkflowDefinition(ctx.config, ctx.cwd, dispatch2.workflow);
9379
+ if (workflowMode === "ask" || workflowMode !== "auto" && workflow && workflow.runWithoutApproval !== true) {
9346
9380
  return `Run without approval is off for workflow ${dispatch2.workflow}`;
9347
9381
  }
9348
9382
  }
@@ -9350,7 +9384,8 @@ function autonomyBlockReason(ctx, goalId, goal, dispatch2) {
9350
9384
  if (targetGoal && targetGoal !== goalId) {
9351
9385
  const target = fetchGoalState(ctx.config, targetGoal, ctx.cwd);
9352
9386
  const targetManaged = target ? managedGoalFromState(expandManagedGoalState(target)) : null;
9353
- if (targetManaged && targetManaged.runWithoutApproval !== true) {
9387
+ const targetMode = targetManaged ? firstTrustOverride(ctx, subjectCandidates(managedModelSubjectKind(targetManaged), targetGoal, target)) : null;
9388
+ if (targetMode === "ask" || targetMode !== "auto" && targetManaged && targetManaged.runWithoutApproval !== true) {
9354
9389
  return `Run without approval is off for goal ${targetGoal}`;
9355
9390
  }
9356
9391
  }
@@ -9359,6 +9394,29 @@ function autonomyBlockReason(ctx, goalId, goal, dispatch2) {
9359
9394
  function managedModelKind(goal) {
9360
9395
  return goal.loopTarget || goal.schedule ? "Loop" : "Goal";
9361
9396
  }
9397
+ function managedModelSubjectKind(goal) {
9398
+ return managedModelKind(goal) === "Loop" ? "loop" : "goal";
9399
+ }
9400
+ function subjectCandidates(kind, id, state) {
9401
+ const ids = /* @__PURE__ */ new Set();
9402
+ ids.add(id);
9403
+ if (state?.extra) {
9404
+ for (const key of ["sourceTemplate", "templateId", "template"]) {
9405
+ const value = state.extra[key];
9406
+ if (typeof value === "string" && value.trim()) ids.add(value.trim());
9407
+ }
9408
+ }
9409
+ return [...ids].map((candidate) => ({ kind, id: candidate }));
9410
+ }
9411
+ function firstTrustOverride(ctx, subjects) {
9412
+ if (!ctx.config.state) return null;
9413
+ const repoSlug = ctx.config.github?.owner && ctx.config.github?.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : "";
9414
+ for (const subject of subjects) {
9415
+ const mode = readTrustModeOverride(ctx.config.state, repoSlug, subject);
9416
+ if (mode) return mode;
9417
+ }
9418
+ return null;
9419
+ }
9362
9420
  function stageAutonomyBlocked(data, goalId, goal, goalState, reason) {
9363
9421
  stageGoalRunLogEvent(data, goalId, {
9364
9422
  source: "goal-manager",
@@ -9550,6 +9608,7 @@ var init_advanceManagedGoal = __esm({
9550
9608
  init_targetLoopResolution();
9551
9609
  init_typeDefinitions();
9552
9610
  init_issue();
9611
+ init_trustPolicy();
9553
9612
  init_workflowDefinitions();
9554
9613
  init_goalCapabilityScheduling();
9555
9614
  advanceManagedGoal = async (ctx) => {
@@ -9645,7 +9704,7 @@ var init_advanceManagedGoal = __esm({
9645
9704
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
9646
9705
  goal.raw.extra.scheduleState = decision2.scheduleState;
9647
9706
  ctx.data.managedGoalDecision = decision2;
9648
- const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, decision2.dispatch) : null;
9707
+ const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
9649
9708
  if (autonomyBlock) {
9650
9709
  stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
9651
9710
  ctx.output.reason = autonomyBlock;
@@ -9707,7 +9766,7 @@ var init_advanceManagedGoal = __esm({
9707
9766
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
9708
9767
  goal.raw.extra.scheduleState = decision2.scheduleState;
9709
9768
  ctx.data.managedGoalDecision = decision2;
9710
- const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, decision2.dispatch) : null;
9769
+ const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
9711
9770
  if (autonomyBlock) {
9712
9771
  stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
9713
9772
  ctx.output.reason = autonomyBlock;
@@ -9772,7 +9831,7 @@ var init_advanceManagedGoal = __esm({
9772
9831
  ...decision.implementation ? { implementation: decision.implementation } : {},
9773
9832
  cliArgs: decision.cliArgs
9774
9833
  };
9775
- const autonomyBlock = autonomyBlockReason(ctx, goal.id, managed, planned);
9834
+ const autonomyBlock = autonomyBlockReason(ctx, goal.id, managed, goal.raw, planned);
9776
9835
  if (autonomyBlock) {
9777
9836
  stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
9778
9837
  ctx.output.reason = autonomyBlock;
@@ -9800,8 +9859,9 @@ var init_advanceManagedGoal = __esm({
9800
9859
  workflow: decision.workflow,
9801
9860
  cliArgs: decision.cliArgs,
9802
9861
  workflowFacts: scalarFacts(managed.facts),
9862
+ evidence: decision.evidence,
9803
9863
  ...decision.saveReport === true ? { saveReport: true } : {},
9804
- resultTarget: { type: "goal", id: goal.id, evidence: decision.evidence }
9864
+ resultTarget: { type: "goal", id: goal.id }
9805
9865
  };
9806
9866
  ctx.output.reason = `dispatch workflow ${decision.workflow} for ${decision.evidence}`;
9807
9867
  return;
@@ -9809,9 +9869,10 @@ var init_advanceManagedGoal = __esm({
9809
9869
  ctx.output.nextDispatch = {
9810
9870
  capability: decision.capability,
9811
9871
  cliArgs: decision.cliArgs,
9872
+ evidence: decision.evidence,
9812
9873
  ...decision.implementation ? { implementation: decision.implementation } : {},
9813
9874
  ...decision.saveReport === true ? { saveReport: true } : {},
9814
- resultTarget: { type: "goal", id: goal.id, evidence: decision.evidence }
9875
+ resultTarget: { type: "goal", id: goal.id }
9815
9876
  };
9816
9877
  ctx.output.reason = `dispatch ${decision.capability} for ${decision.evidence}`;
9817
9878
  };
@@ -10950,6 +11011,12 @@ function parseResultTarget(raw) {
10950
11011
  ...evidence ? { evidence } : {}
10951
11012
  };
10952
11013
  }
11014
+ function parseEvidenceContext(raw) {
11015
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
11016
+ const context = raw;
11017
+ const evidence = typeof context.evidence === "string" && context.evidence.trim().length > 0 ? context.evidence.trim() : void 0;
11018
+ return evidence ? { evidence } : null;
11019
+ }
10953
11020
  function collectGoalCapabilityEvidence(reports, results, fallbackGoalId, explicitEvidence) {
10954
11021
  const items = [];
10955
11022
  for (const report of reports) {
@@ -11054,8 +11121,9 @@ var init_applyCapabilityReports = __esm({
11054
11121
  const reports = collectReports(ctx.data.capabilityReports, agentResult);
11055
11122
  const results = collectResults2(ctx.data.capabilityResults, agentResult);
11056
11123
  const resultTarget = parseResultTarget(ctx.data.capabilityResultTarget);
11124
+ const evidenceContext = parseEvidenceContext(ctx.data.capabilityEvidence);
11057
11125
  const resultGoalId = resultTarget?.id ?? (typeof ctx.args.goal === "string" && ctx.args.goal.length > 0 ? ctx.args.goal : null);
11058
- const explicitEvidence = resultTarget?.evidence ?? (typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0);
11126
+ const explicitEvidence = evidenceContext?.evidence ?? resultTarget?.evidence ?? (typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0);
11059
11127
  const evidenceItems = collectGoalCapabilityEvidence(reports, results, resultGoalId, explicitEvidence);
11060
11128
  if (evidenceItems.length === 0) return;
11061
11129
  const evidenceByGoal = groupGoalEvidence(evidenceItems);
@@ -20483,6 +20551,7 @@ function handoffToJob(handoff) {
20483
20551
  implementation: handoff.implementation,
20484
20552
  cliArgs: handoff.cliArgs,
20485
20553
  workflowFacts: handoff.workflowFacts,
20554
+ evidence: handoff.evidence,
20486
20555
  flavor: "instant",
20487
20556
  saveReport: handoff.saveReport === true,
20488
20557
  resultTarget: handoff.resultTarget
@@ -20828,6 +20897,7 @@ function validateJob(input) {
20828
20897
  target: typeof j.target === "number" ? j.target : void 0,
20829
20898
  cliArgs: j.cliArgs ?? {},
20830
20899
  workflowFacts: j.workflowFacts && typeof j.workflowFacts === "object" && !Array.isArray(j.workflowFacts) ? j.workflowFacts : void 0,
20900
+ evidence: parseJobEvidence(j),
20831
20901
  flavor: j.flavor,
20832
20902
  force: j.force === true,
20833
20903
  saveReport: j.saveReport === true,
@@ -20839,13 +20909,18 @@ function parseCapabilityResultTarget(raw) {
20839
20909
  const target = raw;
20840
20910
  if (target.type !== "goal") return void 0;
20841
20911
  if (typeof target.id !== "string" || target.id.trim().length === 0) return void 0;
20842
- const evidence = typeof target.evidence === "string" && target.evidence.trim().length > 0 ? target.evidence.trim() : void 0;
20843
20912
  return {
20844
20913
  type: "goal",
20845
- id: target.id.trim(),
20846
- ...evidence ? { evidence } : {}
20914
+ id: target.id.trim()
20847
20915
  };
20848
20916
  }
20917
+ function parseJobEvidence(job) {
20918
+ if (typeof job.evidence === "string" && job.evidence.trim().length > 0) return job.evidence.trim();
20919
+ const target = job.resultTarget;
20920
+ if (!target || typeof target !== "object" || Array.isArray(target)) return void 0;
20921
+ const evidence = target.evidence;
20922
+ return typeof evidence === "string" && evidence.trim().length > 0 ? evidence.trim() : void 0;
20923
+ }
20849
20924
  async function runJob(job, base) {
20850
20925
  const valid = validateJob(job);
20851
20926
  const action = valid.action ?? valid.capability;
@@ -20905,6 +20980,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
20905
20980
  if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
20906
20981
  if (valid.saveReport === true) preloadedData.jobSaveReport = true;
20907
20982
  if (valid.force === true) preloadedData.jobForce = true;
20983
+ if (valid.evidence) preloadedData.capabilityEvidence = { evidence: valid.evidence };
20908
20984
  if (valid.resultTarget) preloadedData.capabilityResultTarget = valid.resultTarget;
20909
20985
  if (capabilityContext) {
20910
20986
  preloadedData.capabilitySlug = capabilityContext.slug;
@@ -20964,7 +21040,7 @@ async function runCapabilityWorkflow(parent, workflow, capability, base) {
20964
21040
  ]
20965
21041
  };
20966
21042
  let result = { exitCode: 0 };
20967
- const startIndex = workflowResumeStartIndex(workflow.steps, parent.resultTarget?.evidence);
21043
+ const startIndex = workflowResumeStartIndex(workflow.steps, parent.evidence);
20968
21044
  for (let index = startIndex; index < workflow.steps.length; index++) {
20969
21045
  const step = workflow.steps[index];
20970
21046
  const label = step.action ?? step.capability;
@@ -21054,9 +21130,11 @@ function workflowStepToJob(step, parent, chainData) {
21054
21130
  ...parent.schedule ? { schedule: parent.schedule } : {},
21055
21131
  ...typeof target === "number" ? { target } : {},
21056
21132
  cliArgs,
21133
+ ...step.evidence ? { evidence: step.evidence } : parent.evidence ? { evidence: parent.evidence } : {},
21057
21134
  flavor: parent.flavor,
21058
21135
  force: parent.force,
21059
- saveReport: step.saveReport === true || parent.saveReport === true
21136
+ saveReport: step.saveReport === true || parent.saveReport === true,
21137
+ ...parent.resultTarget ? { resultTarget: parent.resultTarget } : {}
21060
21138
  };
21061
21139
  }
21062
21140
  function shouldRunWorkflowStep(step, data) {
@@ -401,7 +401,6 @@ export interface OutputContract {
401
401
  export interface CapabilityResultTarget {
402
402
  type: "goal"
403
403
  id: string
404
- evidence?: string
405
404
  }
406
405
 
407
406
  // ────────────────────────────────────────────────────────────────────────────
@@ -439,6 +438,7 @@ export interface Context {
439
438
  implementation?: string
440
439
  cliArgs: Record<string, unknown>
441
440
  workflowFacts?: Record<string, unknown>
441
+ evidence?: string
442
442
  saveReport?: boolean
443
443
  resultTarget?: CapabilityResultTarget
444
444
  }
@@ -452,6 +452,7 @@ export interface Context {
452
452
  implementation?: string
453
453
  cliArgs: Record<string, unknown>
454
454
  workflowFacts?: Record<string, unknown>
455
+ evidence?: string
455
456
  saveReport?: boolean
456
457
  resultTarget?: CapabilityResultTarget
457
458
  }
@@ -521,6 +522,8 @@ export interface Job {
521
522
  cliArgs: Record<string, unknown>
522
523
  /** Internal workflow resume context. Not passed to capability CLI args. */
523
524
  workflowFacts?: Record<string, unknown>
525
+ /** Evidence this capability run is expected to report, independent of who consumes it. */
526
+ evidence?: string
524
527
  /** Run once now ("instant") or on the schedule ("scheduled"). */
525
528
  flavor: JobFlavor
526
529
  /** Manual force-run (bypass cadence) for a scheduled job. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.352",
3
+ "version": "0.4.354",
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",