@kody-ade/kody-engine 0.4.569 → 0.4.571
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 +66 -29
- 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.571",
|
|
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",
|
|
@@ -150,6 +150,29 @@ var init_claudeBinary = __esm({
|
|
|
150
150
|
}
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
// src/completionGuard.ts
|
|
154
|
+
function completionToolCutoffAt(startedAtMs, deadlineAtMs) {
|
|
155
|
+
const availableMs = Math.max(0, deadlineAtMs - startedAtMs);
|
|
156
|
+
const reserveMs = Math.min(MAX_COMPLETION_RESERVE_MS, Math.floor(availableMs / 3));
|
|
157
|
+
return deadlineAtMs - reserveMs;
|
|
158
|
+
}
|
|
159
|
+
function createCompletionToolGuard(cutoffAtMs, now = Date.now) {
|
|
160
|
+
return async () => {
|
|
161
|
+
if (now() < cutoffAtMs) return {};
|
|
162
|
+
return {
|
|
163
|
+
decision: "block",
|
|
164
|
+
reason: "The run has entered its reserved completion window. Do not call more tools. Use the evidence and changes already present, state any verification limits clearly, and return your final response now."
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
var MAX_COMPLETION_RESERVE_MS;
|
|
169
|
+
var init_completionGuard = __esm({
|
|
170
|
+
"src/completionGuard.ts"() {
|
|
171
|
+
"use strict";
|
|
172
|
+
MAX_COMPLETION_RESERVE_MS = 10 * 6e4;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
153
176
|
// src/config.ts
|
|
154
177
|
import * as fs2 from "fs";
|
|
155
178
|
import * as path2 from "path";
|
|
@@ -548,6 +571,29 @@ var init_config = __esm({
|
|
|
548
571
|
}
|
|
549
572
|
});
|
|
550
573
|
|
|
574
|
+
// src/fileEditGuards.ts
|
|
575
|
+
import * as fs3 from "fs";
|
|
576
|
+
import * as path3 from "path";
|
|
577
|
+
function createMissingParentWriteGuard(cwd) {
|
|
578
|
+
return async (input) => {
|
|
579
|
+
const toolInput = input.tool_input;
|
|
580
|
+
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
581
|
+
const filePath = toolInput.file_path;
|
|
582
|
+
if (typeof filePath !== "string" || filePath.length === 0) return {};
|
|
583
|
+
const resolvedPath = path3.resolve(cwd, filePath);
|
|
584
|
+
if (fs3.existsSync(path3.dirname(resolvedPath))) return {};
|
|
585
|
+
return {
|
|
586
|
+
decision: "block",
|
|
587
|
+
reason: `Cannot write ${resolvedPath}: its parent directory does not exist. Locate and edit the real repository source path first. If this task genuinely requires a new directory, create that directory explicitly before writing the file.`
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
var init_fileEditGuards = __esm({
|
|
592
|
+
"src/fileEditGuards.ts"() {
|
|
593
|
+
"use strict";
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
551
597
|
// src/format.ts
|
|
552
598
|
function renderEvent(msg, opts = {}) {
|
|
553
599
|
if (opts.quiet) {
|
|
@@ -669,29 +715,6 @@ var init_format = __esm({
|
|
|
669
715
|
}
|
|
670
716
|
});
|
|
671
717
|
|
|
672
|
-
// src/fileEditGuards.ts
|
|
673
|
-
import * as fs3 from "fs";
|
|
674
|
-
import * as path3 from "path";
|
|
675
|
-
function createMissingParentWriteGuard(cwd) {
|
|
676
|
-
return async (input) => {
|
|
677
|
-
const toolInput = input.tool_input;
|
|
678
|
-
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
679
|
-
const filePath = toolInput.file_path;
|
|
680
|
-
if (typeof filePath !== "string" || filePath.length === 0) return {};
|
|
681
|
-
const resolvedPath = path3.resolve(cwd, filePath);
|
|
682
|
-
if (fs3.existsSync(path3.dirname(resolvedPath))) return {};
|
|
683
|
-
return {
|
|
684
|
-
decision: "block",
|
|
685
|
-
reason: `Cannot write ${resolvedPath}: its parent directory does not exist. Locate and edit the real repository source path first. If this task genuinely requires a new directory, create that directory explicitly before writing the file.`
|
|
686
|
-
};
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
var init_fileEditGuards = __esm({
|
|
690
|
-
"src/fileEditGuards.ts"() {
|
|
691
|
-
"use strict";
|
|
692
|
-
}
|
|
693
|
-
});
|
|
694
|
-
|
|
695
718
|
// src/agency/capability-contract-validation.ts
|
|
696
719
|
import Ajv from "ajv";
|
|
697
720
|
function createCapabilityContractValueValidator(compile) {
|
|
@@ -4062,6 +4085,7 @@ async function runAgent(opts) {
|
|
|
4062
4085
|
}
|
|
4063
4086
|
const startedAt = Date.now();
|
|
4064
4087
|
const turnTimeoutMs = resolveTurnTimeoutMs(opts);
|
|
4088
|
+
const completionGuard = typeof opts.deadlineAtMs === "number" ? createCompletionToolGuard(completionToolCutoffAt(startedAt, opts.deadlineAtMs)) : null;
|
|
4065
4089
|
let outcome = "failed";
|
|
4066
4090
|
let outcomeKind = "generic_failed";
|
|
4067
4091
|
let errorMessage2;
|
|
@@ -4106,6 +4130,11 @@ async function runAgent(opts) {
|
|
|
4106
4130
|
env,
|
|
4107
4131
|
hooks: {
|
|
4108
4132
|
PreToolUse: [
|
|
4133
|
+
...completionGuard ? [
|
|
4134
|
+
{
|
|
4135
|
+
hooks: [completionGuard]
|
|
4136
|
+
}
|
|
4137
|
+
] : [],
|
|
4109
4138
|
{
|
|
4110
4139
|
matcher: "Agent",
|
|
4111
4140
|
hooks: [enforceSubagentModelInheritance]
|
|
@@ -4229,11 +4258,13 @@ async function runAgent(opts) {
|
|
|
4229
4258
|
} else if (typeof opts.maxThinkingTokens === "number" && opts.maxThinkingTokens > 0) {
|
|
4230
4259
|
queryOptions.maxThinkingTokens = opts.maxThinkingTokens;
|
|
4231
4260
|
}
|
|
4232
|
-
|
|
4261
|
+
const completionNotice = completionGuard ? "Work within the enforced run time. Tool access closes before the hard deadline to reserve time for a final response. When that happens, stop using tools and finish immediately." : null;
|
|
4262
|
+
const systemPromptAppend = [opts.systemPromptAppend, completionNotice].filter((value) => typeof value === "string" && value.length > 0).join("\n\n");
|
|
4263
|
+
if (systemPromptAppend.length > 0) {
|
|
4233
4264
|
const systemPrompt = {
|
|
4234
4265
|
type: "preset",
|
|
4235
4266
|
preset: "claude_code",
|
|
4236
|
-
append:
|
|
4267
|
+
append: systemPromptAppend
|
|
4237
4268
|
};
|
|
4238
4269
|
if (opts.cacheable) systemPrompt.excludeDynamicSections = true;
|
|
4239
4270
|
queryOptions.systemPrompt = systemPrompt;
|
|
@@ -4463,9 +4494,10 @@ var init_agent = __esm({
|
|
|
4463
4494
|
"src/agent.ts"() {
|
|
4464
4495
|
"use strict";
|
|
4465
4496
|
init_claudeBinary();
|
|
4497
|
+
init_completionGuard();
|
|
4466
4498
|
init_config();
|
|
4467
|
-
init_format();
|
|
4468
4499
|
init_fileEditGuards();
|
|
4500
|
+
init_format();
|
|
4469
4501
|
init_outputContractHooks();
|
|
4470
4502
|
init_runtimePaths();
|
|
4471
4503
|
init_subagents();
|
|
@@ -22138,6 +22170,7 @@ async function runImplementation(profileName, input) {
|
|
|
22138
22170
|
verbose: input.verbose,
|
|
22139
22171
|
quiet: input.quiet,
|
|
22140
22172
|
abortController: input.abortController,
|
|
22173
|
+
deadlineAtMs: input.deadlineAtMs,
|
|
22141
22174
|
ndjsonDir,
|
|
22142
22175
|
additionalDirectories: agentTaskArtifacts ? [agentTaskArtifacts.absDir] : void 0,
|
|
22143
22176
|
allowedToolsOverride: profile.claudeCode.tools,
|
|
@@ -23324,6 +23357,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
23324
23357
|
verbose: base.verbose,
|
|
23325
23358
|
quiet: base.quiet,
|
|
23326
23359
|
abortController: base.abortController,
|
|
23360
|
+
deadlineAtMs: base.deadlineAtMs,
|
|
23327
23361
|
preloadedData: Object.keys(preloadedData).length > 0 ? preloadedData : void 0
|
|
23328
23362
|
};
|
|
23329
23363
|
const shouldApplyResolvedCapabilityArgs = valid.implementation === void 0 && resolvedCapability && profileName === resolvedCapability.implementation;
|
|
@@ -23637,6 +23671,7 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
23637
23671
|
result = await runJob(child, {
|
|
23638
23672
|
...base,
|
|
23639
23673
|
abortController: stepAbort.controller,
|
|
23674
|
+
deadlineAtMs: stepAbort.deadlineAtMs,
|
|
23640
23675
|
preloadedData: {
|
|
23641
23676
|
...chainData,
|
|
23642
23677
|
runSubjectType: "capability",
|
|
@@ -23966,8 +24001,9 @@ function canContinueWorkflow(step, outcome) {
|
|
|
23966
24001
|
return step.continueOn.includes(outcome.type);
|
|
23967
24002
|
}
|
|
23968
24003
|
function workflowStepAbortController(parent, timeoutSeconds) {
|
|
23969
|
-
if (!timeoutSeconds) return { controller: parent, cleanup: () => void 0 };
|
|
24004
|
+
if (!timeoutSeconds) return { controller: parent, deadlineAtMs: void 0, cleanup: () => void 0 };
|
|
23970
24005
|
const controller = new AbortController();
|
|
24006
|
+
const deadlineAtMs = Date.now() + timeoutSeconds * 1e3;
|
|
23971
24007
|
const forwardParentAbort = () => controller.abort(parent?.signal.reason);
|
|
23972
24008
|
if (parent?.signal.aborted) forwardParentAbort();
|
|
23973
24009
|
else parent?.signal.addEventListener("abort", forwardParentAbort, { once: true });
|
|
@@ -23977,6 +24013,7 @@ function workflowStepAbortController(parent, timeoutSeconds) {
|
|
|
23977
24013
|
timer.unref?.();
|
|
23978
24014
|
return {
|
|
23979
24015
|
controller,
|
|
24016
|
+
deadlineAtMs,
|
|
23980
24017
|
cleanup: () => {
|
|
23981
24018
|
clearTimeout(timer);
|
|
23982
24019
|
parent?.signal.removeEventListener("abort", forwardParentAbort);
|
|
@@ -23984,7 +24021,7 @@ function workflowStepAbortController(parent, timeoutSeconds) {
|
|
|
23984
24021
|
};
|
|
23985
24022
|
}
|
|
23986
24023
|
function workflowOutcome(result) {
|
|
23987
|
-
return result.taskState?.core.lastOutcome ??
|
|
24024
|
+
return result.action ?? result.taskState?.core.lastOutcome ?? null;
|
|
23988
24025
|
}
|
|
23989
24026
|
function workflowStepDeadlineResult(result, controller, timeoutSeconds) {
|
|
23990
24027
|
if (!timeoutSeconds || !controller?.signal.aborted || result.exitCode === 0) return result;
|
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.571",
|
|
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",
|