@kody-ade/kody-engine 0.4.353 → 0.4.355
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 +137 -35
- 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.355",
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
9345
|
-
|
|
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,16 +9384,65 @@ 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
|
-
|
|
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
|
}
|
|
9357
9392
|
return null;
|
|
9358
9393
|
}
|
|
9394
|
+
function scheduleWaitDecision(previousScheduleState, plannedDecision, reason) {
|
|
9395
|
+
const at = plannedDecision.scheduleState.lastGoalTickAt;
|
|
9396
|
+
return {
|
|
9397
|
+
kind: "wait",
|
|
9398
|
+
reason,
|
|
9399
|
+
scheduleState: {
|
|
9400
|
+
mode: "agentLoop",
|
|
9401
|
+
lastGoalTickAt: previousScheduleState?.lastGoalTickAt ?? plannedDecision.scheduleState.lastGoalTickAt,
|
|
9402
|
+
lastDecision: { kind: "wait", reason, at },
|
|
9403
|
+
capabilities: previousScheduleState?.capabilities ?? unmarkPlannedCapabilityDispatch(plannedDecision.scheduleState, at)
|
|
9404
|
+
}
|
|
9405
|
+
};
|
|
9406
|
+
}
|
|
9407
|
+
function unmarkPlannedCapabilityDispatch(scheduleState, at) {
|
|
9408
|
+
return Object.fromEntries(
|
|
9409
|
+
Object.entries(scheduleState.capabilities).map(([slug2, status]) => {
|
|
9410
|
+
if (status.lastFiredAt !== at) return [slug2, status];
|
|
9411
|
+
const rest = { ...status };
|
|
9412
|
+
delete rest.lastFiredAt;
|
|
9413
|
+
return [slug2, rest];
|
|
9414
|
+
})
|
|
9415
|
+
);
|
|
9416
|
+
}
|
|
9359
9417
|
function managedModelKind(goal) {
|
|
9360
9418
|
return goal.loopTarget || goal.schedule ? "Loop" : "Goal";
|
|
9361
9419
|
}
|
|
9362
|
-
function
|
|
9420
|
+
function managedModelSubjectKind(goal) {
|
|
9421
|
+
return managedModelKind(goal) === "Loop" ? "loop" : "goal";
|
|
9422
|
+
}
|
|
9423
|
+
function subjectCandidates(kind, id, state) {
|
|
9424
|
+
const ids = /* @__PURE__ */ new Set();
|
|
9425
|
+
ids.add(id);
|
|
9426
|
+
if (state?.extra) {
|
|
9427
|
+
for (const key of ["sourceTemplate", "templateId", "template"]) {
|
|
9428
|
+
const value = state.extra[key];
|
|
9429
|
+
if (typeof value === "string" && value.trim()) ids.add(value.trim());
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
return [...ids].map((candidate) => ({ kind, id: candidate }));
|
|
9433
|
+
}
|
|
9434
|
+
function firstTrustOverride(ctx, subjects) {
|
|
9435
|
+
if (!ctx.config.state) return null;
|
|
9436
|
+
const repoSlug = ctx.config.github?.owner && ctx.config.github?.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : "";
|
|
9437
|
+
for (const subject of subjects) {
|
|
9438
|
+
const mode = readTrustModeOverride(ctx.config.state, repoSlug, subject);
|
|
9439
|
+
if (mode) return mode;
|
|
9440
|
+
}
|
|
9441
|
+
return null;
|
|
9442
|
+
}
|
|
9443
|
+
function stageAutonomyBlocked(data, goalId, goal, goalState, waitDecision, previousScheduleState) {
|
|
9444
|
+
const reason = typeof waitDecision === "string" ? waitDecision : waitDecision.reason;
|
|
9445
|
+
const scheduleState = typeof waitDecision === "string" ? void 0 : waitDecision.scheduleState;
|
|
9363
9446
|
stageGoalRunLogEvent(data, goalId, {
|
|
9364
9447
|
source: "goal-manager",
|
|
9365
9448
|
event: "goal.tick.wait",
|
|
@@ -9369,6 +9452,18 @@ function stageAutonomyBlocked(data, goalId, goal, goalState, reason) {
|
|
|
9369
9452
|
status: "wait",
|
|
9370
9453
|
reason,
|
|
9371
9454
|
goal: goalRunLogSnapshot(goalId, goalState, goal),
|
|
9455
|
+
...scheduleState ? {
|
|
9456
|
+
inspection: {
|
|
9457
|
+
previousScheduleState,
|
|
9458
|
+
scheduleState
|
|
9459
|
+
},
|
|
9460
|
+
change: {
|
|
9461
|
+
scheduleState: {
|
|
9462
|
+
previousDecision: previousScheduleState?.lastDecision,
|
|
9463
|
+
nextDecision: scheduleState.lastDecision
|
|
9464
|
+
}
|
|
9465
|
+
}
|
|
9466
|
+
} : {},
|
|
9372
9467
|
decision: { kind: "wait", reason }
|
|
9373
9468
|
});
|
|
9374
9469
|
}
|
|
@@ -9550,6 +9645,7 @@ var init_advanceManagedGoal = __esm({
|
|
|
9550
9645
|
init_targetLoopResolution();
|
|
9551
9646
|
init_typeDefinitions();
|
|
9552
9647
|
init_issue();
|
|
9648
|
+
init_trustPolicy();
|
|
9553
9649
|
init_workflowDefinitions();
|
|
9554
9650
|
init_goalCapabilityScheduling();
|
|
9555
9651
|
advanceManagedGoal = async (ctx) => {
|
|
@@ -9643,14 +9739,17 @@ var init_advanceManagedGoal = __esm({
|
|
|
9643
9739
|
}
|
|
9644
9740
|
restoreGoalIdFact();
|
|
9645
9741
|
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
9646
|
-
|
|
9647
|
-
ctx.data.managedGoalDecision = decision2;
|
|
9648
|
-
const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, decision2.dispatch) : null;
|
|
9742
|
+
const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
|
|
9649
9743
|
if (autonomyBlock) {
|
|
9650
|
-
|
|
9744
|
+
const waitDecision = scheduleWaitDecision(previousScheduleState, decision2, autonomyBlock);
|
|
9745
|
+
goal.raw.extra.scheduleState = waitDecision.scheduleState;
|
|
9746
|
+
ctx.data.managedGoalDecision = waitDecision;
|
|
9747
|
+
stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, waitDecision, previousScheduleState);
|
|
9651
9748
|
ctx.output.reason = autonomyBlock;
|
|
9652
9749
|
return;
|
|
9653
9750
|
}
|
|
9751
|
+
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
9752
|
+
ctx.data.managedGoalDecision = decision2;
|
|
9654
9753
|
if (decision2.kind === "dispatch" && decision2.dispatch) {
|
|
9655
9754
|
ctx.output.nextDispatch = {
|
|
9656
9755
|
...decision2.dispatch.action ? { action: decision2.dispatch.action } : {},
|
|
@@ -9705,14 +9804,17 @@ var init_advanceManagedGoal = __esm({
|
|
|
9705
9804
|
});
|
|
9706
9805
|
restoreGoalIdFact();
|
|
9707
9806
|
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
9708
|
-
|
|
9709
|
-
ctx.data.managedGoalDecision = decision2;
|
|
9710
|
-
const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, decision2.dispatch) : null;
|
|
9807
|
+
const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, goal.raw, decision2.dispatch) : null;
|
|
9711
9808
|
if (autonomyBlock) {
|
|
9712
|
-
|
|
9809
|
+
const waitDecision = scheduleWaitDecision(previousScheduleState, decision2, autonomyBlock);
|
|
9810
|
+
goal.raw.extra.scheduleState = waitDecision.scheduleState;
|
|
9811
|
+
ctx.data.managedGoalDecision = waitDecision;
|
|
9812
|
+
stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, waitDecision, previousScheduleState);
|
|
9713
9813
|
ctx.output.reason = autonomyBlock;
|
|
9714
9814
|
return;
|
|
9715
9815
|
}
|
|
9816
|
+
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
9817
|
+
ctx.data.managedGoalDecision = decision2;
|
|
9716
9818
|
if (decision2.kind === "dispatch" && decision2.dispatch) {
|
|
9717
9819
|
ctx.output.nextDispatch = {
|
|
9718
9820
|
capability: decision2.dispatch.capability,
|
|
@@ -9772,7 +9874,7 @@ var init_advanceManagedGoal = __esm({
|
|
|
9772
9874
|
...decision.implementation ? { implementation: decision.implementation } : {},
|
|
9773
9875
|
cliArgs: decision.cliArgs
|
|
9774
9876
|
};
|
|
9775
|
-
const autonomyBlock = autonomyBlockReason(ctx, goal.id, managed, planned);
|
|
9877
|
+
const autonomyBlock = autonomyBlockReason(ctx, goal.id, managed, goal.raw, planned);
|
|
9776
9878
|
if (autonomyBlock) {
|
|
9777
9879
|
stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
|
|
9778
9880
|
ctx.output.reason = autonomyBlock;
|
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.355",
|
|
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",
|