@kody-ade/kody-engine 0.4.607 → 0.4.611
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/README.md +1 -1
- package/dist/bin/kody.js +304 -220
- package/dist/capabilities/live-agent/capability.md +9 -0
- package/dist/capabilities/live-agent/definition.json +32 -0
- package/dist/implementations/live-agent/profile.json +30 -0
- package/dist/implementations/live-agent/prompt.md +38 -0
- package/dist/runtime-services/goal-scheduler/scheduler.sh +0 -0
- package/package.json +27 -26
- package/templates/kody.yml +0 -2
package/README.md
CHANGED
|
@@ -113,7 +113,7 @@ model key at runtime; user secrets are not copied into Actions. `KODY_TOKEN`
|
|
|
113
113
|
remains an optional GitHub authentication fallback when Kody must trigger
|
|
114
114
|
downstream workflows or modify `.github/workflows/*`.
|
|
115
115
|
|
|
116
|
-
The consumer workflow listens on `issue_comment` for `@kody ...` dispatch and `workflow_dispatch` for manual runs
|
|
116
|
+
The consumer workflow listens on `issue_comment` for `@kody ...` dispatch and `workflow_dispatch` for manual runs and chat mode. Convex owns scheduled Loop wakeups.
|
|
117
117
|
|
|
118
118
|
## Commands
|
|
119
119
|
|
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.611",
|
|
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",
|
|
@@ -3158,6 +3158,22 @@ function createStateBackendFromEnv(env = process.env, client) {
|
|
|
3158
3158
|
});
|
|
3159
3159
|
return Array.isArray(result) ? result : [];
|
|
3160
3160
|
},
|
|
3161
|
+
async replaceLoopWakeRegistrations(tenantId2, loops, updatedAt) {
|
|
3162
|
+
await transport.mutation(anyApi.loopWakes.replaceRegistrations, {
|
|
3163
|
+
tenantId: requireTenant(tenantId2),
|
|
3164
|
+
loops,
|
|
3165
|
+
updatedAt: requireNonEmpty(updatedAt, "updatedAt")
|
|
3166
|
+
});
|
|
3167
|
+
},
|
|
3168
|
+
async markLoopWakeExecution(tenantId2, wakeId, status, detail, updatedAt) {
|
|
3169
|
+
await transport.mutation(anyApi.loopWakes.markExecution, {
|
|
3170
|
+
tenantId: requireTenant(tenantId2),
|
|
3171
|
+
wakeId: requireNonEmpty(wakeId, "wakeId"),
|
|
3172
|
+
status,
|
|
3173
|
+
detail,
|
|
3174
|
+
updatedAt: requireNonEmpty(updatedAt, "updatedAt")
|
|
3175
|
+
});
|
|
3176
|
+
},
|
|
3161
3177
|
async get(tenantId2, taskKey, kind) {
|
|
3162
3178
|
const result = await transport.query(anyApi.taskState.get, {
|
|
3163
3179
|
tenantId: requireTenant(tenantId2),
|
|
@@ -3176,6 +3192,26 @@ function createStateBackendFromEnv(env = process.env, client) {
|
|
|
3176
3192
|
...expectedUpdatedAt ? { expectedUpdatedAt } : {}
|
|
3177
3193
|
});
|
|
3178
3194
|
},
|
|
3195
|
+
async getAgentState(tenantId2, agent) {
|
|
3196
|
+
const result = await transport.query(anyApi.agentStates.get, {
|
|
3197
|
+
tenantId: requireTenant(tenantId2),
|
|
3198
|
+
agent: requireNonEmpty(agent, "agent")
|
|
3199
|
+
});
|
|
3200
|
+
return result ?? null;
|
|
3201
|
+
},
|
|
3202
|
+
async saveAgentState(tenantId2, state, expectedRevision) {
|
|
3203
|
+
await transport.mutation(anyApi.agentStates.save, {
|
|
3204
|
+
tenantId: requireTenant(tenantId2),
|
|
3205
|
+
state,
|
|
3206
|
+
...expectedRevision === void 0 ? {} : { expectedRevision }
|
|
3207
|
+
});
|
|
3208
|
+
},
|
|
3209
|
+
async resetAgentState(tenantId2, agent) {
|
|
3210
|
+
await transport.mutation(anyApi.agentStates.reset, {
|
|
3211
|
+
tenantId: requireTenant(tenantId2),
|
|
3212
|
+
agent: requireNonEmpty(agent, "agent")
|
|
3213
|
+
});
|
|
3214
|
+
},
|
|
3179
3215
|
async getRepoDoc(tenantId2, kind) {
|
|
3180
3216
|
const result = await transport.query(anyApi.repoDocs.get, {
|
|
3181
3217
|
tenantId: requireTenant(tenantId2),
|
|
@@ -14457,7 +14493,7 @@ function assertLoopDispatchesSucceeded(results) {
|
|
|
14457
14493
|
async function dispatchLoopsWith(input) {
|
|
14458
14494
|
const results = [];
|
|
14459
14495
|
for (const loop of input.loops) {
|
|
14460
|
-
const slot = loopDispatchSlot(loop, input.now, input.force, input.nonce());
|
|
14496
|
+
const slot = input.scheduledFor ?? loopDispatchSlot(loop, input.now, input.force, input.nonce());
|
|
14461
14497
|
if (!slot) continue;
|
|
14462
14498
|
const reservationId = `reservation-${input.nonce()}`;
|
|
14463
14499
|
const idempotencyKey = `${loop.id}:${slot}`;
|
|
@@ -14466,7 +14502,7 @@ async function dispatchLoopsWith(input) {
|
|
|
14466
14502
|
loopId: loop.id,
|
|
14467
14503
|
decision: {
|
|
14468
14504
|
kind: "fire",
|
|
14469
|
-
reason: input.force ? "manual Loop run requested" : "local Loop schedule is due",
|
|
14505
|
+
reason: input.scheduledFor ? "Convex scheduled Loop run" : input.force ? "manual Loop run requested" : "local Loop schedule is due",
|
|
14470
14506
|
scheduledAt: slot
|
|
14471
14507
|
},
|
|
14472
14508
|
leaseUntil: new Date(input.now.getTime() + LOOP_DISPATCH_LEASE_MS).toISOString(),
|
|
@@ -14586,6 +14622,19 @@ function mergeLoopDefinitions(repositoryLoops, runtimeLoops) {
|
|
|
14586
14622
|
}
|
|
14587
14623
|
return [...byId.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
14588
14624
|
}
|
|
14625
|
+
async function syncLoopWakeRegistrations(backend, tenantId2, loops, updatedAt, log2) {
|
|
14626
|
+
try {
|
|
14627
|
+
await backend.replaceLoopWakeRegistrations(
|
|
14628
|
+
tenantId2,
|
|
14629
|
+
loops.filter((loop) => loop.enabled && loop.trigger.type === "schedule"),
|
|
14630
|
+
updatedAt
|
|
14631
|
+
);
|
|
14632
|
+
return true;
|
|
14633
|
+
} catch {
|
|
14634
|
+
log2("\u2192 kody: Convex Loop wake registration backfill skipped; existing Loop execution continues");
|
|
14635
|
+
return false;
|
|
14636
|
+
}
|
|
14637
|
+
}
|
|
14589
14638
|
function loopDispatchSlot(loop, now, force, nonce) {
|
|
14590
14639
|
return force ? `manual:${now.toISOString()}:${nonce}` : dueSlot(loop, now);
|
|
14591
14640
|
}
|
|
@@ -14643,12 +14692,25 @@ var init_dispatchLoops = __esm({
|
|
|
14643
14692
|
const tenantId2 = repositoryTenant(ctx.config);
|
|
14644
14693
|
if (!tenantId2) throw new Error("Repository identity is required for Loop dispatch");
|
|
14645
14694
|
const now = /* @__PURE__ */ new Date();
|
|
14646
|
-
const
|
|
14695
|
+
const scheduledFor = typeof ctx.data.scheduledFor === "string" ? ctx.data.scheduledFor.trim() : "";
|
|
14696
|
+
const force = ctx.data.jobForce === true && !scheduledFor;
|
|
14647
14697
|
const requestedLoopId = typeof ctx.args.loop === "string" ? ctx.args.loop.trim() : "";
|
|
14648
14698
|
const backend = createStateBackendFromEnv();
|
|
14699
|
+
const wakeId = typeof ctx.data.wakeId === "string" ? ctx.data.wakeId : "";
|
|
14700
|
+
if (wakeId) {
|
|
14701
|
+
await backend.markLoopWakeExecution(tenantId2, wakeId, "running", "Engine started Loop", now.toISOString());
|
|
14702
|
+
}
|
|
14649
14703
|
const loops = mergeLoopDefinitions(listLoopDefinitions(ctx.cwd), await backend.listLoops(tenantId2));
|
|
14704
|
+
await syncLoopWakeRegistrations(
|
|
14705
|
+
backend,
|
|
14706
|
+
tenantId2,
|
|
14707
|
+
loops,
|
|
14708
|
+
now.toISOString(),
|
|
14709
|
+
(message) => process.stderr.write(`${message}
|
|
14710
|
+
`)
|
|
14711
|
+
);
|
|
14650
14712
|
const due = selectRunnableLoops(loops, now, {
|
|
14651
|
-
force,
|
|
14713
|
+
force: force || Boolean(scheduledFor),
|
|
14652
14714
|
...requestedLoopId ? { loopId: requestedLoopId } : {}
|
|
14653
14715
|
});
|
|
14654
14716
|
process.stdout.write(`\u2192 kody: Loop scheduler found ${due.length} runnable Loop(s)${force ? " (manual)" : ""}
|
|
@@ -14659,6 +14721,7 @@ var init_dispatchLoops = __esm({
|
|
|
14659
14721
|
backend,
|
|
14660
14722
|
now,
|
|
14661
14723
|
force,
|
|
14724
|
+
scheduledFor: scheduledFor || void 0,
|
|
14662
14725
|
nonce: randomUUID,
|
|
14663
14726
|
run: (job, parentRunId, loopId) => runJob(job, {
|
|
14664
14727
|
cwd: ctx.cwd,
|
|
@@ -14674,6 +14737,16 @@ var init_dispatchLoops = __esm({
|
|
|
14674
14737
|
`);
|
|
14675
14738
|
}
|
|
14676
14739
|
ctx.data.loopDispatchResults = results;
|
|
14740
|
+
if (wakeId) {
|
|
14741
|
+
const failed = results.find((result) => result.status === "failed" || result.status === "blocked");
|
|
14742
|
+
await backend.markLoopWakeExecution(
|
|
14743
|
+
tenantId2,
|
|
14744
|
+
wakeId,
|
|
14745
|
+
failed ? "failed" : "succeeded",
|
|
14746
|
+
failed?.reason ?? "Loop completed",
|
|
14747
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
14748
|
+
);
|
|
14749
|
+
}
|
|
14677
14750
|
assertLoopDispatchesSucceeded(results);
|
|
14678
14751
|
};
|
|
14679
14752
|
}
|
|
@@ -16442,14 +16515,105 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
16442
16515
|
}
|
|
16443
16516
|
});
|
|
16444
16517
|
|
|
16445
|
-
// src/scripts/
|
|
16518
|
+
// src/scripts/loadLiveAgent.ts
|
|
16446
16519
|
import * as fs43 from "fs";
|
|
16520
|
+
function tenant(config) {
|
|
16521
|
+
const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY ?? "").split("/");
|
|
16522
|
+
const owner = config.github?.owner?.trim() || envOwner;
|
|
16523
|
+
const repo = config.github?.repo?.trim() || envRepo;
|
|
16524
|
+
if (!owner || !repo) throw new Error("Repository identity is required for live Agent execution");
|
|
16525
|
+
return `${owner}/${repo}`;
|
|
16526
|
+
}
|
|
16527
|
+
function frontmatter(raw) {
|
|
16528
|
+
const match = /^---\n([\s\S]*?)\n---/.exec(raw);
|
|
16529
|
+
if (!match) return {};
|
|
16530
|
+
const result = {};
|
|
16531
|
+
for (const line of match[1].split("\n")) {
|
|
16532
|
+
const at = line.indexOf(":");
|
|
16533
|
+
if (at < 0) continue;
|
|
16534
|
+
const key = line.slice(0, at).trim();
|
|
16535
|
+
const value = line.slice(at + 1).trim();
|
|
16536
|
+
result[key] = value.startsWith("[") ? value.slice(1, -1).split(",").map((entry) => entry.trim()).filter(Boolean) : value;
|
|
16537
|
+
}
|
|
16538
|
+
return result;
|
|
16539
|
+
}
|
|
16540
|
+
function guidanceBody(row, agent) {
|
|
16541
|
+
if (typeof row.doc?.body !== "string") return null;
|
|
16542
|
+
const metadata = frontmatter(row.doc.body);
|
|
16543
|
+
const audience = Array.isArray(metadata.agent) ? metadata.agent : [metadata.agent ?? "*"];
|
|
16544
|
+
if (!audience.includes("*") && !audience.includes(agent)) return null;
|
|
16545
|
+
return row.doc.body.replace(/^---\n[\s\S]*?\n---\n?/, "").trim();
|
|
16546
|
+
}
|
|
16547
|
+
function intentBody(row) {
|
|
16548
|
+
if (typeof row.doc?.body !== "string") return null;
|
|
16549
|
+
return row.doc.body.replace(/^---\n[\s\S]*?\n---\n?/, "").trim() || null;
|
|
16550
|
+
}
|
|
16551
|
+
var loadLiveAgent;
|
|
16552
|
+
var init_loadLiveAgent = __esm({
|
|
16553
|
+
"src/scripts/loadLiveAgent.ts"() {
|
|
16554
|
+
"use strict";
|
|
16555
|
+
init_definition_paths();
|
|
16556
|
+
init_agents();
|
|
16557
|
+
init_state_backend();
|
|
16558
|
+
loadLiveAgent = async (ctx, profile) => {
|
|
16559
|
+
const agent = String(ctx.args.agent ?? ctx.data.jobAgent ?? "").trim();
|
|
16560
|
+
if (!agent) throw new Error("loadLiveAgent: agent is required");
|
|
16561
|
+
const file = resolveAgentFile2(ctx.cwd, agent, agentsRoot(ctx.cwd));
|
|
16562
|
+
const raw = fs43.existsSync(file) ? fs43.readFileSync(file, "utf8") : "";
|
|
16563
|
+
const metadata = frontmatter(raw);
|
|
16564
|
+
const assignedIntent = typeof metadata.primaryIntent === "string" ? metadata.primaryIntent : "";
|
|
16565
|
+
const requestedIntent = String(ctx.args.intent ?? "").trim();
|
|
16566
|
+
const intent = requestedIntent || assignedIntent;
|
|
16567
|
+
if (!intent || requestedIntent && assignedIntent !== requestedIntent) {
|
|
16568
|
+
throw new Error(`Live Agent '${agent}' does not have the requested primary Intent`);
|
|
16569
|
+
}
|
|
16570
|
+
const backend = createStateBackendFromEnv();
|
|
16571
|
+
const tenantId2 = tenant(ctx.config);
|
|
16572
|
+
const [stateRow, intentRow, policies, constraints, context] = await Promise.all([
|
|
16573
|
+
backend.getAgentState(tenantId2, agent),
|
|
16574
|
+
backend.getRepoDoc(tenantId2, `intent:${intent}`),
|
|
16575
|
+
backend.listRepoDocs(tenantId2, "policy:"),
|
|
16576
|
+
backend.listRepoDocs(tenantId2, "constraint:"),
|
|
16577
|
+
backend.listRepoDocs(tenantId2, "context:")
|
|
16578
|
+
]);
|
|
16579
|
+
if (!stateRow) throw new Error(`Live Agent '${agent}' has no AgentState`);
|
|
16580
|
+
const state = stateRow.state;
|
|
16581
|
+
const selectedIntentBody = intentRow ? intentBody(intentRow) : null;
|
|
16582
|
+
if (!selectedIntentBody) throw new Error(`Primary Intent '${intent}' is missing`);
|
|
16583
|
+
const render = (rows) => rows.map((row) => guidanceBody(row, agent)).filter(Boolean).join("\n\n") || "None assigned.";
|
|
16584
|
+
ctx.data.agentIdentity = loadAgentIdentity(ctx.cwd, agent);
|
|
16585
|
+
ctx.data.liveAgentIntent = selectedIntentBody;
|
|
16586
|
+
ctx.data.liveAgentPolicies = render(policies);
|
|
16587
|
+
ctx.data.liveAgentConstraints = render(constraints);
|
|
16588
|
+
ctx.data.liveAgentContext = render(context);
|
|
16589
|
+
ctx.data.liveAgentCapabilities = Array.isArray(metadata.capabilities) ? metadata.capabilities.map((slug) => `- ${slug}`).join("\n") : "None assigned.";
|
|
16590
|
+
ctx.data.liveAgentSlug = agent;
|
|
16591
|
+
ctx.data.liveAgentPreviousRevision = Number(state.revision ?? 0);
|
|
16592
|
+
ctx.data.jobState = {
|
|
16593
|
+
state: {
|
|
16594
|
+
version: 1,
|
|
16595
|
+
rev: Number(state.revision ?? 0),
|
|
16596
|
+
cursor: String(state.cursor ?? "idle"),
|
|
16597
|
+
data: state.data ?? {},
|
|
16598
|
+
done: false
|
|
16599
|
+
}
|
|
16600
|
+
};
|
|
16601
|
+
ctx.data.jobStateJson = JSON.stringify(state, null, 2);
|
|
16602
|
+
ctx.data.capabilityTools = ["start_capability"];
|
|
16603
|
+
ctx.data.capabilityToolMode = "lock";
|
|
16604
|
+
profile.claudeCode.enableSubmitTool = true;
|
|
16605
|
+
};
|
|
16606
|
+
}
|
|
16607
|
+
});
|
|
16608
|
+
|
|
16609
|
+
// src/scripts/kodyVariables.ts
|
|
16610
|
+
import * as fs44 from "fs";
|
|
16447
16611
|
import * as path41 from "path";
|
|
16448
16612
|
function readKodyVariables(cwd) {
|
|
16449
16613
|
const full = path41.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
16450
16614
|
let raw;
|
|
16451
16615
|
try {
|
|
16452
|
-
raw =
|
|
16616
|
+
raw = fs44.readFileSync(full, "utf-8");
|
|
16453
16617
|
} catch {
|
|
16454
16618
|
return {};
|
|
16455
16619
|
}
|
|
@@ -16474,7 +16638,7 @@ var init_kodyVariables = __esm({
|
|
|
16474
16638
|
});
|
|
16475
16639
|
|
|
16476
16640
|
// src/scripts/loadQaContext.ts
|
|
16477
|
-
import * as
|
|
16641
|
+
import * as fs45 from "fs";
|
|
16478
16642
|
import * as path42 from "path";
|
|
16479
16643
|
function parseSlugList(value) {
|
|
16480
16644
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
@@ -16505,17 +16669,17 @@ function readProfileAgents(raw) {
|
|
|
16505
16669
|
}
|
|
16506
16670
|
function readProfile(cwd) {
|
|
16507
16671
|
const dir = path42.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
16508
|
-
if (!
|
|
16672
|
+
if (!fs45.existsSync(dir)) return "";
|
|
16509
16673
|
let entries;
|
|
16510
16674
|
try {
|
|
16511
|
-
entries =
|
|
16675
|
+
entries = fs45.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
16512
16676
|
} catch {
|
|
16513
16677
|
return "";
|
|
16514
16678
|
}
|
|
16515
16679
|
const blocks = [];
|
|
16516
16680
|
for (const file of entries) {
|
|
16517
16681
|
try {
|
|
16518
|
-
const raw =
|
|
16682
|
+
const raw = fs45.readFileSync(path42.join(dir, file), "utf-8");
|
|
16519
16683
|
const { agent, body } = readProfileAgents(raw);
|
|
16520
16684
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
16521
16685
|
blocks.push(`## ${file}
|
|
@@ -16565,7 +16729,7 @@ var init_loadQaContext = __esm({
|
|
|
16565
16729
|
|
|
16566
16730
|
// src/scripts/loadSimpleCapability.ts
|
|
16567
16731
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16568
|
-
import * as
|
|
16732
|
+
import * as fs46 from "fs";
|
|
16569
16733
|
import * as os6 from "os";
|
|
16570
16734
|
import * as path43 from "path";
|
|
16571
16735
|
function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
@@ -16580,7 +16744,7 @@ function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
|
16580
16744
|
profile.subagentTemplates = {
|
|
16581
16745
|
...profile.subagentTemplates ?? {},
|
|
16582
16746
|
...Object.fromEntries(
|
|
16583
|
-
subagentFiles.map(({ name, file }) => [name,
|
|
16747
|
+
subagentFiles.map(({ name, file }) => [name, fs46.readFileSync(path43.join(toolRoot, file), "utf-8")])
|
|
16584
16748
|
)
|
|
16585
16749
|
};
|
|
16586
16750
|
if (!profile.claudeCode.tools.includes("Agent")) {
|
|
@@ -16621,10 +16785,10 @@ function scalar(value) {
|
|
|
16621
16785
|
return value;
|
|
16622
16786
|
}
|
|
16623
16787
|
function listFiles(root) {
|
|
16624
|
-
if (!
|
|
16788
|
+
if (!fs46.existsSync(root)) return [];
|
|
16625
16789
|
const files = [];
|
|
16626
16790
|
const visit = (dir) => {
|
|
16627
|
-
for (const entry of
|
|
16791
|
+
for (const entry of fs46.readdirSync(dir, { withFileTypes: true })) {
|
|
16628
16792
|
const absolute = path43.join(dir, entry.name);
|
|
16629
16793
|
if (entry.isSymbolicLink()) continue;
|
|
16630
16794
|
if (entry.isDirectory()) visit(absolute);
|
|
@@ -16716,7 +16880,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16716
16880
|
...skillFiles.flatMap((file) => [
|
|
16717
16881
|
`### ${file}`,
|
|
16718
16882
|
"",
|
|
16719
|
-
|
|
16883
|
+
fs46.readFileSync(path43.join(skillRoot, file), "utf-8"),
|
|
16720
16884
|
""
|
|
16721
16885
|
])
|
|
16722
16886
|
] : [],
|
|
@@ -16756,7 +16920,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16756
16920
|
});
|
|
16757
16921
|
|
|
16758
16922
|
// src/taskContext.ts
|
|
16759
|
-
import * as
|
|
16923
|
+
import * as fs47 from "fs";
|
|
16760
16924
|
import * as path44 from "path";
|
|
16761
16925
|
function buildTaskContext(args) {
|
|
16762
16926
|
return {
|
|
@@ -16773,9 +16937,9 @@ function buildTaskContext(args) {
|
|
|
16773
16937
|
function persistTaskContext(cwd, ctx) {
|
|
16774
16938
|
try {
|
|
16775
16939
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
16776
|
-
|
|
16940
|
+
fs47.mkdirSync(dir, { recursive: true });
|
|
16777
16941
|
const file = path44.join(dir, "task-context.json");
|
|
16778
|
-
|
|
16942
|
+
fs47.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
16779
16943
|
`);
|
|
16780
16944
|
return file;
|
|
16781
16945
|
} catch (err) {
|
|
@@ -17696,7 +17860,7 @@ var init_parseReproOutput = __esm({
|
|
|
17696
17860
|
});
|
|
17697
17861
|
|
|
17698
17862
|
// src/scripts/parseSimpleCapabilityOutput.ts
|
|
17699
|
-
import * as
|
|
17863
|
+
import * as fs48 from "fs";
|
|
17700
17864
|
function acceptAuthoritativeCapabilityOutput(ctx, profile, output) {
|
|
17701
17865
|
ctx.data.agentDone = true;
|
|
17702
17866
|
delete ctx.data.agentFailureReason;
|
|
@@ -17713,11 +17877,11 @@ function stringList2(value) {
|
|
|
17713
17877
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
17714
17878
|
}
|
|
17715
17879
|
function readOutputFile(outputPath) {
|
|
17716
|
-
if (!outputPath || !
|
|
17880
|
+
if (!outputPath || !fs48.existsSync(outputPath)) return { found: false };
|
|
17717
17881
|
try {
|
|
17718
|
-
return { found: true, value: JSON.parse(
|
|
17882
|
+
return { found: true, value: JSON.parse(fs48.readFileSync(outputPath, "utf-8")) };
|
|
17719
17883
|
} finally {
|
|
17720
|
-
|
|
17884
|
+
fs48.rmSync(outputPath, { force: true });
|
|
17721
17885
|
}
|
|
17722
17886
|
}
|
|
17723
17887
|
function parseOutput(text2) {
|
|
@@ -18339,7 +18503,7 @@ var init_postResearchComment = __esm({
|
|
|
18339
18503
|
});
|
|
18340
18504
|
|
|
18341
18505
|
// src/scripts/prepareBrowserAuth.ts
|
|
18342
|
-
import * as
|
|
18506
|
+
import * as fs49 from "fs";
|
|
18343
18507
|
import * as os7 from "os";
|
|
18344
18508
|
import * as path45 from "path";
|
|
18345
18509
|
function appendAuthMessage(ctx, message) {
|
|
@@ -18385,8 +18549,8 @@ async function githubJson(url, token, checkName) {
|
|
|
18385
18549
|
throw new Error(`GitHub ${checkName} check failed`);
|
|
18386
18550
|
}
|
|
18387
18551
|
function writeKodyStorageState(input) {
|
|
18388
|
-
const directory =
|
|
18389
|
-
|
|
18552
|
+
const directory = fs49.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
18553
|
+
fs49.chmodSync(directory, 448);
|
|
18390
18554
|
const file = path45.join(directory, "storage-state.json");
|
|
18391
18555
|
const now = Date.now();
|
|
18392
18556
|
const repoEntry = {
|
|
@@ -18418,7 +18582,7 @@ function writeKodyStorageState(input) {
|
|
|
18418
18582
|
}
|
|
18419
18583
|
]
|
|
18420
18584
|
};
|
|
18421
|
-
|
|
18585
|
+
fs49.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
18422
18586
|
return { directory, file, auth };
|
|
18423
18587
|
}
|
|
18424
18588
|
function parseSetCookie(value, hostname) {
|
|
@@ -18448,10 +18612,10 @@ function parseSetCookie(value, hostname) {
|
|
|
18448
18612
|
}
|
|
18449
18613
|
function writeCookieStorageState(targetUrl, setCookies) {
|
|
18450
18614
|
const target = new URL(targetUrl);
|
|
18451
|
-
const directory =
|
|
18452
|
-
|
|
18615
|
+
const directory = fs49.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
18616
|
+
fs49.chmodSync(directory, 448);
|
|
18453
18617
|
const file = path45.join(directory, "storage-state.json");
|
|
18454
|
-
|
|
18618
|
+
fs49.writeFileSync(
|
|
18455
18619
|
file,
|
|
18456
18620
|
JSON.stringify({
|
|
18457
18621
|
cookies: setCookies.map((cookie) => parseSetCookie(cookie, target.hostname)),
|
|
@@ -18472,9 +18636,9 @@ function currentStorageStatePath(args) {
|
|
|
18472
18636
|
function browserSessionCookieHeader(profile, targetUrl) {
|
|
18473
18637
|
const playwright = profile.claudeCode.mcpServers.find((server) => server.name === "playwright");
|
|
18474
18638
|
const storagePath = currentStorageStatePath(playwright?.args ?? []);
|
|
18475
|
-
if (!storagePath || !
|
|
18639
|
+
if (!storagePath || !fs49.existsSync(storagePath)) return void 0;
|
|
18476
18640
|
const hostname = new URL(targetUrl).hostname;
|
|
18477
|
-
const state = JSON.parse(
|
|
18641
|
+
const state = JSON.parse(fs49.readFileSync(storagePath, "utf-8"));
|
|
18478
18642
|
const cookies = (state.cookies ?? []).filter((cookie) => {
|
|
18479
18643
|
const domain = cookie.domain.replace(/^\./, "");
|
|
18480
18644
|
return hostname === domain || hostname.endsWith(`.${domain}`);
|
|
@@ -18541,9 +18705,9 @@ async function prepareAccountModelSettings(ctx, profile, input) {
|
|
|
18541
18705
|
return true;
|
|
18542
18706
|
}
|
|
18543
18707
|
function mergeStorageStates(existingPath, nextPath) {
|
|
18544
|
-
if (existingPath === nextPath || !
|
|
18545
|
-
const existing = JSON.parse(
|
|
18546
|
-
const next = JSON.parse(
|
|
18708
|
+
if (existingPath === nextPath || !fs49.existsSync(existingPath)) return;
|
|
18709
|
+
const existing = JSON.parse(fs49.readFileSync(existingPath, "utf-8"));
|
|
18710
|
+
const next = JSON.parse(fs49.readFileSync(nextPath, "utf-8"));
|
|
18547
18711
|
const cookies = /* @__PURE__ */ new Map();
|
|
18548
18712
|
for (const cookie of [...existing.cookies ?? [], ...next.cookies ?? []]) {
|
|
18549
18713
|
cookies.set(`${cookie.name}\0${cookie.domain}\0${cookie.path}`, cookie);
|
|
@@ -18557,7 +18721,7 @@ function mergeStorageStates(existingPath, nextPath) {
|
|
|
18557
18721
|
}
|
|
18558
18722
|
origins.set(entry.origin, { origin: entry.origin, localStorage: [...localStorage.values()] });
|
|
18559
18723
|
}
|
|
18560
|
-
|
|
18724
|
+
fs49.writeFileSync(
|
|
18561
18725
|
nextPath,
|
|
18562
18726
|
JSON.stringify({ cookies: [...cookies.values()], origins: [...origins.values()] }),
|
|
18563
18727
|
{ mode: 384 }
|
|
@@ -18654,7 +18818,7 @@ async function prepareKodyRepositoryBrowserAuth(ctx, profile, input) {
|
|
|
18654
18818
|
configurePlaywright(profile, state.file);
|
|
18655
18819
|
const authDirectory = state.directory;
|
|
18656
18820
|
registerRuntimeCleanup(ctx, () => {
|
|
18657
|
-
|
|
18821
|
+
fs49.rmSync(authDirectory, { recursive: true, force: true });
|
|
18658
18822
|
});
|
|
18659
18823
|
appendAuthMessage(
|
|
18660
18824
|
ctx,
|
|
@@ -18662,7 +18826,7 @@ async function prepareKodyRepositoryBrowserAuth(ctx, profile, input) {
|
|
|
18662
18826
|
);
|
|
18663
18827
|
return true;
|
|
18664
18828
|
} catch (error) {
|
|
18665
|
-
if (state)
|
|
18829
|
+
if (state) fs49.rmSync(state.directory, { recursive: true, force: true });
|
|
18666
18830
|
const reason = error instanceof Error ? error.message : String(error);
|
|
18667
18831
|
appendAuthMessage(
|
|
18668
18832
|
ctx,
|
|
@@ -18689,11 +18853,11 @@ async function prepareEmailPasswordBrowserAuth(ctx, profile, input) {
|
|
|
18689
18853
|
state = writeCookieStorageState(input.targetUrl, cookies);
|
|
18690
18854
|
configurePlaywright(profile, state.file);
|
|
18691
18855
|
const authDirectory = state.directory;
|
|
18692
|
-
registerRuntimeCleanup(ctx, () =>
|
|
18856
|
+
registerRuntimeCleanup(ctx, () => fs49.rmSync(authDirectory, { recursive: true, force: true }));
|
|
18693
18857
|
ctx.data.qaAuthBlock = "Auth: the app is already signed in through an engine-provided browser session. The login credentials are not available to you; never request, reveal, or report them.";
|
|
18694
18858
|
return true;
|
|
18695
18859
|
} catch (error) {
|
|
18696
|
-
if (state)
|
|
18860
|
+
if (state) fs49.rmSync(state.directory, { recursive: true, force: true });
|
|
18697
18861
|
const reason = error instanceof Error ? error.message : String(error);
|
|
18698
18862
|
ctx.data.qaAuthBlock = `Auth: the engine could not prepare the app login (${reason}). Note this authenticated surface as a gap.`;
|
|
18699
18863
|
return false;
|
|
@@ -20607,7 +20771,7 @@ var init_tickShellRunner = __esm({
|
|
|
20607
20771
|
});
|
|
20608
20772
|
|
|
20609
20773
|
// src/scripts/runScheduledImplementationTick.ts
|
|
20610
|
-
import * as
|
|
20774
|
+
import * as fs50 from "fs";
|
|
20611
20775
|
import * as path48 from "path";
|
|
20612
20776
|
var runScheduledImplementationTick;
|
|
20613
20777
|
var init_runScheduledImplementationTick = __esm({
|
|
@@ -20636,7 +20800,7 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
20636
20800
|
return;
|
|
20637
20801
|
}
|
|
20638
20802
|
const shellPath = path48.join(profile.dir, shell);
|
|
20639
|
-
if (!
|
|
20803
|
+
if (!fs50.existsSync(shellPath)) {
|
|
20640
20804
|
ctx.output.exitCode = 99;
|
|
20641
20805
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
20642
20806
|
return;
|
|
@@ -20668,13 +20832,13 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
20668
20832
|
|
|
20669
20833
|
// src/scripts/runSimpleCapabilityScript.ts
|
|
20670
20834
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
20671
|
-
import * as
|
|
20835
|
+
import * as fs51 from "fs";
|
|
20672
20836
|
function formatDuration2(timeoutMs) {
|
|
20673
20837
|
return timeoutMs % 6e4 === 0 ? `${timeoutMs / 6e4} minutes` : `${timeoutMs}ms`;
|
|
20674
20838
|
}
|
|
20675
20839
|
function isRegularFile2(filePath) {
|
|
20676
20840
|
try {
|
|
20677
|
-
const stat =
|
|
20841
|
+
const stat = fs51.lstatSync(filePath);
|
|
20678
20842
|
return stat.isFile() && !stat.isSymbolicLink();
|
|
20679
20843
|
} catch {
|
|
20680
20844
|
return false;
|
|
@@ -20753,7 +20917,7 @@ var init_runSimpleCapabilityScript = __esm({
|
|
|
20753
20917
|
});
|
|
20754
20918
|
|
|
20755
20919
|
// src/scripts/runTickScript.ts
|
|
20756
|
-
import * as
|
|
20920
|
+
import * as fs52 from "fs";
|
|
20757
20921
|
import * as path49 from "path";
|
|
20758
20922
|
var runTickScript;
|
|
20759
20923
|
var init_runTickScript = __esm({
|
|
@@ -20787,7 +20951,7 @@ var init_runTickScript = __esm({
|
|
|
20787
20951
|
return;
|
|
20788
20952
|
}
|
|
20789
20953
|
const scriptPath = path49.isAbsolute(tickScript) ? tickScript : path49.join(ctx.cwd, tickScript);
|
|
20790
|
-
if (!
|
|
20954
|
+
if (!fs52.existsSync(scriptPath)) {
|
|
20791
20955
|
ctx.output.exitCode = 99;
|
|
20792
20956
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
20793
20957
|
return;
|
|
@@ -20835,6 +20999,41 @@ var init_saveManagedGoalState = __esm({
|
|
|
20835
20999
|
}
|
|
20836
21000
|
});
|
|
20837
21001
|
|
|
21002
|
+
// src/scripts/saveLiveAgentState.ts
|
|
21003
|
+
var saveLiveAgentState;
|
|
21004
|
+
var init_saveLiveAgentState = __esm({
|
|
21005
|
+
"src/scripts/saveLiveAgentState.ts"() {
|
|
21006
|
+
"use strict";
|
|
21007
|
+
init_state_backend();
|
|
21008
|
+
saveLiveAgentState = async (ctx, _profile, agentResult) => {
|
|
21009
|
+
const agent = String(ctx.data.liveAgentSlug ?? "");
|
|
21010
|
+
const previousRevision = Number(ctx.data.liveAgentPreviousRevision ?? 0);
|
|
21011
|
+
const next = ctx.data.nextJobState;
|
|
21012
|
+
if (!agent || !next || typeof next.cursor !== "string" || !next.cursor) {
|
|
21013
|
+
throw new Error(String(ctx.data.nextStateParseError ?? "Live Agent did not submit valid continuation state"));
|
|
21014
|
+
}
|
|
21015
|
+
const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY ?? "").split("/");
|
|
21016
|
+
const owner = ctx.config.github?.owner?.trim() || envOwner;
|
|
21017
|
+
const repo = ctx.config.github?.repo?.trim() || envRepo;
|
|
21018
|
+
if (!owner || !repo) throw new Error("Repository identity is required for live Agent state");
|
|
21019
|
+
const summary = (agentResult?.finalText ?? "").trim().slice(0, 1e3);
|
|
21020
|
+
await createStateBackendFromEnv().saveAgentState(
|
|
21021
|
+
`${owner}/${repo}`,
|
|
21022
|
+
{
|
|
21023
|
+
version: 1,
|
|
21024
|
+
agent,
|
|
21025
|
+
revision: previousRevision + 1,
|
|
21026
|
+
cursor: next.cursor,
|
|
21027
|
+
summary,
|
|
21028
|
+
data: next.data && typeof next.data === "object" ? next.data : {},
|
|
21029
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21030
|
+
},
|
|
21031
|
+
previousRevision
|
|
21032
|
+
);
|
|
21033
|
+
};
|
|
21034
|
+
}
|
|
21035
|
+
});
|
|
21036
|
+
|
|
20838
21037
|
// src/scripts/setCommentTarget.ts
|
|
20839
21038
|
var setCommentTarget;
|
|
20840
21039
|
var init_setCommentTarget = __esm({
|
|
@@ -21952,7 +22151,7 @@ var init_warmupMcp = __esm({
|
|
|
21952
22151
|
});
|
|
21953
22152
|
|
|
21954
22153
|
// src/scripts/writeAgentRunSummary.ts
|
|
21955
|
-
import * as
|
|
22154
|
+
import * as fs53 from "fs";
|
|
21956
22155
|
var writeAgentRunSummary;
|
|
21957
22156
|
var init_writeAgentRunSummary = __esm({
|
|
21958
22157
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -21978,7 +22177,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
21978
22177
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
21979
22178
|
lines.push("");
|
|
21980
22179
|
try {
|
|
21981
|
-
|
|
22180
|
+
fs53.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
21982
22181
|
`);
|
|
21983
22182
|
} catch {
|
|
21984
22183
|
}
|
|
@@ -22135,6 +22334,7 @@ var init_scripts = __esm({
|
|
|
22135
22334
|
init_loadIssueStateComment();
|
|
22136
22335
|
init_loadJobFromFile();
|
|
22137
22336
|
init_loadLinkedFinding();
|
|
22337
|
+
init_loadLiveAgent();
|
|
22138
22338
|
init_loadMemoryContext();
|
|
22139
22339
|
init_loadPriorArt();
|
|
22140
22340
|
init_loadQaContext();
|
|
@@ -22183,6 +22383,7 @@ var init_scripts = __esm({
|
|
|
22183
22383
|
init_runSimpleCapabilityScript();
|
|
22184
22384
|
init_runTickScript();
|
|
22185
22385
|
init_saveManagedGoalState();
|
|
22386
|
+
init_saveLiveAgentState();
|
|
22186
22387
|
init_saveTaskState();
|
|
22187
22388
|
init_setCommentTarget();
|
|
22188
22389
|
init_setLifecycleLabel();
|
|
@@ -22222,6 +22423,7 @@ var init_scripts = __esm({
|
|
|
22222
22423
|
loadConventions,
|
|
22223
22424
|
loadCoverageRules,
|
|
22224
22425
|
loadLinkedFinding,
|
|
22426
|
+
loadLiveAgent,
|
|
22225
22427
|
loadMemoryContext,
|
|
22226
22428
|
loadPriorArt,
|
|
22227
22429
|
loadQaContext,
|
|
@@ -22257,6 +22459,7 @@ var init_scripts = __esm({
|
|
|
22257
22459
|
saveManagedGoalState
|
|
22258
22460
|
};
|
|
22259
22461
|
postflightScripts = {
|
|
22462
|
+
saveLiveAgentState,
|
|
22260
22463
|
parseSimpleCapabilityOutput,
|
|
22261
22464
|
parseAgentResult: parseAgentResult2,
|
|
22262
22465
|
parseIssueStateFromAgentResult,
|
|
@@ -22316,7 +22519,7 @@ var init_scripts = __esm({
|
|
|
22316
22519
|
});
|
|
22317
22520
|
|
|
22318
22521
|
// src/stateWorkspace.ts
|
|
22319
|
-
import * as
|
|
22522
|
+
import * as fs54 from "fs";
|
|
22320
22523
|
import * as path51 from "path";
|
|
22321
22524
|
function tenantId(config) {
|
|
22322
22525
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
@@ -22325,8 +22528,8 @@ function tenantId(config) {
|
|
|
22325
22528
|
}
|
|
22326
22529
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
22327
22530
|
const target = path51.join(cwd, RUNTIME_ROOT, relativePath);
|
|
22328
|
-
|
|
22329
|
-
|
|
22531
|
+
fs54.mkdirSync(path51.dirname(target), { recursive: true });
|
|
22532
|
+
fs54.writeFileSync(target, content, "utf8");
|
|
22330
22533
|
}
|
|
22331
22534
|
function record(value) {
|
|
22332
22535
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -22347,8 +22550,8 @@ function memoryIndex(docs) {
|
|
|
22347
22550
|
if (lines.length === 0) return "";
|
|
22348
22551
|
return ["# Kody memory index", "", "One line per backend memory document.", "", ...lines, ""].join("\n");
|
|
22349
22552
|
}
|
|
22350
|
-
async function hydratePrefix(backend,
|
|
22351
|
-
const docs = await backend.listRepoDocs(
|
|
22553
|
+
async function hydratePrefix(backend, tenant2, cwd, prefix) {
|
|
22554
|
+
const docs = await backend.listRepoDocs(tenant2, prefix);
|
|
22352
22555
|
for (const doc of docs) {
|
|
22353
22556
|
const slug = doc.kind.slice(prefix.length);
|
|
22354
22557
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(slug)) continue;
|
|
@@ -22361,8 +22564,8 @@ async function hydratePrefix(backend, tenant, cwd, prefix) {
|
|
|
22361
22564
|
if (index) writeRuntimeFile(cwd, "memory/INDEX.md", index);
|
|
22362
22565
|
}
|
|
22363
22566
|
}
|
|
22364
|
-
async function hydrateSingleton(backend,
|
|
22365
|
-
const doc = await backend.getRepoDoc(
|
|
22567
|
+
async function hydrateSingleton(backend, tenant2, cwd, kind, relativePath) {
|
|
22568
|
+
const doc = await backend.getRepoDoc(tenant2, kind);
|
|
22366
22569
|
if (!doc) return;
|
|
22367
22570
|
const body = stringField6(doc.doc, "body");
|
|
22368
22571
|
if (body !== null) {
|
|
@@ -22372,8 +22575,8 @@ async function hydrateSingleton(backend, tenant, cwd, kind, relativePath) {
|
|
|
22372
22575
|
writeRuntimeFile(cwd, relativePath, `${JSON.stringify(doc.doc, null, 2)}
|
|
22373
22576
|
`);
|
|
22374
22577
|
}
|
|
22375
|
-
async function hydrateWorkflows(backend,
|
|
22376
|
-
for (const workflow of await backend.listWorkflows(
|
|
22578
|
+
async function hydrateWorkflows(backend, tenant2, cwd) {
|
|
22579
|
+
for (const workflow of await backend.listWorkflows(tenant2)) {
|
|
22377
22580
|
if (!/^[a-z0-9][a-z0-9_-]{0,79}$/.test(workflow.workflowId)) continue;
|
|
22378
22581
|
writeRuntimeFile(
|
|
22379
22582
|
cwd,
|
|
@@ -22384,25 +22587,25 @@ async function hydrateWorkflows(backend, tenant, cwd) {
|
|
|
22384
22587
|
}
|
|
22385
22588
|
}
|
|
22386
22589
|
async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
22387
|
-
const
|
|
22590
|
+
const tenant2 = tenantId(config);
|
|
22388
22591
|
const configured = hasStateBackendConfig();
|
|
22389
|
-
if (!
|
|
22592
|
+
if (!tenant2 || !configured) {
|
|
22390
22593
|
if (process.env.GITHUB_ACTIONS === "true")
|
|
22391
22594
|
throw new Error("Kody backend access is required for runtime workspace documents");
|
|
22392
22595
|
return;
|
|
22393
22596
|
}
|
|
22394
|
-
const key = `${path51.resolve(cwd)}|${
|
|
22597
|
+
const key = `${path51.resolve(cwd)}|${tenant2}`;
|
|
22395
22598
|
if (hydratedWorkspaces.has(key)) return;
|
|
22396
22599
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
22397
22600
|
const root = path51.join(cwd, RUNTIME_ROOT);
|
|
22398
|
-
|
|
22601
|
+
fs54.rmSync(root, { recursive: true, force: true });
|
|
22399
22602
|
await Promise.all([
|
|
22400
|
-
hydratePrefix(backend,
|
|
22401
|
-
hydratePrefix(backend,
|
|
22402
|
-
hydrateSingleton(backend,
|
|
22403
|
-
hydrateSingleton(backend,
|
|
22404
|
-
hydrateSingleton(backend,
|
|
22405
|
-
hydrateWorkflows(backend,
|
|
22603
|
+
hydratePrefix(backend, tenant2, cwd, "context:"),
|
|
22604
|
+
hydratePrefix(backend, tenant2, cwd, "memory:"),
|
|
22605
|
+
hydrateSingleton(backend, tenant2, cwd, "instructions", "instructions.md"),
|
|
22606
|
+
hydrateSingleton(backend, tenant2, cwd, "system-prompt", "system-prompt.md"),
|
|
22607
|
+
hydrateSingleton(backend, tenant2, cwd, "variables", "variables.json"),
|
|
22608
|
+
hydrateWorkflows(backend, tenant2, cwd)
|
|
22406
22609
|
]);
|
|
22407
22610
|
hydratedWorkspaces.add(key);
|
|
22408
22611
|
}
|
|
@@ -22482,7 +22685,7 @@ var init_tools = __esm({
|
|
|
22482
22685
|
|
|
22483
22686
|
// src/executor.ts
|
|
22484
22687
|
import { spawn as spawn8 } from "child_process";
|
|
22485
|
-
import * as
|
|
22688
|
+
import * as fs55 from "fs";
|
|
22486
22689
|
import * as os8 from "os";
|
|
22487
22690
|
import * as path52 from "path";
|
|
22488
22691
|
function isMutatingPostflight(scriptName) {
|
|
@@ -23269,7 +23472,7 @@ function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
|
23269
23472
|
// fallback
|
|
23270
23473
|
];
|
|
23271
23474
|
for (const c of candidates) {
|
|
23272
|
-
if (
|
|
23475
|
+
if (fs55.existsSync(c)) return c;
|
|
23273
23476
|
}
|
|
23274
23477
|
return candidates[0];
|
|
23275
23478
|
}
|
|
@@ -23385,7 +23588,7 @@ function resolveShellTimeoutMs(entry) {
|
|
|
23385
23588
|
async function runShellEntry(entry, ctx, profile) {
|
|
23386
23589
|
const shellName = entry.shell;
|
|
23387
23590
|
const shellPath = path52.join(profile.dir, shellName);
|
|
23388
|
-
if (!
|
|
23591
|
+
if (!fs55.existsSync(shellPath)) {
|
|
23389
23592
|
ctx.skipAgent = true;
|
|
23390
23593
|
ctx.output.exitCode = 99;
|
|
23391
23594
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
@@ -23459,9 +23662,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
23459
23662
|
}
|
|
23460
23663
|
let sideChannelText = "";
|
|
23461
23664
|
try {
|
|
23462
|
-
if (
|
|
23463
|
-
sideChannelText =
|
|
23464
|
-
|
|
23665
|
+
if (fs55.existsSync(outputFile)) {
|
|
23666
|
+
sideChannelText = fs55.readFileSync(outputFile, "utf-8");
|
|
23667
|
+
fs55.rmSync(outputFile, { force: true });
|
|
23465
23668
|
}
|
|
23466
23669
|
} catch {
|
|
23467
23670
|
}
|
|
@@ -26194,7 +26397,7 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
|
|
|
26194
26397
|
|
|
26195
26398
|
// src/kody-cli.ts
|
|
26196
26399
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
26197
|
-
import * as
|
|
26400
|
+
import * as fs56 from "fs";
|
|
26198
26401
|
import * as path53 from "path";
|
|
26199
26402
|
|
|
26200
26403
|
// src/app-auth.ts
|
|
@@ -26242,26 +26445,6 @@ async function ghApp(jwt, apiPath, method = "GET") {
|
|
|
26242
26445
|
}
|
|
26243
26446
|
return await res.json();
|
|
26244
26447
|
}
|
|
26245
|
-
async function ghAppPage(authToken, apiPath) {
|
|
26246
|
-
const res = await fetch(`${GH_API}${apiPath}`, {
|
|
26247
|
-
headers: {
|
|
26248
|
-
Authorization: `Bearer ${authToken}`,
|
|
26249
|
-
Accept: "application/vnd.github+json",
|
|
26250
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
26251
|
-
"User-Agent": "kody-engine"
|
|
26252
|
-
}
|
|
26253
|
-
});
|
|
26254
|
-
if (!res.ok) {
|
|
26255
|
-
const body = await res.text().catch(() => "");
|
|
26256
|
-
throw new Error(
|
|
26257
|
-
`GitHub App API GET ${apiPath} \u2192 ${res.status} ${res.statusText}${body ? `: ${body.slice(0, 200)}` : ""}`
|
|
26258
|
-
);
|
|
26259
|
-
}
|
|
26260
|
-
return {
|
|
26261
|
-
data: await res.json(),
|
|
26262
|
-
hasNext: /rel="next"/.test(res.headers.get("link") ?? "")
|
|
26263
|
-
};
|
|
26264
|
-
}
|
|
26265
26448
|
function readAppCreds(env = process.env) {
|
|
26266
26449
|
const appId = env.KODY_APP_ID?.trim();
|
|
26267
26450
|
const privateKey = env.KODY_APP_PRIVATE_KEY;
|
|
@@ -26286,36 +26469,6 @@ async function mintAppInstallationToken(creds) {
|
|
|
26286
26469
|
const tok = await ghApp(jwt, `/app/installations/${installationId}/access_tokens`, "POST");
|
|
26287
26470
|
return tok.token;
|
|
26288
26471
|
}
|
|
26289
|
-
async function discoverAppRepositories(creds) {
|
|
26290
|
-
const jwt = buildAppJwt(creds.appId, creds.privateKey);
|
|
26291
|
-
const installations = [];
|
|
26292
|
-
for (let page = 1; ; page++) {
|
|
26293
|
-
const result = await ghAppPage(jwt, `/app/installations?per_page=100&page=${page}`);
|
|
26294
|
-
installations.push(...result.data.filter((item) => Number.isInteger(item.id) && item.id > 0));
|
|
26295
|
-
if (!result.hasNext) break;
|
|
26296
|
-
}
|
|
26297
|
-
const byRepo = /* @__PURE__ */ new Map();
|
|
26298
|
-
for (const installation of installations) {
|
|
26299
|
-
const token = await mintAppInstallationToken({
|
|
26300
|
-
appId: creds.appId,
|
|
26301
|
-
privateKey: creds.privateKey,
|
|
26302
|
-
installationId: String(installation.id)
|
|
26303
|
-
});
|
|
26304
|
-
for (let page = 1; ; page++) {
|
|
26305
|
-
const result = await ghAppPage(
|
|
26306
|
-
token,
|
|
26307
|
-
`/installation/repositories?per_page=100&page=${page}`
|
|
26308
|
-
);
|
|
26309
|
-
for (const repository of result.data.repositories ?? []) {
|
|
26310
|
-
const repo = repository.full_name?.trim();
|
|
26311
|
-
if (!repo || !/^[^/\s]+\/[^/\s]+$/.test(repo)) continue;
|
|
26312
|
-
byRepo.set(repo.toLowerCase(), { repo, token });
|
|
26313
|
-
}
|
|
26314
|
-
if (!result.hasNext) break;
|
|
26315
|
-
}
|
|
26316
|
-
}
|
|
26317
|
-
return [...byRepo.values()].sort((left, right) => left.repo.localeCompare(right.repo));
|
|
26318
|
-
}
|
|
26319
26472
|
|
|
26320
26473
|
// src/kody-cli.ts
|
|
26321
26474
|
init_capabilityFolders();
|
|
@@ -26891,7 +27044,8 @@ function routeRunRequest(request) {
|
|
|
26891
27044
|
return {
|
|
26892
27045
|
kind: "action",
|
|
26893
27046
|
action: "loop-scheduler",
|
|
26894
|
-
cliArgs: { loop: target.id }
|
|
27047
|
+
cliArgs: { loop: target.id },
|
|
27048
|
+
...typeof request.input?.scheduledFor === "string" ? { scheduledFor: request.input.scheduledFor } : {}
|
|
26895
27049
|
};
|
|
26896
27050
|
}
|
|
26897
27051
|
if (target.type === "workflow") {
|
|
@@ -26997,9 +27151,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
26997
27151
|
return void 0;
|
|
26998
27152
|
}
|
|
26999
27153
|
function detectPackageManager2(cwd) {
|
|
27000
|
-
if (
|
|
27001
|
-
if (
|
|
27002
|
-
if (
|
|
27154
|
+
if (fs56.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
27155
|
+
if (fs56.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
|
|
27156
|
+
if (fs56.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
|
|
27003
27157
|
return "npm";
|
|
27004
27158
|
}
|
|
27005
27159
|
function shouldChainScheduledWatch(match) {
|
|
@@ -27102,8 +27256,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
27102
27256
|
const logPath = lastRunLogPath(cwd);
|
|
27103
27257
|
let tail = "";
|
|
27104
27258
|
try {
|
|
27105
|
-
if (
|
|
27106
|
-
const content =
|
|
27259
|
+
if (fs56.existsSync(logPath)) {
|
|
27260
|
+
const content = fs56.readFileSync(logPath, "utf-8");
|
|
27107
27261
|
tail = content.slice(-3e3);
|
|
27108
27262
|
}
|
|
27109
27263
|
} catch {
|
|
@@ -27159,6 +27313,8 @@ async function runCi(argv) {
|
|
|
27159
27313
|
let forceRunAction = null;
|
|
27160
27314
|
let forceRunCliArgs = {};
|
|
27161
27315
|
let forceWorkflowRunId;
|
|
27316
|
+
let forceRunScheduledFor;
|
|
27317
|
+
let forceRunWakeId;
|
|
27162
27318
|
let forceRunTargetKind = "action";
|
|
27163
27319
|
let runRequestFanOut = false;
|
|
27164
27320
|
let runRequestFanOutForce = false;
|
|
@@ -27183,6 +27339,8 @@ async function runCi(argv) {
|
|
|
27183
27339
|
forceRunAction = route.action;
|
|
27184
27340
|
forceRunCliArgs = route.cliArgs;
|
|
27185
27341
|
forceWorkflowRunId = route.workflowRunId;
|
|
27342
|
+
forceRunScheduledFor = route.scheduledFor;
|
|
27343
|
+
if (route.scheduledFor) forceRunWakeId = parsedRunRequest.request.requestId;
|
|
27186
27344
|
} else if (route.kind === "workflow") {
|
|
27187
27345
|
forceRunAction = route.workflow;
|
|
27188
27346
|
forceRunTargetKind = "workflow";
|
|
@@ -27198,9 +27356,9 @@ async function runCi(argv) {
|
|
|
27198
27356
|
forceRunCliArgs = { goal: envForceMessage };
|
|
27199
27357
|
}
|
|
27200
27358
|
}
|
|
27201
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
27359
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs56.existsSync(dispatchEventPath)) {
|
|
27202
27360
|
try {
|
|
27203
|
-
const evt = JSON.parse(
|
|
27361
|
+
const evt = JSON.parse(fs56.readFileSync(dispatchEventPath, "utf-8"));
|
|
27204
27362
|
const inputs = objectValue2(evt.inputs);
|
|
27205
27363
|
const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
|
|
27206
27364
|
const sessionInput = String(inputs?.sessionId ?? "");
|
|
@@ -27326,7 +27484,8 @@ async function runCi(argv) {
|
|
|
27326
27484
|
cwd,
|
|
27327
27485
|
config,
|
|
27328
27486
|
verbose: args.verbose,
|
|
27329
|
-
quiet: args.quiet
|
|
27487
|
+
quiet: args.quiet,
|
|
27488
|
+
...forceRunScheduledFor ? { preloadedData: { scheduledFor: forceRunScheduledFor, wakeId: forceRunWakeId } } : {}
|
|
27330
27489
|
}
|
|
27331
27490
|
);
|
|
27332
27491
|
const ec = result.exitCode;
|
|
@@ -27615,7 +27774,7 @@ init_repoWorkspace();
|
|
|
27615
27774
|
|
|
27616
27775
|
// src/scripts/brainTurnLog.ts
|
|
27617
27776
|
init_runtimePaths();
|
|
27618
|
-
import * as
|
|
27777
|
+
import * as fs57 from "fs";
|
|
27619
27778
|
import * as path54 from "path";
|
|
27620
27779
|
import posixPath4 from "path/posix";
|
|
27621
27780
|
var live = /* @__PURE__ */ new Map();
|
|
@@ -27624,8 +27783,8 @@ function brainEventsFilePath(dir, chatId) {
|
|
|
27624
27783
|
}
|
|
27625
27784
|
function lastPersistedSeq(dir, chatId) {
|
|
27626
27785
|
const p = brainEventsFilePath(dir, chatId);
|
|
27627
|
-
if (!
|
|
27628
|
-
const lines =
|
|
27786
|
+
if (!fs57.existsSync(p)) return 0;
|
|
27787
|
+
const lines = fs57.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
27629
27788
|
if (lines.length === 0) return 0;
|
|
27630
27789
|
try {
|
|
27631
27790
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -27635,9 +27794,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
27635
27794
|
}
|
|
27636
27795
|
function readSince(dir, chatId, since) {
|
|
27637
27796
|
const p = brainEventsFilePath(dir, chatId);
|
|
27638
|
-
if (!
|
|
27797
|
+
if (!fs57.existsSync(p)) return [];
|
|
27639
27798
|
const out = [];
|
|
27640
|
-
for (const line of
|
|
27799
|
+
for (const line of fs57.readFileSync(p, "utf-8").split("\n")) {
|
|
27641
27800
|
if (!line) continue;
|
|
27642
27801
|
try {
|
|
27643
27802
|
const rec = JSON.parse(line);
|
|
@@ -27663,12 +27822,12 @@ function beginTurn(dir, chatId) {
|
|
|
27663
27822
|
};
|
|
27664
27823
|
live.set(chatId, state);
|
|
27665
27824
|
const p = brainEventsFilePath(dir, chatId);
|
|
27666
|
-
|
|
27825
|
+
fs57.mkdirSync(path54.dirname(p), { recursive: true });
|
|
27667
27826
|
return (event) => {
|
|
27668
27827
|
state.seq += 1;
|
|
27669
27828
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
27670
27829
|
try {
|
|
27671
|
-
|
|
27830
|
+
fs57.appendFileSync(p, `${JSON.stringify(rec)}
|
|
27672
27831
|
`);
|
|
27673
27832
|
} catch (err) {
|
|
27674
27833
|
process.stderr.write(
|
|
@@ -27707,7 +27866,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
27707
27866
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
27708
27867
|
};
|
|
27709
27868
|
try {
|
|
27710
|
-
|
|
27869
|
+
fs57.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
27711
27870
|
`);
|
|
27712
27871
|
} catch {
|
|
27713
27872
|
}
|
|
@@ -29694,55 +29853,6 @@ async function brainTerminalAgent(options) {
|
|
|
29694
29853
|
|
|
29695
29854
|
// src/servers/pool-serve.ts
|
|
29696
29855
|
import { createServer as createServer5 } from "http";
|
|
29697
|
-
|
|
29698
|
-
// src/pool/agency-loop-tick.ts
|
|
29699
|
-
function normalizeRepositories(repositories) {
|
|
29700
|
-
const unique = /* @__PURE__ */ new Set();
|
|
29701
|
-
for (const raw of repositories) {
|
|
29702
|
-
const repo = raw.trim().toLowerCase();
|
|
29703
|
-
if (/^[^/\s]+\/[^/\s]+$/.test(repo)) unique.add(repo);
|
|
29704
|
-
}
|
|
29705
|
-
return [...unique].sort();
|
|
29706
|
-
}
|
|
29707
|
-
async function runAgencyLoopTick(deps) {
|
|
29708
|
-
const repositories = normalizeRepositories(await deps.discover());
|
|
29709
|
-
if (repositories.length === 0) {
|
|
29710
|
-
deps.log("no consumer agencies discovered \u2014 nothing to tick");
|
|
29711
|
-
return { discovered: 0, claimed: 0 };
|
|
29712
|
-
}
|
|
29713
|
-
deps.log(
|
|
29714
|
-
`running scheduled fan-out for ${repositories.length} consumer agenc${repositories.length === 1 ? "y" : "ies"}`
|
|
29715
|
-
);
|
|
29716
|
-
const clock = deps.now ?? Date.now;
|
|
29717
|
-
let claimed = 0;
|
|
29718
|
-
for (const repository of repositories) {
|
|
29719
|
-
const [owner, repo] = repository.split("/");
|
|
29720
|
-
try {
|
|
29721
|
-
const jobId = `sched-${owner}-${repo}-${clock()}`;
|
|
29722
|
-
const result = await deps.claim(owner, repo, {
|
|
29723
|
-
jobId,
|
|
29724
|
-
repo: repository,
|
|
29725
|
-
runRequest: {
|
|
29726
|
-
requestId: jobId,
|
|
29727
|
-
target: { type: "workflow", id: "scheduled-fanout" },
|
|
29728
|
-
intent: "tick",
|
|
29729
|
-
source: "schedule"
|
|
29730
|
-
}
|
|
29731
|
-
});
|
|
29732
|
-
if (result.ok) {
|
|
29733
|
-
claimed++;
|
|
29734
|
-
deps.log(`[${repository}] scheduled fan-out claimed ${result.machineId}`);
|
|
29735
|
-
} else {
|
|
29736
|
-
deps.log(`[${repository}] scheduled fan-out skipped: ${result.reason ?? "runner unavailable"}`);
|
|
29737
|
-
}
|
|
29738
|
-
} catch (error) {
|
|
29739
|
-
deps.log(`[${repository}] scheduled fan-out error: ${error instanceof Error ? error.message : String(error)}`);
|
|
29740
|
-
}
|
|
29741
|
-
}
|
|
29742
|
-
return { discovered: repositories.length, claimed };
|
|
29743
|
-
}
|
|
29744
|
-
|
|
29745
|
-
// src/servers/pool-serve.ts
|
|
29746
29856
|
init_keys();
|
|
29747
29857
|
|
|
29748
29858
|
// src/pool/registry.ts
|
|
@@ -30378,30 +30488,6 @@ async function poolServe() {
|
|
|
30378
30488
|
const tick = setInterval(() => {
|
|
30379
30489
|
registry.resyncAll().catch((err) => log(`resync tick failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
30380
30490
|
}, refillMs);
|
|
30381
|
-
const discoverAgencies = async () => {
|
|
30382
|
-
if (!appCreds) return registry.activeRepos();
|
|
30383
|
-
const repositories = await discoverAppRepositories(appCreds);
|
|
30384
|
-
for (const access of repositories) repoTokens.set(access.repo.toLowerCase(), access.token);
|
|
30385
|
-
return [.../* @__PURE__ */ new Set([...repositories.map((access) => access.repo), ...registry.activeRepos()])];
|
|
30386
|
-
};
|
|
30387
|
-
let agencyTickInFlight = null;
|
|
30388
|
-
const runLoopTick = () => {
|
|
30389
|
-
if (agencyTickInFlight) return agencyTickInFlight;
|
|
30390
|
-
agencyTickInFlight = runAgencyLoopTick({
|
|
30391
|
-
discover: discoverAgencies,
|
|
30392
|
-
claim: (owner, repo, req) => registry.claim(owner, repo, req),
|
|
30393
|
-
log
|
|
30394
|
-
}).catch((err) => log(`agency Loop tick failed: ${err instanceof Error ? err.message : String(err)}`)).finally(() => {
|
|
30395
|
-
agencyTickInFlight = null;
|
|
30396
|
-
});
|
|
30397
|
-
return agencyTickInFlight;
|
|
30398
|
-
};
|
|
30399
|
-
const loopTickEnabled = (process.env.POOL_LOOP_TICK ?? process.env.POOL_CAPABILITY_TICK ?? "1") !== "0";
|
|
30400
|
-
const loopTickMs = envInt2(
|
|
30401
|
-
process.env.POOL_LOOP_TICK_MS ? "POOL_LOOP_TICK_MS" : "POOL_CAPABILITY_TICK_MS",
|
|
30402
|
-
15 * 6e4
|
|
30403
|
-
);
|
|
30404
|
-
const loopTick = loopTickEnabled ? setInterval(() => void runLoopTick(), loopTickMs) : null;
|
|
30405
30491
|
const server = createServer5(async (req, res) => {
|
|
30406
30492
|
try {
|
|
30407
30493
|
if (!req.method || !req.url) return sendJson2(res, 400, { error: "bad request" });
|
|
@@ -30455,11 +30541,9 @@ async function poolServe() {
|
|
|
30455
30541
|
resolve24();
|
|
30456
30542
|
});
|
|
30457
30543
|
});
|
|
30458
|
-
if (loopTickEnabled) void runLoopTick();
|
|
30459
30544
|
const shutdown = (signal) => {
|
|
30460
30545
|
log(`${signal} \u2014 shutting down`);
|
|
30461
30546
|
clearInterval(tick);
|
|
30462
|
-
if (loopTick) clearInterval(loopTick);
|
|
30463
30547
|
server.close(() => process.exit(0));
|
|
30464
30548
|
};
|
|
30465
30549
|
process.once("SIGINT", () => shutdown("SIGINT"));
|
|
@@ -30471,7 +30555,7 @@ async function poolServe() {
|
|
|
30471
30555
|
|
|
30472
30556
|
// src/servers/runner-serve.ts
|
|
30473
30557
|
import { spawn as spawn10 } from "child_process";
|
|
30474
|
-
import * as
|
|
30558
|
+
import * as fs58 from "fs";
|
|
30475
30559
|
import { createServer as createServer6 } from "http";
|
|
30476
30560
|
var DEFAULT_PORT2 = 8080;
|
|
30477
30561
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -30547,8 +30631,8 @@ async function defaultRunJob(job) {
|
|
|
30547
30631
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
30548
30632
|
const branch = job.ref ?? "main";
|
|
30549
30633
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
30550
|
-
|
|
30551
|
-
|
|
30634
|
+
fs58.rmSync(workdir, { recursive: true, force: true });
|
|
30635
|
+
fs58.mkdirSync(workdir, { recursive: true });
|
|
30552
30636
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
30553
30637
|
const target = job.runRequest.target;
|
|
30554
30638
|
const interactive = target.type === "chat";
|
|
@@ -31136,7 +31220,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
31136
31220
|
const args = parseArgs(argv);
|
|
31137
31221
|
const cwdFlag = argv.indexOf("--cwd");
|
|
31138
31222
|
const definitionCwd = cwdFlag >= 0 && argv[cwdFlag + 1] ? argv[cwdFlag + 1] : process.cwd();
|
|
31139
|
-
const shouldHydrate = !(args.command === "server" && args.serverName === "brain-serve") && !hasExplicitDefinitionsRoot(definitionCwd) && (Boolean(process.env.CONVEX_URL?.trim()) || process.env.GITHUB_ACTIONS === "true" && Boolean(process.env.GITHUB_EVENT_NAME));
|
|
31223
|
+
const shouldHydrate = args.command !== "help" && args.command !== "version" && !(args.command === "server" && args.serverName === "brain-serve") && !hasExplicitDefinitionsRoot(definitionCwd) && (Boolean(process.env.CONVEX_URL?.trim()) || process.env.GITHUB_ACTIONS === "true" && Boolean(process.env.GITHUB_EVENT_NAME));
|
|
31140
31224
|
if (shouldHydrate) {
|
|
31141
31225
|
try {
|
|
31142
31226
|
await hydrateDefinitionsFromEnv(definitionCwd);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "live-agent",
|
|
3
|
+
"action": "live-agent",
|
|
4
|
+
"purpose": "Run one continuation cycle for a selected persistent Agent.",
|
|
5
|
+
"inputSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"agent": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Selected Agent slug."
|
|
11
|
+
},
|
|
12
|
+
"intent": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Primary Intent slug recorded by the Loop."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"required": ["agent"],
|
|
18
|
+
"additionalProperties": false
|
|
19
|
+
},
|
|
20
|
+
"outputSchema": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"cursor": { "type": "string" },
|
|
24
|
+
"data": { "type": "object", "additionalProperties": true }
|
|
25
|
+
},
|
|
26
|
+
"additionalProperties": true
|
|
27
|
+
},
|
|
28
|
+
"effects": ["agent-state"],
|
|
29
|
+
"permissions": [],
|
|
30
|
+
"success": "The Agent completes one cycle and persists its continuation state.",
|
|
31
|
+
"failure": "The Agent cycle fails or its continuation state cannot be persisted."
|
|
32
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "live-agent",
|
|
3
|
+
"role": "primitive",
|
|
4
|
+
"kind": "oneshot",
|
|
5
|
+
"inputs": [
|
|
6
|
+
{ "name": "agent", "flag": "--agent", "type": "string", "required": true, "describe": "Live Agent slug." },
|
|
7
|
+
{ "name": "intent", "flag": "--intent", "type": "string", "required": false, "describe": "Primary Intent slug recorded by the Loop." }
|
|
8
|
+
],
|
|
9
|
+
"claudeCode": {
|
|
10
|
+
"model": "inherit",
|
|
11
|
+
"permissionMode": "default",
|
|
12
|
+
"maxTurns": 100,
|
|
13
|
+
"maxThinkingTokens": null,
|
|
14
|
+
"systemPromptAppend": null,
|
|
15
|
+
"enableSubmitTool": true,
|
|
16
|
+
"tools": ["mcp__kody-capability__start_capability", "mcp__kody-submit__submit_state"],
|
|
17
|
+
"hooks": [], "skills": [], "commands": [], "subagents": [], "plugins": [], "mcpServers": []
|
|
18
|
+
},
|
|
19
|
+
"cliTools": [],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"preflight": [{ "script": "loadLiveAgent" }, { "script": "composePrompt" }],
|
|
22
|
+
"postflight": [
|
|
23
|
+
{ "script": "parseJobStateFromAgentResult", "with": { "fenceLabel": "kody-agent-next-state" } },
|
|
24
|
+
{ "script": "saveLiveAgentState" },
|
|
25
|
+
{ "script": "appendCompanyActivity" }
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"inputArtifacts": [],
|
|
29
|
+
"outputArtifacts": []
|
|
30
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
You are a persistent Kody Agent completing one scheduled cycle.
|
|
2
|
+
|
|
3
|
+
## Identity
|
|
4
|
+
|
|
5
|
+
{{agentIdentity}}
|
|
6
|
+
|
|
7
|
+
## Primary Intent
|
|
8
|
+
|
|
9
|
+
{{liveAgentIntent}}
|
|
10
|
+
|
|
11
|
+
## Policies
|
|
12
|
+
|
|
13
|
+
{{liveAgentPolicies}}
|
|
14
|
+
|
|
15
|
+
## Constraints
|
|
16
|
+
|
|
17
|
+
{{liveAgentConstraints}}
|
|
18
|
+
|
|
19
|
+
## Context
|
|
20
|
+
|
|
21
|
+
{{liveAgentContext}}
|
|
22
|
+
|
|
23
|
+
## Assigned Capabilities
|
|
24
|
+
|
|
25
|
+
{{liveAgentCapabilities}}
|
|
26
|
+
|
|
27
|
+
## Previous continuation
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{{jobStateJson}}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Inspect current conditions, decide the best next action toward the Intent, and use only assigned capabilities. Do not create work merely to appear active. If waiting is correct, record what is being awaited.
|
|
34
|
+
|
|
35
|
+
As your final action, call `submit_state` exactly once with:
|
|
36
|
+
- `cursor`: the next continuation cursor;
|
|
37
|
+
- `data`: compact durable continuation data;
|
|
38
|
+
- `done`: always `false` for a live Agent.
|
|
File without changes
|
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.611",
|
|
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",
|
|
@@ -12,6 +12,30 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"kody:run": "tsx bin/kody.ts",
|
|
17
|
+
"serve": "tsx bin/kody.ts serve",
|
|
18
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
19
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
20
|
+
"clean:dist": "node scripts/clean-dist.cjs",
|
|
21
|
+
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
22
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
23
|
+
"pretest": "pnpm check:modularity",
|
|
24
|
+
"test": "vitest run tests/unit tests/int --coverage",
|
|
25
|
+
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
26
|
+
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
27
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
28
|
+
"verify:live-release": "tsx scripts/live-release-gate.ts",
|
|
29
|
+
"test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
|
|
30
|
+
"test:all": "vitest run tests --no-coverage",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"lint": "biome check",
|
|
33
|
+
"lint:fix": "biome check --write",
|
|
34
|
+
"format": "biome format --write",
|
|
35
|
+
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
36
|
+
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
|
|
37
|
+
"prepublishOnly": "pnpm typecheck && pnpm test:runtime-services && pnpm build && pnpm verify:package"
|
|
38
|
+
},
|
|
15
39
|
"dependencies": {
|
|
16
40
|
"@actions/cache": "^6.0.0",
|
|
17
41
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -38,28 +62,5 @@
|
|
|
38
62
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
39
63
|
},
|
|
40
64
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
41
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
42
|
-
|
|
43
|
-
"kody:run": "tsx bin/kody.ts",
|
|
44
|
-
"serve": "tsx bin/kody.ts serve",
|
|
45
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
46
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
47
|
-
"clean:dist": "node scripts/clean-dist.cjs",
|
|
48
|
-
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
49
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
50
|
-
"pretest": "pnpm check:modularity",
|
|
51
|
-
"test": "vitest run tests/unit tests/int --coverage",
|
|
52
|
-
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
53
|
-
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
54
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
55
|
-
"verify:live-release": "tsx scripts/live-release-gate.ts",
|
|
56
|
-
"test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
|
|
57
|
-
"test:all": "vitest run tests --no-coverage",
|
|
58
|
-
"typecheck": "tsc --noEmit",
|
|
59
|
-
"lint": "biome check",
|
|
60
|
-
"lint:fix": "biome check --write",
|
|
61
|
-
"format": "biome format --write",
|
|
62
|
-
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
63
|
-
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
65
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
66
|
+
}
|