@kody-ade/kody-engine 0.4.350 → 0.4.351
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 +370 -300
- 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.351",
|
|
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",
|
|
@@ -4551,7 +4551,13 @@ function loadProfile(profilePath) {
|
|
|
4551
4551
|
const preNames = new Set(profile.scripts.preflight.map((e) => e.script).filter(Boolean));
|
|
4552
4552
|
const postNames = profile.scripts.postflight.map((e) => e.script).filter(Boolean);
|
|
4553
4553
|
const needsState = postNames.includes("writeJobStateFile") || postNames.includes("parseJobStateFromAgentResult");
|
|
4554
|
-
const STATE_LOADERS = [
|
|
4554
|
+
const STATE_LOADERS = [
|
|
4555
|
+
"loadCapabilityState",
|
|
4556
|
+
"loadJobFromFile",
|
|
4557
|
+
"runTickScript",
|
|
4558
|
+
"runScheduledImplementationTick",
|
|
4559
|
+
"runScheduledExecutableTick"
|
|
4560
|
+
];
|
|
4555
4561
|
if (needsState && !STATE_LOADERS.some((s) => preNames.has(s))) {
|
|
4556
4562
|
throw new ProfileError(
|
|
4557
4563
|
profilePath,
|
|
@@ -5769,8 +5775,10 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
5769
5775
|
const priorAction = priorState.implementations?.[child.implementation]?.lastAction;
|
|
5770
5776
|
let actionType2;
|
|
5771
5777
|
if (priorAction && /_COMPLETED$/i.test(priorAction.type)) {
|
|
5772
|
-
process.stderr.write(
|
|
5773
|
-
`)
|
|
5778
|
+
process.stderr.write(
|
|
5779
|
+
`[kody container] skipping ${child.implementation}: already completed (${priorAction.type})
|
|
5780
|
+
`
|
|
5781
|
+
);
|
|
5774
5782
|
actionType2 = priorAction.type;
|
|
5775
5783
|
} else {
|
|
5776
5784
|
let cliArgs;
|
|
@@ -7482,6 +7490,7 @@ function managedGoalFromState(state) {
|
|
|
7482
7490
|
destination: { outcome: destination.outcome, evidence },
|
|
7483
7491
|
capabilities,
|
|
7484
7492
|
route,
|
|
7493
|
+
...extra.runWithoutApproval === true ? { runWithoutApproval: true } : {},
|
|
7485
7494
|
workflowRef: asWorkflowRef(extra.workflowRef),
|
|
7486
7495
|
schedule: typeof extra.schedule === "string" ? extra.schedule : void 0,
|
|
7487
7496
|
preferredRunTime: asPreferredRunTime(extra.preferredRunTime),
|
|
@@ -7503,6 +7512,7 @@ function writeManagedGoalToState(state, goal) {
|
|
|
7503
7512
|
destination: goal.destination,
|
|
7504
7513
|
capabilities: goal.capabilities,
|
|
7505
7514
|
route: goal.route,
|
|
7515
|
+
...goal.runWithoutApproval === true ? { runWithoutApproval: true } : {},
|
|
7506
7516
|
workflowRef: goal.workflowRef,
|
|
7507
7517
|
stage: goal.stage,
|
|
7508
7518
|
facts: goal.facts,
|
|
@@ -8078,15 +8088,7 @@ function serializeTodoGoalState(goalId, state, previousRaw) {
|
|
|
8078
8088
|
const routeByEvidence = new Map(route.map((step) => [stringField3(step.evidence), step]));
|
|
8079
8089
|
const previousItems = new Map(parseItemsFromAnyRaw(previousRaw ?? "").map((item) => [item.id, item]));
|
|
8080
8090
|
const items = evidence.length > 0 ? evidence.map(
|
|
8081
|
-
(key) => itemFromEvidence(
|
|
8082
|
-
key,
|
|
8083
|
-
routeByEvidence.get(key),
|
|
8084
|
-
facts,
|
|
8085
|
-
evidenceState,
|
|
8086
|
-
createdAt,
|
|
8087
|
-
now,
|
|
8088
|
-
previousItems.get(key)
|
|
8089
|
-
)
|
|
8091
|
+
(key) => itemFromEvidence(key, routeByEvidence.get(key), facts, evidenceState, createdAt, now, previousItems.get(key))
|
|
8090
8092
|
) : stringArray(raw.capabilities).map(
|
|
8091
8093
|
(capability) => itemFromCapability(capability, createdAt, previousItems.get(capability))
|
|
8092
8094
|
);
|
|
@@ -8612,6 +8614,102 @@ var init_typeDefinitions = __esm({
|
|
|
8612
8614
|
}
|
|
8613
8615
|
});
|
|
8614
8616
|
|
|
8617
|
+
// src/workflowDefinitions.ts
|
|
8618
|
+
import * as fs28 from "fs";
|
|
8619
|
+
import * as path26 from "path";
|
|
8620
|
+
function isWorkflowDefinitionId(value) {
|
|
8621
|
+
return WORKFLOW_ID_PATTERN.test(value);
|
|
8622
|
+
}
|
|
8623
|
+
function workflowDefinitionPath(id) {
|
|
8624
|
+
if (!isWorkflowDefinitionId(id)) {
|
|
8625
|
+
throw new Error(`Invalid workflow id "${id}"`);
|
|
8626
|
+
}
|
|
8627
|
+
return `workflows/${id}/workflow.json`;
|
|
8628
|
+
}
|
|
8629
|
+
function normalizeWorkflowDefinition(value) {
|
|
8630
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
8631
|
+
const raw = value;
|
|
8632
|
+
const name = typeof raw.name === "string" ? raw.name.trim() : "";
|
|
8633
|
+
const workflow = parseCapabilityWorkflow({ steps: raw.steps });
|
|
8634
|
+
const steps = workflow?.steps;
|
|
8635
|
+
const capabilities = steps ? steps.map((step) => step.capability) : normalizeWorkflowCapabilities(raw.capabilities);
|
|
8636
|
+
if (!name || capabilities.length === 0) return null;
|
|
8637
|
+
return {
|
|
8638
|
+
version: 1,
|
|
8639
|
+
name,
|
|
8640
|
+
capabilities,
|
|
8641
|
+
...raw.runWithoutApproval === true ? { runWithoutApproval: true } : {},
|
|
8642
|
+
...steps ? { steps } : {},
|
|
8643
|
+
...typeof raw.createdAt === "string" ? { createdAt: raw.createdAt } : {},
|
|
8644
|
+
...typeof raw.updatedAt === "string" ? { updatedAt: raw.updatedAt } : {}
|
|
8645
|
+
};
|
|
8646
|
+
}
|
|
8647
|
+
function readWorkflowDefinition(config, cwd, id) {
|
|
8648
|
+
const file = readStateText(config, cwd, workflowDefinitionPath(id));
|
|
8649
|
+
if (!file) return readCompanyStoreWorkflowDefinition(id);
|
|
8650
|
+
return parseWorkflowDefinition(file.content);
|
|
8651
|
+
}
|
|
8652
|
+
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
8653
|
+
return {
|
|
8654
|
+
slug: id,
|
|
8655
|
+
dir: path26.dirname(source),
|
|
8656
|
+
profilePath: source,
|
|
8657
|
+
bodyPath: source,
|
|
8658
|
+
title: workflow.name,
|
|
8659
|
+
body: "",
|
|
8660
|
+
rawBody: "",
|
|
8661
|
+
rawProfile: { name: id, workflow },
|
|
8662
|
+
config: {
|
|
8663
|
+
action: id,
|
|
8664
|
+
workflow: workflowDefinitionToConfig(workflow),
|
|
8665
|
+
describe: workflow.name
|
|
8666
|
+
}
|
|
8667
|
+
};
|
|
8668
|
+
}
|
|
8669
|
+
function normalizeWorkflowCapabilities(value) {
|
|
8670
|
+
if (!Array.isArray(value)) return [];
|
|
8671
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8672
|
+
const capabilities = [];
|
|
8673
|
+
for (const item of value) {
|
|
8674
|
+
if (typeof item !== "string") continue;
|
|
8675
|
+
const slug2 = item.trim();
|
|
8676
|
+
if (!CAPABILITY_ID_PATTERN.test(slug2) || seen.has(slug2)) continue;
|
|
8677
|
+
seen.add(slug2);
|
|
8678
|
+
capabilities.push(slug2);
|
|
8679
|
+
}
|
|
8680
|
+
return capabilities;
|
|
8681
|
+
}
|
|
8682
|
+
function workflowDefinitionToConfig(workflow) {
|
|
8683
|
+
return {
|
|
8684
|
+
steps: workflow.steps ?? workflow.capabilities.map((capability) => ({ capability }))
|
|
8685
|
+
};
|
|
8686
|
+
}
|
|
8687
|
+
function readCompanyStoreWorkflowDefinition(id) {
|
|
8688
|
+
const root = getCompanyStoreAssetRoot("workflows");
|
|
8689
|
+
if (!root) return null;
|
|
8690
|
+
const filePath = path26.join(root, id, "workflow.json");
|
|
8691
|
+
if (!fs28.existsSync(filePath)) return null;
|
|
8692
|
+
return parseWorkflowDefinition(fs28.readFileSync(filePath, "utf8"));
|
|
8693
|
+
}
|
|
8694
|
+
function parseWorkflowDefinition(content) {
|
|
8695
|
+
try {
|
|
8696
|
+
return normalizeWorkflowDefinition(JSON.parse(content));
|
|
8697
|
+
} catch {
|
|
8698
|
+
return null;
|
|
8699
|
+
}
|
|
8700
|
+
}
|
|
8701
|
+
var WORKFLOW_ID_PATTERN, CAPABILITY_ID_PATTERN;
|
|
8702
|
+
var init_workflowDefinitions = __esm({
|
|
8703
|
+
"src/workflowDefinitions.ts"() {
|
|
8704
|
+
"use strict";
|
|
8705
|
+
init_capabilityFolders();
|
|
8706
|
+
init_companyStore();
|
|
8707
|
+
init_stateRepo();
|
|
8708
|
+
WORKFLOW_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
8709
|
+
CAPABILITY_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;
|
|
8710
|
+
}
|
|
8711
|
+
});
|
|
8712
|
+
|
|
8615
8713
|
// src/scripts/issueStateComment.ts
|
|
8616
8714
|
function isStateEnvelope(x) {
|
|
8617
8715
|
if (x === null || typeof x !== "object") return false;
|
|
@@ -8796,8 +8894,8 @@ var init_contentsApiBackend = __esm({
|
|
|
8796
8894
|
});
|
|
8797
8895
|
|
|
8798
8896
|
// src/scripts/jobState/localFileBackend.ts
|
|
8799
|
-
import * as
|
|
8800
|
-
import * as
|
|
8897
|
+
import * as fs29 from "fs";
|
|
8898
|
+
import * as path27 from "path";
|
|
8801
8899
|
function sanitizeKey(s) {
|
|
8802
8900
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
8803
8901
|
}
|
|
@@ -8853,7 +8951,7 @@ var init_localFileBackend = __esm({
|
|
|
8853
8951
|
if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
|
|
8854
8952
|
this.cwd = opts.cwd;
|
|
8855
8953
|
this.jobsDir = opts.jobsDir;
|
|
8856
|
-
this.absDir =
|
|
8954
|
+
this.absDir = path27.join(opts.cwd, opts.jobsDir);
|
|
8857
8955
|
this.owner = opts.owner;
|
|
8858
8956
|
this.repo = opts.repo;
|
|
8859
8957
|
this.cache = opts.cache ?? defaultCacheAdapter();
|
|
@@ -8868,7 +8966,7 @@ var init_localFileBackend = __esm({
|
|
|
8868
8966
|
`);
|
|
8869
8967
|
return;
|
|
8870
8968
|
}
|
|
8871
|
-
|
|
8969
|
+
fs29.mkdirSync(this.absDir, { recursive: true });
|
|
8872
8970
|
const prefix = this.cacheKeyPrefix();
|
|
8873
8971
|
const probeKey = `${prefix}probe-${Date.now()}`;
|
|
8874
8972
|
try {
|
|
@@ -8897,7 +8995,7 @@ var init_localFileBackend = __esm({
|
|
|
8897
8995
|
`);
|
|
8898
8996
|
return;
|
|
8899
8997
|
}
|
|
8900
|
-
if (!
|
|
8998
|
+
if (!fs29.existsSync(this.absDir)) {
|
|
8901
8999
|
return;
|
|
8902
9000
|
}
|
|
8903
9001
|
const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
|
|
@@ -8913,11 +9011,11 @@ var init_localFileBackend = __esm({
|
|
|
8913
9011
|
}
|
|
8914
9012
|
load(slug2) {
|
|
8915
9013
|
const relPath = stateFilePath(this.jobsDir, slug2);
|
|
8916
|
-
const absPath =
|
|
8917
|
-
if (!
|
|
9014
|
+
const absPath = path27.join(this.cwd, relPath);
|
|
9015
|
+
if (!fs29.existsSync(absPath)) {
|
|
8918
9016
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
8919
9017
|
}
|
|
8920
|
-
const raw =
|
|
9018
|
+
const raw = fs29.readFileSync(absPath, "utf-8");
|
|
8921
9019
|
let parsed;
|
|
8922
9020
|
try {
|
|
8923
9021
|
parsed = JSON.parse(raw);
|
|
@@ -8934,13 +9032,13 @@ var init_localFileBackend = __esm({
|
|
|
8934
9032
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
8935
9033
|
return false;
|
|
8936
9034
|
}
|
|
8937
|
-
const absPath =
|
|
8938
|
-
|
|
9035
|
+
const absPath = path27.join(this.cwd, loaded.path);
|
|
9036
|
+
fs29.mkdirSync(path27.dirname(absPath), { recursive: true });
|
|
8939
9037
|
const body = `${JSON.stringify(next, null, 2)}
|
|
8940
9038
|
`;
|
|
8941
9039
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
8942
|
-
|
|
8943
|
-
|
|
9040
|
+
fs29.writeFileSync(tmpPath, body, "utf-8");
|
|
9041
|
+
fs29.renameSync(tmpPath, absPath);
|
|
8944
9042
|
return true;
|
|
8945
9043
|
}
|
|
8946
9044
|
cacheKeyPrefix() {
|
|
@@ -8980,7 +9078,7 @@ var init_jobState = __esm({
|
|
|
8980
9078
|
});
|
|
8981
9079
|
|
|
8982
9080
|
// src/scripts/goalCapabilityScheduling.ts
|
|
8983
|
-
import * as
|
|
9081
|
+
import * as path28 from "path";
|
|
8984
9082
|
function isCapabilityCadenceGoal(goal, extra) {
|
|
8985
9083
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
|
|
8986
9084
|
}
|
|
@@ -9036,7 +9134,7 @@ function planTargetLoopSchedule(opts) {
|
|
|
9036
9134
|
}
|
|
9037
9135
|
async function planGoalCapabilitySchedule(opts) {
|
|
9038
9136
|
const jobsDir = opts.jobsDir ?? ".kody/capabilities";
|
|
9039
|
-
const jobsRoot =
|
|
9137
|
+
const jobsRoot = path28.join(opts.cwd, jobsDir);
|
|
9040
9138
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
9041
9139
|
const at = now.toISOString();
|
|
9042
9140
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
@@ -9226,6 +9324,43 @@ var init_goalCapabilityScheduling = __esm({
|
|
|
9226
9324
|
});
|
|
9227
9325
|
|
|
9228
9326
|
// src/scripts/advanceManagedGoal.ts
|
|
9327
|
+
function autonomyBlockReason(ctx, goalId, goal, dispatch2) {
|
|
9328
|
+
if (ctx.data.jobForce === true) return null;
|
|
9329
|
+
if (goal.runWithoutApproval !== true) {
|
|
9330
|
+
return `Run without approval is off for ${managedModelKind(goal)} ${goalId}`;
|
|
9331
|
+
}
|
|
9332
|
+
if (dispatch2.workflow) {
|
|
9333
|
+
const workflow = readWorkflowDefinition(ctx.config, ctx.cwd, dispatch2.workflow);
|
|
9334
|
+
if (workflow && workflow.runWithoutApproval !== true) {
|
|
9335
|
+
return `Run without approval is off for workflow ${dispatch2.workflow}`;
|
|
9336
|
+
}
|
|
9337
|
+
}
|
|
9338
|
+
const targetGoal = dispatch2.action === "goal-manager" && typeof dispatch2.cliArgs.goal === "string" ? dispatch2.cliArgs.goal : null;
|
|
9339
|
+
if (targetGoal && targetGoal !== goalId) {
|
|
9340
|
+
const target = fetchGoalState(ctx.config, targetGoal, ctx.cwd);
|
|
9341
|
+
const targetManaged = target ? managedGoalFromState(expandManagedGoalState(target)) : null;
|
|
9342
|
+
if (targetManaged && targetManaged.runWithoutApproval !== true) {
|
|
9343
|
+
return `Run without approval is off for goal ${targetGoal}`;
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9346
|
+
return null;
|
|
9347
|
+
}
|
|
9348
|
+
function managedModelKind(goal) {
|
|
9349
|
+
return goal.loopTarget || goal.schedule ? "Loop" : "Goal";
|
|
9350
|
+
}
|
|
9351
|
+
function stageAutonomyBlocked(data, goalId, goal, goalState, reason) {
|
|
9352
|
+
stageGoalRunLogEvent(data, goalId, {
|
|
9353
|
+
source: "goal-manager",
|
|
9354
|
+
event: "goal.tick.wait",
|
|
9355
|
+
goalType: goal.type,
|
|
9356
|
+
goalState,
|
|
9357
|
+
stage: goal.stage,
|
|
9358
|
+
status: "wait",
|
|
9359
|
+
reason,
|
|
9360
|
+
goal: goalRunLogSnapshot(goalId, goalState, goal),
|
|
9361
|
+
decision: { kind: "wait", reason }
|
|
9362
|
+
});
|
|
9363
|
+
}
|
|
9229
9364
|
function stageManagedGoalDecision(data, goalId, goal, goalState, decision, details) {
|
|
9230
9365
|
if (decision.kind === "dispatch" || decision.kind === "dispatchWorkflow") {
|
|
9231
9366
|
stageGoalRunLogEvent(data, goalId, {
|
|
@@ -9400,9 +9535,11 @@ var init_advanceManagedGoal = __esm({
|
|
|
9400
9535
|
init_manager();
|
|
9401
9536
|
init_runLog();
|
|
9402
9537
|
init_state2();
|
|
9538
|
+
init_stateStore();
|
|
9403
9539
|
init_targetLoopResolution();
|
|
9404
9540
|
init_typeDefinitions();
|
|
9405
9541
|
init_issue();
|
|
9542
|
+
init_workflowDefinitions();
|
|
9406
9543
|
init_goalCapabilityScheduling();
|
|
9407
9544
|
advanceManagedGoal = async (ctx) => {
|
|
9408
9545
|
ctx.skipAgent = true;
|
|
@@ -9497,6 +9634,12 @@ var init_advanceManagedGoal = __esm({
|
|
|
9497
9634
|
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
9498
9635
|
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
9499
9636
|
ctx.data.managedGoalDecision = decision2;
|
|
9637
|
+
const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, decision2.dispatch) : null;
|
|
9638
|
+
if (autonomyBlock) {
|
|
9639
|
+
stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
|
|
9640
|
+
ctx.output.reason = autonomyBlock;
|
|
9641
|
+
return;
|
|
9642
|
+
}
|
|
9500
9643
|
if (decision2.kind === "dispatch" && decision2.dispatch) {
|
|
9501
9644
|
ctx.output.nextDispatch = {
|
|
9502
9645
|
...decision2.dispatch.action ? { action: decision2.dispatch.action } : {},
|
|
@@ -9553,6 +9696,12 @@ var init_advanceManagedGoal = __esm({
|
|
|
9553
9696
|
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
9554
9697
|
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
9555
9698
|
ctx.data.managedGoalDecision = decision2;
|
|
9699
|
+
const autonomyBlock = decision2.kind === "dispatch" && decision2.dispatch ? autonomyBlockReason(ctx, goal.id, managed, decision2.dispatch) : null;
|
|
9700
|
+
if (autonomyBlock) {
|
|
9701
|
+
stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
|
|
9702
|
+
ctx.output.reason = autonomyBlock;
|
|
9703
|
+
return;
|
|
9704
|
+
}
|
|
9556
9705
|
if (decision2.kind === "dispatch" && decision2.dispatch) {
|
|
9557
9706
|
ctx.output.nextDispatch = {
|
|
9558
9707
|
capability: decision2.dispatch.capability,
|
|
@@ -9606,6 +9755,19 @@ var init_advanceManagedGoal = __esm({
|
|
|
9606
9755
|
}
|
|
9607
9756
|
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
9608
9757
|
const afterDecisionSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
|
|
9758
|
+
if (decision.kind === "dispatch" || decision.kind === "dispatchWorkflow") {
|
|
9759
|
+
const planned = decision.kind === "dispatchWorkflow" ? { workflow: decision.workflow, cliArgs: decision.cliArgs } : {
|
|
9760
|
+
capability: decision.capability,
|
|
9761
|
+
...decision.implementation ? { implementation: decision.implementation } : {},
|
|
9762
|
+
cliArgs: decision.cliArgs
|
|
9763
|
+
};
|
|
9764
|
+
const autonomyBlock = autonomyBlockReason(ctx, goal.id, managed, planned);
|
|
9765
|
+
if (autonomyBlock) {
|
|
9766
|
+
stageAutonomyBlocked(ctx.data, goal.id, managed, goal.state, autonomyBlock);
|
|
9767
|
+
ctx.output.reason = autonomyBlock;
|
|
9768
|
+
return;
|
|
9769
|
+
}
|
|
9770
|
+
}
|
|
9609
9771
|
stageManagedGoalDecision(ctx.data, goal.id, managed, goal.state, decision, {
|
|
9610
9772
|
goalSnapshot: afterDecisionSnapshot,
|
|
9611
9773
|
inspection: {
|
|
@@ -11145,8 +11307,8 @@ var init_classifyByLabel = __esm({
|
|
|
11145
11307
|
});
|
|
11146
11308
|
|
|
11147
11309
|
// src/scripts/commitAndPush.ts
|
|
11148
|
-
import * as
|
|
11149
|
-
import * as
|
|
11310
|
+
import * as fs30 from "fs";
|
|
11311
|
+
import * as path29 from "path";
|
|
11150
11312
|
function sentinelPathForStage(cwd, profileName) {
|
|
11151
11313
|
const runId = resolveRunId();
|
|
11152
11314
|
return runtimeStatePath(cwd, "agent-runs", runId, `commit-${profileName}.lock`);
|
|
@@ -11167,9 +11329,9 @@ var init_commitAndPush = __esm({
|
|
|
11167
11329
|
}
|
|
11168
11330
|
const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
|
|
11169
11331
|
const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
|
|
11170
|
-
if (sentinel &&
|
|
11332
|
+
if (sentinel && fs30.existsSync(sentinel)) {
|
|
11171
11333
|
try {
|
|
11172
|
-
const replay = JSON.parse(
|
|
11334
|
+
const replay = JSON.parse(fs30.readFileSync(sentinel, "utf-8"));
|
|
11173
11335
|
ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
|
|
11174
11336
|
if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
|
|
11175
11337
|
if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
|
|
@@ -11222,8 +11384,8 @@ var init_commitAndPush = __esm({
|
|
|
11222
11384
|
const result = ctx.data.commitResult;
|
|
11223
11385
|
if (sentinel && result?.committed) {
|
|
11224
11386
|
try {
|
|
11225
|
-
|
|
11226
|
-
|
|
11387
|
+
fs30.mkdirSync(path29.dirname(sentinel), { recursive: true });
|
|
11388
|
+
fs30.writeFileSync(
|
|
11227
11389
|
sentinel,
|
|
11228
11390
|
JSON.stringify(
|
|
11229
11391
|
{
|
|
@@ -11314,8 +11476,8 @@ var init_commitGoalState = __esm({
|
|
|
11314
11476
|
});
|
|
11315
11477
|
|
|
11316
11478
|
// src/scripts/composePrompt.ts
|
|
11317
|
-
import * as
|
|
11318
|
-
import * as
|
|
11479
|
+
import * as fs31 from "fs";
|
|
11480
|
+
import * as path30 from "path";
|
|
11319
11481
|
function fenceUntrusted(value) {
|
|
11320
11482
|
if (value.trim().length === 0) return value;
|
|
11321
11483
|
const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
|
|
@@ -11436,10 +11598,10 @@ var init_composePrompt = __esm({
|
|
|
11436
11598
|
const explicit = ctx.data.promptTemplate;
|
|
11437
11599
|
const mode = ctx.args.mode;
|
|
11438
11600
|
const candidates = [
|
|
11439
|
-
explicit ?
|
|
11440
|
-
mode ?
|
|
11441
|
-
|
|
11442
|
-
|
|
11601
|
+
explicit ? path30.join(profile.dir, explicit) : null,
|
|
11602
|
+
mode ? path30.join(profile.dir, "prompts", `${mode}.md`) : null,
|
|
11603
|
+
path30.join(profile.dir, "prompt.md"),
|
|
11604
|
+
path30.join(profile.dir, "capability.md")
|
|
11443
11605
|
].filter(Boolean);
|
|
11444
11606
|
let templatePath = "";
|
|
11445
11607
|
let template = "";
|
|
@@ -11452,7 +11614,7 @@ var init_composePrompt = __esm({
|
|
|
11452
11614
|
break;
|
|
11453
11615
|
}
|
|
11454
11616
|
try {
|
|
11455
|
-
template =
|
|
11617
|
+
template = fs31.readFileSync(c, "utf-8");
|
|
11456
11618
|
templatePath = c;
|
|
11457
11619
|
break;
|
|
11458
11620
|
} catch (err) {
|
|
@@ -11463,7 +11625,7 @@ var init_composePrompt = __esm({
|
|
|
11463
11625
|
if (!templatePath) {
|
|
11464
11626
|
let dirState;
|
|
11465
11627
|
try {
|
|
11466
|
-
dirState = `dir contents: [${
|
|
11628
|
+
dirState = `dir contents: [${fs31.readdirSync(profile.dir).join(", ")}]`;
|
|
11467
11629
|
} catch (err) {
|
|
11468
11630
|
dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
|
|
11469
11631
|
}
|
|
@@ -12152,19 +12314,19 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
12152
12314
|
|
|
12153
12315
|
// src/scripts/diagMcp.ts
|
|
12154
12316
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
12155
|
-
import * as
|
|
12317
|
+
import * as fs32 from "fs";
|
|
12156
12318
|
import * as os6 from "os";
|
|
12157
|
-
import * as
|
|
12319
|
+
import * as path31 from "path";
|
|
12158
12320
|
var diagMcp;
|
|
12159
12321
|
var init_diagMcp = __esm({
|
|
12160
12322
|
"src/scripts/diagMcp.ts"() {
|
|
12161
12323
|
"use strict";
|
|
12162
12324
|
diagMcp = async (_ctx) => {
|
|
12163
12325
|
const home = os6.homedir();
|
|
12164
|
-
const cacheDir =
|
|
12326
|
+
const cacheDir = path31.join(home, ".cache", "ms-playwright");
|
|
12165
12327
|
let entries = [];
|
|
12166
12328
|
try {
|
|
12167
|
-
entries =
|
|
12329
|
+
entries = fs32.readdirSync(cacheDir);
|
|
12168
12330
|
} catch {
|
|
12169
12331
|
}
|
|
12170
12332
|
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
@@ -12192,13 +12354,13 @@ var init_diagMcp = __esm({
|
|
|
12192
12354
|
});
|
|
12193
12355
|
|
|
12194
12356
|
// src/scripts/frameworkDetectors.ts
|
|
12195
|
-
import * as
|
|
12196
|
-
import * as
|
|
12357
|
+
import * as fs33 from "fs";
|
|
12358
|
+
import * as path32 from "path";
|
|
12197
12359
|
function detectFrameworks(cwd) {
|
|
12198
12360
|
const out = [];
|
|
12199
12361
|
let deps = {};
|
|
12200
12362
|
try {
|
|
12201
|
-
const pkg = JSON.parse(
|
|
12363
|
+
const pkg = JSON.parse(fs33.readFileSync(path32.join(cwd, "package.json"), "utf-8"));
|
|
12202
12364
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12203
12365
|
} catch {
|
|
12204
12366
|
return out;
|
|
@@ -12235,25 +12397,25 @@ function detectFrameworks(cwd) {
|
|
|
12235
12397
|
}
|
|
12236
12398
|
function findFile(cwd, candidates) {
|
|
12237
12399
|
for (const c of candidates) {
|
|
12238
|
-
if (
|
|
12400
|
+
if (fs33.existsSync(path32.join(cwd, c))) return c;
|
|
12239
12401
|
}
|
|
12240
12402
|
return null;
|
|
12241
12403
|
}
|
|
12242
12404
|
function discoverPayloadCollections(cwd) {
|
|
12243
12405
|
const out = [];
|
|
12244
12406
|
for (const dir of COLLECTION_DIRS) {
|
|
12245
|
-
const full =
|
|
12246
|
-
if (!
|
|
12407
|
+
const full = path32.join(cwd, dir);
|
|
12408
|
+
if (!fs33.existsSync(full)) continue;
|
|
12247
12409
|
let files;
|
|
12248
12410
|
try {
|
|
12249
|
-
files =
|
|
12411
|
+
files = fs33.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
12250
12412
|
} catch {
|
|
12251
12413
|
continue;
|
|
12252
12414
|
}
|
|
12253
12415
|
for (const file of files) {
|
|
12254
12416
|
try {
|
|
12255
|
-
const filePath =
|
|
12256
|
-
const content =
|
|
12417
|
+
const filePath = path32.join(full, file);
|
|
12418
|
+
const content = fs33.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
12257
12419
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
12258
12420
|
if (!slugMatch) continue;
|
|
12259
12421
|
const slug2 = slugMatch[1];
|
|
@@ -12267,7 +12429,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
12267
12429
|
out.push({
|
|
12268
12430
|
name,
|
|
12269
12431
|
slug: slug2,
|
|
12270
|
-
filePath:
|
|
12432
|
+
filePath: path32.relative(cwd, filePath),
|
|
12271
12433
|
fields: fields.slice(0, 20),
|
|
12272
12434
|
hasAdmin
|
|
12273
12435
|
});
|
|
@@ -12280,28 +12442,28 @@ function discoverPayloadCollections(cwd) {
|
|
|
12280
12442
|
function discoverAdminComponents(cwd, collections) {
|
|
12281
12443
|
const out = [];
|
|
12282
12444
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
12283
|
-
const full =
|
|
12284
|
-
if (!
|
|
12445
|
+
const full = path32.join(cwd, dir);
|
|
12446
|
+
if (!fs33.existsSync(full)) continue;
|
|
12285
12447
|
let entries;
|
|
12286
12448
|
try {
|
|
12287
|
-
entries =
|
|
12449
|
+
entries = fs33.readdirSync(full, { withFileTypes: true });
|
|
12288
12450
|
} catch {
|
|
12289
12451
|
continue;
|
|
12290
12452
|
}
|
|
12291
12453
|
for (const entry of entries) {
|
|
12292
|
-
const entryPath =
|
|
12454
|
+
const entryPath = path32.join(full, entry.name);
|
|
12293
12455
|
let name;
|
|
12294
12456
|
let filePath;
|
|
12295
12457
|
if (entry.isDirectory()) {
|
|
12296
12458
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
12297
|
-
(f) =>
|
|
12459
|
+
(f) => fs33.existsSync(path32.join(entryPath, f))
|
|
12298
12460
|
);
|
|
12299
12461
|
if (!indexFile) continue;
|
|
12300
12462
|
name = entry.name;
|
|
12301
|
-
filePath =
|
|
12463
|
+
filePath = path32.relative(cwd, path32.join(entryPath, indexFile));
|
|
12302
12464
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
12303
12465
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
12304
|
-
filePath =
|
|
12466
|
+
filePath = path32.relative(cwd, entryPath);
|
|
12305
12467
|
} else {
|
|
12306
12468
|
continue;
|
|
12307
12469
|
}
|
|
@@ -12309,7 +12471,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
12309
12471
|
if (collections) {
|
|
12310
12472
|
for (const col of collections) {
|
|
12311
12473
|
try {
|
|
12312
|
-
const colContent =
|
|
12474
|
+
const colContent = fs33.readFileSync(path32.join(cwd, col.filePath), "utf-8");
|
|
12313
12475
|
if (colContent.includes(name)) {
|
|
12314
12476
|
usedInCollection = col.slug;
|
|
12315
12477
|
break;
|
|
@@ -12327,8 +12489,8 @@ function scanApiRoutes(cwd) {
|
|
|
12327
12489
|
const out = [];
|
|
12328
12490
|
const appDirs = ["src/app", "app"];
|
|
12329
12491
|
for (const appDir of appDirs) {
|
|
12330
|
-
const apiDir =
|
|
12331
|
-
if (!
|
|
12492
|
+
const apiDir = path32.join(cwd, appDir, "api");
|
|
12493
|
+
if (!fs33.existsSync(apiDir)) continue;
|
|
12332
12494
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
12333
12495
|
break;
|
|
12334
12496
|
}
|
|
@@ -12337,14 +12499,14 @@ function scanApiRoutes(cwd) {
|
|
|
12337
12499
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
12338
12500
|
let entries;
|
|
12339
12501
|
try {
|
|
12340
|
-
entries =
|
|
12502
|
+
entries = fs33.readdirSync(dir, { withFileTypes: true });
|
|
12341
12503
|
} catch {
|
|
12342
12504
|
return;
|
|
12343
12505
|
}
|
|
12344
12506
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
12345
12507
|
if (routeFile) {
|
|
12346
12508
|
try {
|
|
12347
|
-
const content =
|
|
12509
|
+
const content = fs33.readFileSync(path32.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
12348
12510
|
const methods = HTTP_METHODS.filter(
|
|
12349
12511
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
12350
12512
|
);
|
|
@@ -12352,7 +12514,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
12352
12514
|
out.push({
|
|
12353
12515
|
path: prefix,
|
|
12354
12516
|
methods,
|
|
12355
|
-
filePath:
|
|
12517
|
+
filePath: path32.relative(cwd, path32.join(dir, routeFile.name))
|
|
12356
12518
|
});
|
|
12357
12519
|
}
|
|
12358
12520
|
} catch {
|
|
@@ -12363,7 +12525,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
12363
12525
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
12364
12526
|
let segment = entry.name;
|
|
12365
12527
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
12366
|
-
walkApiRoutes(
|
|
12528
|
+
walkApiRoutes(path32.join(dir, entry.name), prefix, cwd, out);
|
|
12367
12529
|
continue;
|
|
12368
12530
|
}
|
|
12369
12531
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -12371,16 +12533,16 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
12371
12533
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
12372
12534
|
segment = `:${segment.slice(1, -1)}`;
|
|
12373
12535
|
}
|
|
12374
|
-
walkApiRoutes(
|
|
12536
|
+
walkApiRoutes(path32.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
12375
12537
|
}
|
|
12376
12538
|
}
|
|
12377
12539
|
function scanEnvVars(cwd) {
|
|
12378
12540
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
12379
12541
|
for (const envFile of candidates) {
|
|
12380
|
-
const envPath =
|
|
12381
|
-
if (!
|
|
12542
|
+
const envPath = path32.join(cwd, envFile);
|
|
12543
|
+
if (!fs33.existsSync(envPath)) continue;
|
|
12382
12544
|
try {
|
|
12383
|
-
const content =
|
|
12545
|
+
const content = fs33.readFileSync(envPath, "utf-8");
|
|
12384
12546
|
const vars = [];
|
|
12385
12547
|
for (const line of content.split("\n")) {
|
|
12386
12548
|
const trimmed = line.trim();
|
|
@@ -12425,8 +12587,8 @@ var init_frameworkDetectors = __esm({
|
|
|
12425
12587
|
});
|
|
12426
12588
|
|
|
12427
12589
|
// src/scripts/discoverQaContext.ts
|
|
12428
|
-
import * as
|
|
12429
|
-
import * as
|
|
12590
|
+
import * as fs34 from "fs";
|
|
12591
|
+
import * as path33 from "path";
|
|
12430
12592
|
function runQaDiscovery(cwd) {
|
|
12431
12593
|
const out = {
|
|
12432
12594
|
routes: [],
|
|
@@ -12457,9 +12619,9 @@ function runQaDiscovery(cwd) {
|
|
|
12457
12619
|
}
|
|
12458
12620
|
function detectDevServer(cwd, out) {
|
|
12459
12621
|
try {
|
|
12460
|
-
const pkg = JSON.parse(
|
|
12622
|
+
const pkg = JSON.parse(fs34.readFileSync(path33.join(cwd, "package.json"), "utf-8"));
|
|
12461
12623
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12462
|
-
const pm =
|
|
12624
|
+
const pm = fs34.existsSync(path33.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs34.existsSync(path33.join(cwd, "yarn.lock")) ? "yarn" : fs34.existsSync(path33.join(cwd, "bun.lockb")) ? "bun" : "npm";
|
|
12463
12625
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
12464
12626
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
12465
12627
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -12469,8 +12631,8 @@ function detectDevServer(cwd, out) {
|
|
|
12469
12631
|
function scanFrontendRoutes(cwd, out) {
|
|
12470
12632
|
const appDirs = ["src/app", "app"];
|
|
12471
12633
|
for (const appDir of appDirs) {
|
|
12472
|
-
const full =
|
|
12473
|
-
if (!
|
|
12634
|
+
const full = path33.join(cwd, appDir);
|
|
12635
|
+
if (!fs34.existsSync(full)) continue;
|
|
12474
12636
|
walkFrontendRoutes(full, "", out);
|
|
12475
12637
|
break;
|
|
12476
12638
|
}
|
|
@@ -12478,7 +12640,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
12478
12640
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
12479
12641
|
let entries;
|
|
12480
12642
|
try {
|
|
12481
|
-
entries =
|
|
12643
|
+
entries = fs34.readdirSync(dir, { withFileTypes: true });
|
|
12482
12644
|
} catch {
|
|
12483
12645
|
return;
|
|
12484
12646
|
}
|
|
@@ -12495,7 +12657,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
12495
12657
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
12496
12658
|
let segment = entry.name;
|
|
12497
12659
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
12498
|
-
walkFrontendRoutes(
|
|
12660
|
+
walkFrontendRoutes(path33.join(dir, entry.name), prefix, out);
|
|
12499
12661
|
continue;
|
|
12500
12662
|
}
|
|
12501
12663
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -12503,7 +12665,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
12503
12665
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
12504
12666
|
segment = `:${segment.slice(1, -1)}`;
|
|
12505
12667
|
}
|
|
12506
|
-
walkFrontendRoutes(
|
|
12668
|
+
walkFrontendRoutes(path33.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
12507
12669
|
}
|
|
12508
12670
|
}
|
|
12509
12671
|
function detectAuthFiles(cwd, out) {
|
|
@@ -12520,23 +12682,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
12520
12682
|
"src/app/api/oauth"
|
|
12521
12683
|
];
|
|
12522
12684
|
for (const c of candidates) {
|
|
12523
|
-
if (
|
|
12685
|
+
if (fs34.existsSync(path33.join(cwd, c))) out.authFiles.push(c);
|
|
12524
12686
|
}
|
|
12525
12687
|
}
|
|
12526
12688
|
function detectRoles(cwd, out) {
|
|
12527
12689
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
12528
12690
|
for (const rp of rolePaths) {
|
|
12529
|
-
const dir =
|
|
12530
|
-
if (!
|
|
12691
|
+
const dir = path33.join(cwd, rp);
|
|
12692
|
+
if (!fs34.existsSync(dir)) continue;
|
|
12531
12693
|
let files;
|
|
12532
12694
|
try {
|
|
12533
|
-
files =
|
|
12695
|
+
files = fs34.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
12534
12696
|
} catch {
|
|
12535
12697
|
continue;
|
|
12536
12698
|
}
|
|
12537
12699
|
for (const f of files) {
|
|
12538
12700
|
try {
|
|
12539
|
-
const content =
|
|
12701
|
+
const content = fs34.readFileSync(path33.join(dir, f), "utf-8").slice(0, 5e3);
|
|
12540
12702
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
12541
12703
|
if (roleMatches) {
|
|
12542
12704
|
for (const m of roleMatches) {
|
|
@@ -13781,12 +13943,12 @@ var init_fixFlow = __esm({
|
|
|
13781
13943
|
|
|
13782
13944
|
// src/scripts/initFlow.ts
|
|
13783
13945
|
import { execFileSync as execFileSync15 } from "child_process";
|
|
13784
|
-
import * as
|
|
13785
|
-
import * as
|
|
13946
|
+
import * as fs35 from "fs";
|
|
13947
|
+
import * as path34 from "path";
|
|
13786
13948
|
function detectPackageManager(cwd) {
|
|
13787
|
-
if (
|
|
13788
|
-
if (
|
|
13789
|
-
if (
|
|
13949
|
+
if (fs35.existsSync(path34.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
13950
|
+
if (fs35.existsSync(path34.join(cwd, "yarn.lock"))) return "yarn";
|
|
13951
|
+
if (fs35.existsSync(path34.join(cwd, "bun.lockb"))) return "bun";
|
|
13790
13952
|
return "npm";
|
|
13791
13953
|
}
|
|
13792
13954
|
function qualityCommandsFor(pm) {
|
|
@@ -13858,22 +14020,22 @@ function performInit(cwd, force) {
|
|
|
13858
14020
|
const pm = detectPackageManager(cwd);
|
|
13859
14021
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
13860
14022
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
13861
|
-
const configPath =
|
|
13862
|
-
if (
|
|
14023
|
+
const configPath = path34.join(cwd, "kody.config.json");
|
|
14024
|
+
if (fs35.existsSync(configPath) && !force) {
|
|
13863
14025
|
skipped.push("kody.config.json");
|
|
13864
14026
|
} else {
|
|
13865
14027
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
13866
|
-
|
|
14028
|
+
fs35.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
13867
14029
|
`);
|
|
13868
14030
|
wrote.push("kody.config.json");
|
|
13869
14031
|
}
|
|
13870
|
-
const workflowDir =
|
|
13871
|
-
const workflowPath =
|
|
13872
|
-
if (
|
|
14032
|
+
const workflowDir = path34.join(cwd, ".github", "workflows");
|
|
14033
|
+
const workflowPath = path34.join(workflowDir, "kody.yml");
|
|
14034
|
+
if (fs35.existsSync(workflowPath) && !force) {
|
|
13873
14035
|
skipped.push(".github/workflows/kody.yml");
|
|
13874
14036
|
} else {
|
|
13875
|
-
|
|
13876
|
-
|
|
14037
|
+
fs35.mkdirSync(workflowDir, { recursive: true });
|
|
14038
|
+
fs35.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
13877
14039
|
wrote.push(".github/workflows/kody.yml");
|
|
13878
14040
|
}
|
|
13879
14041
|
for (const exe of listImplementations()) {
|
|
@@ -13884,12 +14046,12 @@ function performInit(cwd, force) {
|
|
|
13884
14046
|
continue;
|
|
13885
14047
|
}
|
|
13886
14048
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
13887
|
-
const target =
|
|
13888
|
-
if (
|
|
14049
|
+
const target = path34.join(workflowDir, `kody-${exe.name}.yml`);
|
|
14050
|
+
if (fs35.existsSync(target) && !force) {
|
|
13889
14051
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
13890
14052
|
continue;
|
|
13891
14053
|
}
|
|
13892
|
-
|
|
14054
|
+
fs35.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
13893
14055
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
13894
14056
|
}
|
|
13895
14057
|
let labels;
|
|
@@ -14037,7 +14199,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
14037
14199
|
});
|
|
14038
14200
|
|
|
14039
14201
|
// src/scripts/loadAgentAdhoc.ts
|
|
14040
|
-
import * as
|
|
14202
|
+
import * as fs36 from "fs";
|
|
14041
14203
|
function resolveMessage(messageArg) {
|
|
14042
14204
|
const fromComment = readCommentBody();
|
|
14043
14205
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -14045,9 +14207,9 @@ function resolveMessage(messageArg) {
|
|
|
14045
14207
|
}
|
|
14046
14208
|
function readCommentBody() {
|
|
14047
14209
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
14048
|
-
if (!eventPath || !
|
|
14210
|
+
if (!eventPath || !fs36.existsSync(eventPath)) return "";
|
|
14049
14211
|
try {
|
|
14050
|
-
const event = JSON.parse(
|
|
14212
|
+
const event = JSON.parse(fs36.readFileSync(eventPath, "utf-8"));
|
|
14051
14213
|
return String(event.comment?.body ?? "");
|
|
14052
14214
|
} catch {
|
|
14053
14215
|
return "";
|
|
@@ -14100,10 +14262,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
14100
14262
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
14101
14263
|
}
|
|
14102
14264
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
14103
|
-
if (!
|
|
14265
|
+
if (!fs36.existsSync(agentPath)) {
|
|
14104
14266
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
14105
14267
|
}
|
|
14106
|
-
const { title, body } = parseAgentFile(
|
|
14268
|
+
const { title, body } = parseAgentFile(fs36.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
14107
14269
|
const message = resolveMessage(ctx.args.message);
|
|
14108
14270
|
if (!message) {
|
|
14109
14271
|
throw new Error(
|
|
@@ -14347,8 +14509,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
14347
14509
|
});
|
|
14348
14510
|
|
|
14349
14511
|
// src/scripts/loadJobFromFile.ts
|
|
14350
|
-
import * as
|
|
14351
|
-
import * as
|
|
14512
|
+
import * as fs37 from "fs";
|
|
14513
|
+
import * as path35 from "path";
|
|
14352
14514
|
function parseJobFile(raw, slug2) {
|
|
14353
14515
|
let stripped = raw;
|
|
14354
14516
|
if (stripped.startsWith("---\n")) {
|
|
@@ -14386,9 +14548,9 @@ var init_loadJobFromFile = __esm({
|
|
|
14386
14548
|
if (!slug2) {
|
|
14387
14549
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
14388
14550
|
}
|
|
14389
|
-
const capability = resolveCapabilityFolder(slug2,
|
|
14551
|
+
const capability = resolveCapabilityFolder(slug2, path35.join(ctx.cwd, jobsDir));
|
|
14390
14552
|
if (!capability) {
|
|
14391
|
-
throw new Error(`loadJobFromFile: capability folder not found or incomplete: ${
|
|
14553
|
+
throw new Error(`loadJobFromFile: capability folder not found or incomplete: ${path35.join(ctx.cwd, jobsDir, slug2)}`);
|
|
14392
14554
|
}
|
|
14393
14555
|
const { title, body, config } = capability;
|
|
14394
14556
|
const mentions = (config.mentions ?? []).map((login) => `@${login}`).join(" ");
|
|
@@ -14397,12 +14559,12 @@ var init_loadJobFromFile = __esm({
|
|
|
14397
14559
|
let agentIdentity = "";
|
|
14398
14560
|
if (agentSlug) {
|
|
14399
14561
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
14400
|
-
if (!
|
|
14562
|
+
if (!fs37.existsSync(agentPath)) {
|
|
14401
14563
|
throw new Error(
|
|
14402
14564
|
`loadJobFromFile: capability '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
14403
14565
|
);
|
|
14404
14566
|
}
|
|
14405
|
-
const agentRaw =
|
|
14567
|
+
const agentRaw = fs37.readFileSync(agentPath, "utf-8");
|
|
14406
14568
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
14407
14569
|
agentTitle = parsed.title;
|
|
14408
14570
|
agentIdentity = parsed.body;
|
|
@@ -14482,13 +14644,13 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
14482
14644
|
});
|
|
14483
14645
|
|
|
14484
14646
|
// src/scripts/kodyVariables.ts
|
|
14485
|
-
import * as
|
|
14486
|
-
import * as
|
|
14647
|
+
import * as fs38 from "fs";
|
|
14648
|
+
import * as path36 from "path";
|
|
14487
14649
|
function readKodyVariables(cwd) {
|
|
14488
|
-
const full =
|
|
14650
|
+
const full = path36.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
14489
14651
|
let raw;
|
|
14490
14652
|
try {
|
|
14491
|
-
raw =
|
|
14653
|
+
raw = fs38.readFileSync(full, "utf-8");
|
|
14492
14654
|
} catch {
|
|
14493
14655
|
return {};
|
|
14494
14656
|
}
|
|
@@ -14556,8 +14718,8 @@ var init_keys = __esm({
|
|
|
14556
14718
|
});
|
|
14557
14719
|
|
|
14558
14720
|
// src/stateRepoGithub.ts
|
|
14559
|
-
import * as
|
|
14560
|
-
import * as
|
|
14721
|
+
import * as fs39 from "fs";
|
|
14722
|
+
import * as path37 from "path";
|
|
14561
14723
|
function recordValue4(value) {
|
|
14562
14724
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
14563
14725
|
}
|
|
@@ -14697,15 +14859,15 @@ function mergeJsonl(localText, remoteText) {
|
|
|
14697
14859
|
async function syncJsonlFileFromGithubState(opts) {
|
|
14698
14860
|
const remote = await readGithubStateTextWithConfig(opts);
|
|
14699
14861
|
if (!remote) return;
|
|
14700
|
-
const local =
|
|
14862
|
+
const local = fs39.existsSync(opts.localPath) ? fs39.readFileSync(opts.localPath, "utf-8") : "";
|
|
14701
14863
|
const next = mergeJsonl(local, remote.content);
|
|
14702
14864
|
if (next === local) return;
|
|
14703
|
-
|
|
14704
|
-
|
|
14865
|
+
fs39.mkdirSync(path37.dirname(opts.localPath), { recursive: true });
|
|
14866
|
+
fs39.writeFileSync(opts.localPath, next);
|
|
14705
14867
|
}
|
|
14706
14868
|
async function persistJsonlFileToGithubState(opts) {
|
|
14707
|
-
if (!
|
|
14708
|
-
const localText =
|
|
14869
|
+
if (!fs39.existsSync(opts.localPath)) return;
|
|
14870
|
+
const localText = fs39.readFileSync(opts.localPath, "utf-8");
|
|
14709
14871
|
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
14710
14872
|
const remote = await readGithubStateTextWithConfig(opts);
|
|
14711
14873
|
const body = mergeJsonl(localText, remote?.content ?? "");
|
|
@@ -14844,8 +15006,8 @@ var init_runtimeSecrets = __esm({
|
|
|
14844
15006
|
});
|
|
14845
15007
|
|
|
14846
15008
|
// src/scripts/loadQaContext.ts
|
|
14847
|
-
import * as
|
|
14848
|
-
import * as
|
|
15009
|
+
import * as fs40 from "fs";
|
|
15010
|
+
import * as path38 from "path";
|
|
14849
15011
|
function parseSlugList(value) {
|
|
14850
15012
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
14851
15013
|
return inner.split(",").map(
|
|
@@ -14874,18 +15036,18 @@ function readProfileAgents(raw) {
|
|
|
14874
15036
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
14875
15037
|
}
|
|
14876
15038
|
function readProfile(cwd) {
|
|
14877
|
-
const dir =
|
|
14878
|
-
if (!
|
|
15039
|
+
const dir = path38.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
15040
|
+
if (!fs40.existsSync(dir)) return "";
|
|
14879
15041
|
let entries;
|
|
14880
15042
|
try {
|
|
14881
|
-
entries =
|
|
15043
|
+
entries = fs40.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
14882
15044
|
} catch {
|
|
14883
15045
|
return "";
|
|
14884
15046
|
}
|
|
14885
15047
|
const blocks = [];
|
|
14886
15048
|
for (const file of entries) {
|
|
14887
15049
|
try {
|
|
14888
|
-
const raw =
|
|
15050
|
+
const raw = fs40.readFileSync(path38.join(dir, file), "utf-8");
|
|
14889
15051
|
const { agent, body } = readProfileAgents(raw);
|
|
14890
15052
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
14891
15053
|
blocks.push(`## ${file}
|
|
@@ -14934,8 +15096,8 @@ var init_loadQaContext = __esm({
|
|
|
14934
15096
|
});
|
|
14935
15097
|
|
|
14936
15098
|
// src/taskContext.ts
|
|
14937
|
-
import * as
|
|
14938
|
-
import * as
|
|
15099
|
+
import * as fs41 from "fs";
|
|
15100
|
+
import * as path39 from "path";
|
|
14939
15101
|
function buildTaskContext(args) {
|
|
14940
15102
|
return {
|
|
14941
15103
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -14951,9 +15113,9 @@ function buildTaskContext(args) {
|
|
|
14951
15113
|
function persistTaskContext(cwd, ctx) {
|
|
14952
15114
|
try {
|
|
14953
15115
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
14954
|
-
|
|
14955
|
-
const file =
|
|
14956
|
-
|
|
15116
|
+
fs41.mkdirSync(dir, { recursive: true });
|
|
15117
|
+
const file = path39.join(dir, "task-context.json");
|
|
15118
|
+
fs41.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
14957
15119
|
`);
|
|
14958
15120
|
return file;
|
|
14959
15121
|
} catch (err) {
|
|
@@ -17463,12 +17625,12 @@ fi
|
|
|
17463
17625
|
|
|
17464
17626
|
// src/scripts/runPreviewBuild.ts
|
|
17465
17627
|
import { copyFile, writeFile } from "fs/promises";
|
|
17466
|
-
import * as
|
|
17628
|
+
import * as path40 from "path";
|
|
17467
17629
|
import { fileURLToPath } from "url";
|
|
17468
17630
|
function bundledDockerfilePath(mode) {
|
|
17469
|
-
const here =
|
|
17631
|
+
const here = path40.dirname(fileURLToPath(import.meta.url));
|
|
17470
17632
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
17471
|
-
return
|
|
17633
|
+
return path40.join(here, "preview-build-templates", file);
|
|
17472
17634
|
}
|
|
17473
17635
|
function required(name) {
|
|
17474
17636
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -17719,10 +17881,10 @@ var init_runPreviewBuild = __esm({
|
|
|
17719
17881
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
17720
17882
|
if (Object.keys(buildEnv).length > 0) {
|
|
17721
17883
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
17722
|
-
await writeFile(
|
|
17884
|
+
await writeFile(path40.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
17723
17885
|
`, "utf8");
|
|
17724
17886
|
}
|
|
17725
|
-
const consumerDockerfile =
|
|
17887
|
+
const consumerDockerfile = path40.join(ctx.cwd, "Dockerfile.preview");
|
|
17726
17888
|
const { stat } = await import("fs/promises");
|
|
17727
17889
|
let hasConsumerDockerfile = false;
|
|
17728
17890
|
try {
|
|
@@ -17906,8 +18068,8 @@ var init_tickShellRunner = __esm({
|
|
|
17906
18068
|
});
|
|
17907
18069
|
|
|
17908
18070
|
// src/scripts/runScheduledImplementationTick.ts
|
|
17909
|
-
import * as
|
|
17910
|
-
import * as
|
|
18071
|
+
import * as fs42 from "fs";
|
|
18072
|
+
import * as path41 from "path";
|
|
17911
18073
|
var runScheduledImplementationTick;
|
|
17912
18074
|
var init_runScheduledImplementationTick = __esm({
|
|
17913
18075
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -17927,14 +18089,14 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
17927
18089
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
17928
18090
|
return;
|
|
17929
18091
|
}
|
|
17930
|
-
const capability = resolveCapabilityFolder(slug2,
|
|
18092
|
+
const capability = resolveCapabilityFolder(slug2, path41.join(ctx.cwd, jobsDir));
|
|
17931
18093
|
if (!capability) {
|
|
17932
18094
|
ctx.output.exitCode = 99;
|
|
17933
18095
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug2} (searched ${jobsDir} and company store)`;
|
|
17934
18096
|
return;
|
|
17935
18097
|
}
|
|
17936
|
-
const shellPath =
|
|
17937
|
-
if (!
|
|
18098
|
+
const shellPath = path41.join(profile.dir, shell);
|
|
18099
|
+
if (!fs42.existsSync(shellPath)) {
|
|
17938
18100
|
ctx.output.exitCode = 99;
|
|
17939
18101
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
17940
18102
|
return;
|
|
@@ -17965,8 +18127,8 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
17965
18127
|
});
|
|
17966
18128
|
|
|
17967
18129
|
// src/scripts/runTickScript.ts
|
|
17968
|
-
import * as
|
|
17969
|
-
import * as
|
|
18130
|
+
import * as fs43 from "fs";
|
|
18131
|
+
import * as path42 from "path";
|
|
17970
18132
|
var runTickScript;
|
|
17971
18133
|
var init_runTickScript = __esm({
|
|
17972
18134
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -17985,10 +18147,10 @@ var init_runTickScript = __esm({
|
|
|
17985
18147
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
17986
18148
|
return;
|
|
17987
18149
|
}
|
|
17988
|
-
const capability = readCapabilityFolder(
|
|
18150
|
+
const capability = readCapabilityFolder(path42.join(ctx.cwd, jobsDir), slug2);
|
|
17989
18151
|
if (!capability) {
|
|
17990
18152
|
ctx.output.exitCode = 99;
|
|
17991
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
18153
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path42.join(ctx.cwd, jobsDir, slug2)}`;
|
|
17992
18154
|
return;
|
|
17993
18155
|
}
|
|
17994
18156
|
const tickScript = capability.config.tickScript;
|
|
@@ -17997,8 +18159,8 @@ var init_runTickScript = __esm({
|
|
|
17997
18159
|
ctx.output.reason = `runTickScript: capability ${slug2} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
17998
18160
|
return;
|
|
17999
18161
|
}
|
|
18000
|
-
const scriptPath =
|
|
18001
|
-
if (!
|
|
18162
|
+
const scriptPath = path42.isAbsolute(tickScript) ? tickScript : path42.join(ctx.cwd, tickScript);
|
|
18163
|
+
if (!fs43.existsSync(scriptPath)) {
|
|
18002
18164
|
ctx.output.exitCode = 99;
|
|
18003
18165
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
18004
18166
|
return;
|
|
@@ -19143,7 +19305,7 @@ var init_warmupMcp = __esm({
|
|
|
19143
19305
|
});
|
|
19144
19306
|
|
|
19145
19307
|
// src/scripts/writeAgentRunSummary.ts
|
|
19146
|
-
import * as
|
|
19308
|
+
import * as fs44 from "fs";
|
|
19147
19309
|
var writeAgentRunSummary;
|
|
19148
19310
|
var init_writeAgentRunSummary = __esm({
|
|
19149
19311
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -19169,7 +19331,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
19169
19331
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
19170
19332
|
lines.push("");
|
|
19171
19333
|
try {
|
|
19172
|
-
|
|
19334
|
+
fs44.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
19173
19335
|
`);
|
|
19174
19336
|
} catch {
|
|
19175
19337
|
}
|
|
@@ -19427,6 +19589,7 @@ var init_scripts = __esm({
|
|
|
19427
19589
|
planTaskJobs,
|
|
19428
19590
|
dispatchNextTaskJob,
|
|
19429
19591
|
runScheduledImplementationTick,
|
|
19592
|
+
runScheduledExecutableTick: runScheduledImplementationTick,
|
|
19430
19593
|
runTickScript,
|
|
19431
19594
|
runPreviewBuild,
|
|
19432
19595
|
advanceManagedGoal,
|
|
@@ -19495,53 +19658,53 @@ var init_scripts = __esm({
|
|
|
19495
19658
|
// src/stateWorkspace.ts
|
|
19496
19659
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
19497
19660
|
import * as crypto3 from "crypto";
|
|
19498
|
-
import * as
|
|
19661
|
+
import * as fs45 from "fs";
|
|
19499
19662
|
import * as os7 from "os";
|
|
19500
|
-
import * as
|
|
19663
|
+
import * as path43 from "path";
|
|
19501
19664
|
function writeLocalFile(cwd, relativePath, content) {
|
|
19502
|
-
const fullPath =
|
|
19503
|
-
|
|
19504
|
-
|
|
19665
|
+
const fullPath = path43.join(cwd, relativePath);
|
|
19666
|
+
fs45.mkdirSync(path43.dirname(fullPath), { recursive: true });
|
|
19667
|
+
fs45.writeFileSync(fullPath, content);
|
|
19505
19668
|
}
|
|
19506
19669
|
function copyPath(source, target) {
|
|
19507
|
-
const st =
|
|
19508
|
-
|
|
19670
|
+
const st = fs45.lstatSync(source);
|
|
19671
|
+
fs45.rmSync(target, { recursive: true, force: true });
|
|
19509
19672
|
if (st.isSymbolicLink()) return;
|
|
19510
|
-
|
|
19511
|
-
|
|
19673
|
+
fs45.mkdirSync(path43.dirname(target), { recursive: true });
|
|
19674
|
+
fs45.cpSync(source, target, { recursive: true, force: true });
|
|
19512
19675
|
}
|
|
19513
19676
|
function overlayDirectoryChildren(cwd, sourceDir, localDir) {
|
|
19514
|
-
if (!
|
|
19515
|
-
for (const entry of
|
|
19516
|
-
const source =
|
|
19517
|
-
const target =
|
|
19677
|
+
if (!fs45.existsSync(sourceDir)) return;
|
|
19678
|
+
for (const entry of fs45.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
19679
|
+
const source = path43.join(sourceDir, entry.name);
|
|
19680
|
+
const target = path43.join(cwd, localDir, entry.name);
|
|
19518
19681
|
copyPath(source, target);
|
|
19519
19682
|
}
|
|
19520
19683
|
}
|
|
19521
19684
|
function hydrateStateWorkspace(config, cwd) {
|
|
19522
19685
|
if (process.env.VITEST && process.env[TEST_FETCH_ENV] !== "1") return;
|
|
19523
19686
|
const parsed = parseStateRepo(config);
|
|
19524
|
-
const hydrateKey = `${
|
|
19687
|
+
const hydrateKey = `${path43.resolve(cwd)}|${parsed.owner}/${parsed.repo}|${parsed.basePath}|${parsed.branch}`;
|
|
19525
19688
|
if (hydratedWorkspaces.has(hydrateKey)) return;
|
|
19526
19689
|
const snapshotRoot = fetchStateSnapshot(parsed);
|
|
19527
19690
|
for (const mapping of DIR_MAPPINGS) {
|
|
19528
|
-
overlayDirectoryChildren(cwd,
|
|
19691
|
+
overlayDirectoryChildren(cwd, path43.join(snapshotRoot, mapping.stateDir), mapping.localDir);
|
|
19529
19692
|
}
|
|
19530
19693
|
for (const mapping of FILE_MAPPINGS) {
|
|
19531
|
-
const source =
|
|
19532
|
-
if (
|
|
19533
|
-
writeLocalFile(cwd, mapping.localPath,
|
|
19694
|
+
const source = path43.join(snapshotRoot, mapping.statePath);
|
|
19695
|
+
if (fs45.existsSync(source) && !fs45.lstatSync(source).isSymbolicLink() && fs45.statSync(source).isFile()) {
|
|
19696
|
+
writeLocalFile(cwd, mapping.localPath, fs45.readFileSync(source, "utf-8"));
|
|
19534
19697
|
}
|
|
19535
19698
|
}
|
|
19536
19699
|
hydratedWorkspaces.add(hydrateKey);
|
|
19537
19700
|
}
|
|
19538
19701
|
function fetchStateSnapshot(parsed) {
|
|
19539
|
-
const cacheDir =
|
|
19702
|
+
const cacheDir = path43.join(cacheRoot2(), cacheKey3(parsed));
|
|
19540
19703
|
const url = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
19541
19704
|
try {
|
|
19542
|
-
|
|
19543
|
-
if (!
|
|
19544
|
-
|
|
19705
|
+
fs45.mkdirSync(path43.dirname(cacheDir), { recursive: true });
|
|
19706
|
+
if (!fs45.existsSync(path43.join(cacheDir, ".git"))) {
|
|
19707
|
+
fs45.rmSync(cacheDir, { recursive: true, force: true });
|
|
19545
19708
|
runGit3(["clone", "--no-checkout", "--filter=blob:none", url, cacheDir]);
|
|
19546
19709
|
}
|
|
19547
19710
|
runGit3(["-C", cacheDir, "remote", "set-url", "origin", url]);
|
|
@@ -19556,10 +19719,10 @@ function fetchStateSnapshot(parsed) {
|
|
|
19556
19719
|
`stateWorkspace: failed to fetch ${parsed.owner}/${parsed.repo}:${parsed.basePath}@${parsed.branch}: ${msg}`
|
|
19557
19720
|
);
|
|
19558
19721
|
}
|
|
19559
|
-
return
|
|
19722
|
+
return path43.join(cacheDir, parsed.basePath);
|
|
19560
19723
|
}
|
|
19561
19724
|
function cacheRoot2() {
|
|
19562
|
-
return process.env[CACHE_ENV2]?.trim() ||
|
|
19725
|
+
return process.env[CACHE_ENV2]?.trim() || path43.join(os7.homedir(), ".cache", "kody", "state-repo");
|
|
19563
19726
|
}
|
|
19564
19727
|
function cacheKey3(parsed) {
|
|
19565
19728
|
return crypto3.createHash("sha256").update(`${parsed.owner}/${parsed.repo}#${parsed.branch}#${parsed.basePath}`).digest("hex").slice(0, 24);
|
|
@@ -19599,15 +19762,15 @@ var init_stateWorkspace = __esm({
|
|
|
19599
19762
|
"use strict";
|
|
19600
19763
|
init_stateRepo();
|
|
19601
19764
|
DIR_MAPPINGS = [
|
|
19602
|
-
{ stateDir: "capabilities", localDir:
|
|
19603
|
-
{ stateDir: "agents", localDir:
|
|
19604
|
-
{ stateDir: "context", localDir:
|
|
19605
|
-
{ stateDir: "memory", localDir:
|
|
19765
|
+
{ stateDir: "capabilities", localDir: path43.join(".kody", "capabilities") },
|
|
19766
|
+
{ stateDir: "agents", localDir: path43.join(".kody", "agents") },
|
|
19767
|
+
{ stateDir: "context", localDir: path43.join(".kody", "context") },
|
|
19768
|
+
{ stateDir: "memory", localDir: path43.join(".kody", "memory") }
|
|
19606
19769
|
];
|
|
19607
19770
|
FILE_MAPPINGS = [
|
|
19608
|
-
{ statePath: "instructions.md", localPath:
|
|
19609
|
-
{ statePath: "variables.json", localPath:
|
|
19610
|
-
{ statePath: "secrets.enc", localPath:
|
|
19771
|
+
{ statePath: "instructions.md", localPath: path43.join(".kody", "instructions.md") },
|
|
19772
|
+
{ statePath: "variables.json", localPath: path43.join(".kody", "variables.json") },
|
|
19773
|
+
{ statePath: "secrets.enc", localPath: path43.join(".kody", "secrets.enc") }
|
|
19611
19774
|
];
|
|
19612
19775
|
CACHE_ENV2 = "KODY_STATE_REPO_CACHE";
|
|
19613
19776
|
TEST_FETCH_ENV = "KODY_STATE_WORKSPACE_FETCH_FOR_TESTS";
|
|
@@ -19681,8 +19844,8 @@ var init_tools = __esm({
|
|
|
19681
19844
|
|
|
19682
19845
|
// src/executor.ts
|
|
19683
19846
|
import { spawn as spawn7 } from "child_process";
|
|
19684
|
-
import * as
|
|
19685
|
-
import * as
|
|
19847
|
+
import * as fs46 from "fs";
|
|
19848
|
+
import * as path44 from "path";
|
|
19686
19849
|
function isMutatingPostflight(scriptName) {
|
|
19687
19850
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
19688
19851
|
}
|
|
@@ -19727,9 +19890,7 @@ function jobReferenceBlock(profileName, profile, data) {
|
|
|
19727
19890
|
const jobId = typeof data.jobId === "string" && data.jobId.length > 0 ? data.jobId : null;
|
|
19728
19891
|
const flavor = typeof data.jobFlavor === "string" && data.jobFlavor.length > 0 ? data.jobFlavor : null;
|
|
19729
19892
|
const schedule = typeof data.jobSchedule === "string" && data.jobSchedule.length > 0 ? data.jobSchedule : null;
|
|
19730
|
-
const isJob2 = Boolean(
|
|
19731
|
-
jobId || flavor || schedule || data.jobCapability || data.selectedImplementation || data.jobWhy
|
|
19732
|
-
);
|
|
19893
|
+
const isJob2 = Boolean(jobId || flavor || schedule || data.jobCapability || data.selectedImplementation || data.jobWhy);
|
|
19733
19894
|
if (!isJob2) return null;
|
|
19734
19895
|
const capability = typeof data.jobCapability === "string" && data.jobCapability.length > 0 ? data.jobCapability : profile.implementation ? profile.name : null;
|
|
19735
19896
|
const implementation = typeof profile.implementation === "string" && profile.implementation.length > 0 ? profile.implementation : typeof data.selectedImplementation === "string" && data.selectedImplementation.length > 0 ? data.selectedImplementation : profileName;
|
|
@@ -19907,7 +20068,7 @@ async function runImplementation(profileName, input) {
|
|
|
19907
20068
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
19908
20069
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
19909
20070
|
const invokeAgent = async (prompt) => {
|
|
19910
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
20071
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path44.isAbsolute(p) ? p : path44.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
19911
20072
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
19912
20073
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
19913
20074
|
const agents = loadSubagents(profile);
|
|
@@ -20333,17 +20494,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
20333
20494
|
function resolveProfilePath(profileName) {
|
|
20334
20495
|
const found = resolveImplementation(profileName);
|
|
20335
20496
|
if (found) return found;
|
|
20336
|
-
const here =
|
|
20497
|
+
const here = path44.dirname(new URL(import.meta.url).pathname);
|
|
20337
20498
|
const candidates = [
|
|
20338
|
-
|
|
20499
|
+
path44.join(here, "implementations", profileName, "profile.json"),
|
|
20339
20500
|
// same-dir sibling (dev)
|
|
20340
|
-
|
|
20501
|
+
path44.join(here, "..", "implementations", profileName, "profile.json"),
|
|
20341
20502
|
// up one (prod: dist/bin → dist/implementations)
|
|
20342
|
-
|
|
20503
|
+
path44.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
20343
20504
|
// fallback
|
|
20344
20505
|
];
|
|
20345
20506
|
for (const c of candidates) {
|
|
20346
|
-
if (
|
|
20507
|
+
if (fs46.existsSync(c)) return c;
|
|
20347
20508
|
}
|
|
20348
20509
|
return candidates[0];
|
|
20349
20510
|
}
|
|
@@ -20458,8 +20619,8 @@ function resolveShellTimeoutMs(entry) {
|
|
|
20458
20619
|
}
|
|
20459
20620
|
async function runShellEntry(entry, ctx, profile) {
|
|
20460
20621
|
const shellName = entry.shell;
|
|
20461
|
-
const shellPath =
|
|
20462
|
-
if (!
|
|
20622
|
+
const shellPath = path44.join(profile.dir, shellName);
|
|
20623
|
+
if (!fs46.existsSync(shellPath)) {
|
|
20463
20624
|
ctx.skipAgent = true;
|
|
20464
20625
|
ctx.output.exitCode = 99;
|
|
20465
20626
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
@@ -20610,101 +20771,6 @@ var init_executor = __esm({
|
|
|
20610
20771
|
}
|
|
20611
20772
|
});
|
|
20612
20773
|
|
|
20613
|
-
// src/workflowDefinitions.ts
|
|
20614
|
-
import * as fs46 from "fs";
|
|
20615
|
-
import * as path44 from "path";
|
|
20616
|
-
function isWorkflowDefinitionId(value) {
|
|
20617
|
-
return WORKFLOW_ID_PATTERN.test(value);
|
|
20618
|
-
}
|
|
20619
|
-
function workflowDefinitionPath(id) {
|
|
20620
|
-
if (!isWorkflowDefinitionId(id)) {
|
|
20621
|
-
throw new Error(`Invalid workflow id "${id}"`);
|
|
20622
|
-
}
|
|
20623
|
-
return `workflows/${id}/workflow.json`;
|
|
20624
|
-
}
|
|
20625
|
-
function normalizeWorkflowDefinition(value) {
|
|
20626
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
20627
|
-
const raw = value;
|
|
20628
|
-
const name = typeof raw.name === "string" ? raw.name.trim() : "";
|
|
20629
|
-
const workflow = parseCapabilityWorkflow({ steps: raw.steps });
|
|
20630
|
-
const steps = workflow?.steps;
|
|
20631
|
-
const capabilities = steps ? steps.map((step) => step.capability) : normalizeWorkflowCapabilities(raw.capabilities);
|
|
20632
|
-
if (!name || capabilities.length === 0) return null;
|
|
20633
|
-
return {
|
|
20634
|
-
version: 1,
|
|
20635
|
-
name,
|
|
20636
|
-
capabilities,
|
|
20637
|
-
...steps ? { steps } : {},
|
|
20638
|
-
...typeof raw.createdAt === "string" ? { createdAt: raw.createdAt } : {},
|
|
20639
|
-
...typeof raw.updatedAt === "string" ? { updatedAt: raw.updatedAt } : {}
|
|
20640
|
-
};
|
|
20641
|
-
}
|
|
20642
|
-
function readWorkflowDefinition(config, cwd, id) {
|
|
20643
|
-
const file = readStateText(config, cwd, workflowDefinitionPath(id));
|
|
20644
|
-
if (!file) return readCompanyStoreWorkflowDefinition(id);
|
|
20645
|
-
return parseWorkflowDefinition(file.content);
|
|
20646
|
-
}
|
|
20647
|
-
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
20648
|
-
return {
|
|
20649
|
-
slug: id,
|
|
20650
|
-
dir: path44.dirname(source),
|
|
20651
|
-
profilePath: source,
|
|
20652
|
-
bodyPath: source,
|
|
20653
|
-
title: workflow.name,
|
|
20654
|
-
body: "",
|
|
20655
|
-
rawBody: "",
|
|
20656
|
-
rawProfile: { name: id, workflow },
|
|
20657
|
-
config: {
|
|
20658
|
-
action: id,
|
|
20659
|
-
workflow: workflowDefinitionToConfig(workflow),
|
|
20660
|
-
describe: workflow.name
|
|
20661
|
-
}
|
|
20662
|
-
};
|
|
20663
|
-
}
|
|
20664
|
-
function normalizeWorkflowCapabilities(value) {
|
|
20665
|
-
if (!Array.isArray(value)) return [];
|
|
20666
|
-
const seen = /* @__PURE__ */ new Set();
|
|
20667
|
-
const capabilities = [];
|
|
20668
|
-
for (const item of value) {
|
|
20669
|
-
if (typeof item !== "string") continue;
|
|
20670
|
-
const slug2 = item.trim();
|
|
20671
|
-
if (!CAPABILITY_ID_PATTERN.test(slug2) || seen.has(slug2)) continue;
|
|
20672
|
-
seen.add(slug2);
|
|
20673
|
-
capabilities.push(slug2);
|
|
20674
|
-
}
|
|
20675
|
-
return capabilities;
|
|
20676
|
-
}
|
|
20677
|
-
function workflowDefinitionToConfig(workflow) {
|
|
20678
|
-
return {
|
|
20679
|
-
steps: workflow.steps ?? workflow.capabilities.map((capability) => ({ capability }))
|
|
20680
|
-
};
|
|
20681
|
-
}
|
|
20682
|
-
function readCompanyStoreWorkflowDefinition(id) {
|
|
20683
|
-
const root = getCompanyStoreAssetRoot("workflows");
|
|
20684
|
-
if (!root) return null;
|
|
20685
|
-
const filePath = path44.join(root, id, "workflow.json");
|
|
20686
|
-
if (!fs46.existsSync(filePath)) return null;
|
|
20687
|
-
return parseWorkflowDefinition(fs46.readFileSync(filePath, "utf8"));
|
|
20688
|
-
}
|
|
20689
|
-
function parseWorkflowDefinition(content) {
|
|
20690
|
-
try {
|
|
20691
|
-
return normalizeWorkflowDefinition(JSON.parse(content));
|
|
20692
|
-
} catch {
|
|
20693
|
-
return null;
|
|
20694
|
-
}
|
|
20695
|
-
}
|
|
20696
|
-
var WORKFLOW_ID_PATTERN, CAPABILITY_ID_PATTERN;
|
|
20697
|
-
var init_workflowDefinitions = __esm({
|
|
20698
|
-
"src/workflowDefinitions.ts"() {
|
|
20699
|
-
"use strict";
|
|
20700
|
-
init_capabilityFolders();
|
|
20701
|
-
init_companyStore();
|
|
20702
|
-
init_stateRepo();
|
|
20703
|
-
WORKFLOW_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
20704
|
-
CAPABILITY_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;
|
|
20705
|
-
}
|
|
20706
|
-
});
|
|
20707
|
-
|
|
20708
20774
|
// src/job.ts
|
|
20709
20775
|
var job_exports = {};
|
|
20710
20776
|
__export(job_exports, {
|
|
@@ -20824,6 +20890,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
20824
20890
|
preloadedData.selectedImplementation = profileName;
|
|
20825
20891
|
if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
|
|
20826
20892
|
if (valid.saveReport === true) preloadedData.jobSaveReport = true;
|
|
20893
|
+
if (valid.force === true) preloadedData.jobForce = true;
|
|
20827
20894
|
if (valid.resultTarget) preloadedData.capabilityResultTarget = valid.resultTarget;
|
|
20828
20895
|
if (capabilityContext) {
|
|
20829
20896
|
preloadedData.capabilitySlug = capabilityContext.slug;
|
|
@@ -23032,8 +23099,10 @@ ${CI_HELP}`);
|
|
|
23032
23099
|
`);
|
|
23033
23100
|
const buildOnly = dispatch2.implementation === "preview-build";
|
|
23034
23101
|
if (args.skipInstall || buildOnly) {
|
|
23035
|
-
process.stdout.write(
|
|
23036
|
-
|
|
23102
|
+
process.stdout.write(
|
|
23103
|
+
`\u2192 kody: skipping dep install (${buildOnly ? "build-only implementation" : "--skip-install"})
|
|
23104
|
+
`
|
|
23105
|
+
);
|
|
23037
23106
|
} else {
|
|
23038
23107
|
const code = installDeps(pm, cwd);
|
|
23039
23108
|
if (code !== 0) {
|
|
@@ -26206,7 +26275,8 @@ Usage:
|
|
|
26206
26275
|
kody-engine release --issue <N> [--cwd <path>] [--verbose|--quiet]
|
|
26207
26276
|
kody-engine init [--cwd <path>] [--verbose|--quiet]
|
|
26208
26277
|
kody-engine <action> [--cwd <path>] [--verbose|--quiet]
|
|
26209
|
-
kody-engine
|
|
26278
|
+
kody-engine exec <name> [--cwd <path>] [--verbose|--quiet]
|
|
26279
|
+
kody-engine implementation <name> [--cwd <path>] [--verbose|--quiet]
|
|
26210
26280
|
kody-engine ci [preflight flags \u2014 see: kody-engine ci --help]
|
|
26211
26281
|
kody-engine chat [chat flags \u2014 see: kody-engine chat --help]
|
|
26212
26282
|
kody-engine stats [--since 7d|--run <id>|--json|--cwd <path>]
|
|
@@ -26214,7 +26284,7 @@ Usage:
|
|
|
26214
26284
|
kody-engine version
|
|
26215
26285
|
|
|
26216
26286
|
Top-level work commands are capabilities. A capability owns the public command name
|
|
26217
|
-
and resolves the implementation that runs it. Use the
|
|
26287
|
+
and resolves the implementation that runs it. Use the exec command only for
|
|
26218
26288
|
internal implementation profiles and scheduled helpers.
|
|
26219
26289
|
|
|
26220
26290
|
Exit codes:
|
|
@@ -26250,10 +26320,10 @@ function parseArgs(argv) {
|
|
|
26250
26320
|
if (cmd === "stats") {
|
|
26251
26321
|
return { ...result, command: "stats", statsArgv: argv.slice(1) };
|
|
26252
26322
|
}
|
|
26253
|
-
if (cmd === "implementation") {
|
|
26323
|
+
if (cmd === "implementation" || cmd === "exec") {
|
|
26254
26324
|
const implementationName = argv[1];
|
|
26255
26325
|
if (!implementationName || implementationName.startsWith("-")) {
|
|
26256
|
-
result.errors.push(
|
|
26326
|
+
result.errors.push(`${cmd} requires a name`);
|
|
26257
26327
|
return result;
|
|
26258
26328
|
}
|
|
26259
26329
|
if (!resolveImplementation(implementationName)) {
|
|
@@ -26288,7 +26358,7 @@ function parseArgs(argv) {
|
|
|
26288
26358
|
return result;
|
|
26289
26359
|
}
|
|
26290
26360
|
const discoveredActions = listCapabilityActions().map((e) => e.action);
|
|
26291
|
-
const available = ["ci", "chat", "stats", "implementation", "help", "version", ...discoveredActions];
|
|
26361
|
+
const available = ["ci", "chat", "stats", "exec", "implementation", "help", "version", ...discoveredActions];
|
|
26292
26362
|
result.errors.push(`unknown command: ${cmd} (available: ${available.join(", ")})`);
|
|
26293
26363
|
return result;
|
|
26294
26364
|
}
|