@kody-ade/kody-engine 0.4.244 → 0.4.245
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/agent-actions/types.ts +20 -24
- package/dist/bin/kody.js +1034 -747
- 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.245",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative agentAction profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -194,8 +194,8 @@ function isRunningAsBot() {
|
|
|
194
194
|
}
|
|
195
195
|
function postIssueComment(issueNumber, body, cwd) {
|
|
196
196
|
if (isRunningAsBot()) {
|
|
197
|
-
const
|
|
198
|
-
if (
|
|
197
|
+
const slug2 = detectBotDispatchShape(body);
|
|
198
|
+
if (slug2) throw new BotDispatchCommentError(slug2);
|
|
199
199
|
}
|
|
200
200
|
try {
|
|
201
201
|
gh(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
@@ -295,8 +295,8 @@ function getPrLatestReviewBody(prNumber, cwd) {
|
|
|
295
295
|
}
|
|
296
296
|
function postPrReviewComment(prNumber, body, cwd) {
|
|
297
297
|
if (isRunningAsBot()) {
|
|
298
|
-
const
|
|
299
|
-
if (
|
|
298
|
+
const slug2 = detectBotDispatchShape(body);
|
|
299
|
+
if (slug2) throw new BotDispatchCommentError(slug2);
|
|
300
300
|
}
|
|
301
301
|
try {
|
|
302
302
|
gh(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
@@ -313,9 +313,9 @@ var init_issue = __esm({
|
|
|
313
313
|
"use strict";
|
|
314
314
|
API_TIMEOUT_MS = 3e4;
|
|
315
315
|
BotDispatchCommentError = class extends Error {
|
|
316
|
-
constructor(
|
|
316
|
+
constructor(slug2) {
|
|
317
317
|
super(
|
|
318
|
-
`bot self-dispatch via @kody comments is banned. Refusing to post "@kody ${
|
|
318
|
+
`bot self-dispatch via @kody comments is banned. Refusing to post "@kody ${slug2} \u2026" \u2014 use runAgentActionChain (same-run) or dispatchAgentAction (cross-run) instead. See docs/agent-responsibility-dispatch.md for the contract.`
|
|
319
319
|
);
|
|
320
320
|
this.name = "BotDispatchCommentError";
|
|
321
321
|
}
|
|
@@ -332,8 +332,8 @@ function is404(err) {
|
|
|
332
332
|
const msg = err instanceof Error ? err.message : String(err);
|
|
333
333
|
return /HTTP 404/i.test(msg) || /Not Found/i.test(msg);
|
|
334
334
|
}
|
|
335
|
-
function parseStateRepoSlug(
|
|
336
|
-
const value =
|
|
335
|
+
function parseStateRepoSlug(slug2, field = "stateRepo") {
|
|
336
|
+
const value = slug2.trim();
|
|
337
337
|
let repoPath = value;
|
|
338
338
|
if (/^https?:\/\//i.test(value)) {
|
|
339
339
|
let parsed;
|
|
@@ -460,6 +460,18 @@ function appendStateLine(config, cwd, filePath, line, message) {
|
|
|
460
460
|
`}`;
|
|
461
461
|
writeStateText(config, cwd, filePath, next, message, prior?.sha);
|
|
462
462
|
}
|
|
463
|
+
function listStateDirectory(config, cwd, dirPath) {
|
|
464
|
+
const targetPath = stateRepoPath(config, dirPath);
|
|
465
|
+
let raw = "";
|
|
466
|
+
try {
|
|
467
|
+
raw = gh(["api", apiPath(config, targetPath)], { cwd });
|
|
468
|
+
} catch (err) {
|
|
469
|
+
if (is404(err)) return [];
|
|
470
|
+
throw err;
|
|
471
|
+
}
|
|
472
|
+
const parsed = JSON.parse(raw);
|
|
473
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
474
|
+
}
|
|
463
475
|
var init_stateRepo = __esm({
|
|
464
476
|
"src/stateRepo.ts"() {
|
|
465
477
|
"use strict";
|
|
@@ -619,11 +631,11 @@ function parseGoalActivations(raw) {
|
|
|
619
631
|
const seen = /* @__PURE__ */ new Set();
|
|
620
632
|
for (const value of raw) {
|
|
621
633
|
if (typeof value === "string") {
|
|
622
|
-
const
|
|
623
|
-
if (!
|
|
624
|
-
if (!seen.has(
|
|
625
|
-
seen.add(
|
|
626
|
-
out.push(
|
|
634
|
+
const slug2 = parseSlug(value, "company.activeGoals");
|
|
635
|
+
if (!slug2) continue;
|
|
636
|
+
if (!seen.has(slug2)) {
|
|
637
|
+
seen.add(slug2);
|
|
638
|
+
out.push(slug2);
|
|
627
639
|
}
|
|
628
640
|
continue;
|
|
629
641
|
}
|
|
@@ -658,20 +670,20 @@ function parseSlugArray(raw, field) {
|
|
|
658
670
|
if (!Array.isArray(raw)) throw new Error(`kody.config.json: ${field} must be an array of strings`);
|
|
659
671
|
const out = [];
|
|
660
672
|
for (const value of raw) {
|
|
661
|
-
const
|
|
662
|
-
if (!
|
|
663
|
-
out.push(
|
|
673
|
+
const slug2 = parseSlug(value, field);
|
|
674
|
+
if (!slug2) continue;
|
|
675
|
+
out.push(slug2);
|
|
664
676
|
}
|
|
665
677
|
return [...new Set(out)];
|
|
666
678
|
}
|
|
667
679
|
function parseSlug(value, field) {
|
|
668
680
|
if (typeof value !== "string") throw new Error(`kody.config.json: ${field} entries must be strings`);
|
|
669
|
-
const
|
|
670
|
-
if (!
|
|
671
|
-
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(
|
|
681
|
+
const slug2 = value.trim();
|
|
682
|
+
if (!slug2) return "";
|
|
683
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(slug2)) {
|
|
672
684
|
throw new Error(`kody.config.json: ${field} contains invalid slug "${value}"`);
|
|
673
685
|
}
|
|
674
|
-
return
|
|
686
|
+
return slug2;
|
|
675
687
|
}
|
|
676
688
|
function recordValue(raw) {
|
|
677
689
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : void 0;
|
|
@@ -2303,56 +2315,6 @@ var init_agent = __esm({
|
|
|
2303
2315
|
}
|
|
2304
2316
|
});
|
|
2305
2317
|
|
|
2306
|
-
// src/scripts/scheduleEvery.ts
|
|
2307
|
-
function isScheduleEvery(value) {
|
|
2308
|
-
return typeof value === "string" && SCHEDULE_EVERY_VALUES.includes(value);
|
|
2309
|
-
}
|
|
2310
|
-
function scheduleEveryToMs(every) {
|
|
2311
|
-
const MIN = 60 * 1e3;
|
|
2312
|
-
const HOUR = 60 * MIN;
|
|
2313
|
-
const DAY = 24 * HOUR;
|
|
2314
|
-
switch (every) {
|
|
2315
|
-
case "15m":
|
|
2316
|
-
return 15 * MIN;
|
|
2317
|
-
case "30m":
|
|
2318
|
-
return 30 * MIN;
|
|
2319
|
-
case "1h":
|
|
2320
|
-
return HOUR;
|
|
2321
|
-
case "2h":
|
|
2322
|
-
return 2 * HOUR;
|
|
2323
|
-
case "6h":
|
|
2324
|
-
return 6 * HOUR;
|
|
2325
|
-
case "12h":
|
|
2326
|
-
return 12 * HOUR;
|
|
2327
|
-
case "1d":
|
|
2328
|
-
return DAY;
|
|
2329
|
-
case "3d":
|
|
2330
|
-
return 3 * DAY;
|
|
2331
|
-
case "7d":
|
|
2332
|
-
return 7 * DAY;
|
|
2333
|
-
case "manual":
|
|
2334
|
-
return Number.POSITIVE_INFINITY;
|
|
2335
|
-
}
|
|
2336
|
-
}
|
|
2337
|
-
var SCHEDULE_EVERY_VALUES;
|
|
2338
|
-
var init_scheduleEvery = __esm({
|
|
2339
|
-
"src/scripts/scheduleEvery.ts"() {
|
|
2340
|
-
"use strict";
|
|
2341
|
-
SCHEDULE_EVERY_VALUES = [
|
|
2342
|
-
"15m",
|
|
2343
|
-
"30m",
|
|
2344
|
-
"1h",
|
|
2345
|
-
"2h",
|
|
2346
|
-
"6h",
|
|
2347
|
-
"12h",
|
|
2348
|
-
"1d",
|
|
2349
|
-
"3d",
|
|
2350
|
-
"7d",
|
|
2351
|
-
"manual"
|
|
2352
|
-
];
|
|
2353
|
-
}
|
|
2354
|
-
});
|
|
2355
|
-
|
|
2356
2318
|
// src/agent-responsibilityFolders.ts
|
|
2357
2319
|
import * as fs6 from "fs";
|
|
2358
2320
|
import * as path8 from "path";
|
|
@@ -2369,8 +2331,8 @@ function listAgentResponsibilityFolderSlugs(absDir) {
|
|
|
2369
2331
|
function isAgentResponsibilityFolder(dir) {
|
|
2370
2332
|
return fs6.existsSync(path8.join(dir, AGENT_RESPONSIBILITY_PROFILE_FILE)) && fs6.existsSync(path8.join(dir, AGENT_RESPONSIBILITY_BODY_FILE));
|
|
2371
2333
|
}
|
|
2372
|
-
function readAgentResponsibilityFolder(root,
|
|
2373
|
-
const dir = path8.join(root,
|
|
2334
|
+
function readAgentResponsibilityFolder(root, slug2) {
|
|
2335
|
+
const dir = path8.join(root, slug2);
|
|
2374
2336
|
const profilePath = path8.join(dir, AGENT_RESPONSIBILITY_PROFILE_FILE);
|
|
2375
2337
|
const bodyPath = path8.join(dir, AGENT_RESPONSIBILITY_BODY_FILE);
|
|
2376
2338
|
if (!fs6.existsSync(profilePath) || !fs6.statSync(profilePath).isFile()) return null;
|
|
@@ -2378,9 +2340,9 @@ function readAgentResponsibilityFolder(root, slug) {
|
|
|
2378
2340
|
try {
|
|
2379
2341
|
const rawProfile = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
|
|
2380
2342
|
const rawBody = fs6.readFileSync(bodyPath, "utf-8");
|
|
2381
|
-
const { title, body } = parseAgentResponsibilityBody(rawBody,
|
|
2343
|
+
const { title, body } = parseAgentResponsibilityBody(rawBody, slug2);
|
|
2382
2344
|
return {
|
|
2383
|
-
slug,
|
|
2345
|
+
slug: slug2,
|
|
2384
2346
|
dir,
|
|
2385
2347
|
profilePath,
|
|
2386
2348
|
bodyPath,
|
|
@@ -2399,7 +2361,6 @@ function parseAgentResponsibilityConfig(raw) {
|
|
|
2399
2361
|
return {
|
|
2400
2362
|
action: stringField(raw.action),
|
|
2401
2363
|
agentAction: stringField(raw.agentAction),
|
|
2402
|
-
every: isScheduleEvery(raw.every) ? raw.every : void 0,
|
|
2403
2364
|
tickScript: stringField(raw.tickScript),
|
|
2404
2365
|
disabled: typeof raw.disabled === "boolean" ? raw.disabled : void 0,
|
|
2405
2366
|
agent: stringField(raw.agent),
|
|
@@ -2413,11 +2374,11 @@ function parseAgentResponsibilityConfig(raw) {
|
|
|
2413
2374
|
writesTo: stringList(raw.writesTo ?? raw.writes_to)
|
|
2414
2375
|
};
|
|
2415
2376
|
}
|
|
2416
|
-
function parseAgentResponsibilityBody(raw,
|
|
2377
|
+
function parseAgentResponsibilityBody(raw, slug2) {
|
|
2417
2378
|
const trimmed = raw.trim();
|
|
2418
2379
|
const firstLine2 = trimmed.split("\n", 1)[0] ?? "";
|
|
2419
2380
|
const h1 = /^#\s+(.+?)\s*$/.exec(firstLine2);
|
|
2420
|
-
const title = h1 ? h1[1].trim() : humanizeSlug(
|
|
2381
|
+
const title = h1 ? h1[1].trim() : humanizeSlug(slug2);
|
|
2421
2382
|
const body = stripLeadingH1(raw);
|
|
2422
2383
|
return { title, body };
|
|
2423
2384
|
}
|
|
@@ -2431,8 +2392,8 @@ function stripLeadingH1(raw) {
|
|
|
2431
2392
|
}
|
|
2432
2393
|
return lines.slice(i).join("\n");
|
|
2433
2394
|
}
|
|
2434
|
-
function humanizeSlug(
|
|
2435
|
-
return
|
|
2395
|
+
function humanizeSlug(slug2) {
|
|
2396
|
+
return slug2.split(/[-_]+/).filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
|
|
2436
2397
|
}
|
|
2437
2398
|
function stringField(value) {
|
|
2438
2399
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
@@ -2454,7 +2415,6 @@ var AGENT_RESPONSIBILITY_PROFILE_FILE, AGENT_RESPONSIBILITY_BODY_FILE;
|
|
|
2454
2415
|
var init_agent_responsibilityFolders = __esm({
|
|
2455
2416
|
"src/agent-responsibilityFolders.ts"() {
|
|
2456
2417
|
"use strict";
|
|
2457
|
-
init_scheduleEvery();
|
|
2458
2418
|
AGENT_RESPONSIBILITY_PROFILE_FILE = "profile.json";
|
|
2459
2419
|
AGENT_RESPONSIBILITY_BODY_FILE = "agent-responsibility.md";
|
|
2460
2420
|
}
|
|
@@ -2680,10 +2640,10 @@ function resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRo
|
|
|
2680
2640
|
function hasAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot = getProjectAgentResponsibilitiesRoot()) {
|
|
2681
2641
|
return resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot) !== null;
|
|
2682
2642
|
}
|
|
2683
|
-
function resolveAgentResponsibilityFolder(
|
|
2684
|
-
if (!isSafeName(
|
|
2643
|
+
function resolveAgentResponsibilityFolder(slug2, projectAgentResponsibilitiesRoot = getProjectAgentResponsibilitiesRoot()) {
|
|
2644
|
+
if (!isSafeName(slug2)) return null;
|
|
2685
2645
|
for (const root of getAgentResponsibilityRoots(projectAgentResponsibilitiesRoot)) {
|
|
2686
|
-
const agentResponsibility = readAgentResponsibilityFolder(root,
|
|
2646
|
+
const agentResponsibility = readAgentResponsibilityFolder(root, slug2);
|
|
2687
2647
|
if (agentResponsibility) return agentResponsibility;
|
|
2688
2648
|
}
|
|
2689
2649
|
return null;
|
|
@@ -2742,15 +2702,15 @@ function listAgentActionResponsibilityActions(root, source) {
|
|
|
2742
2702
|
function listFolderAgentResponsibilityActions(root, source) {
|
|
2743
2703
|
if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
|
|
2744
2704
|
const out = [];
|
|
2745
|
-
for (const
|
|
2746
|
-
if (!isSafeName(
|
|
2747
|
-
const agentResponsibility = readAgentResponsibilityFolder(root,
|
|
2705
|
+
for (const slug2 of listAgentResponsibilityFolderSlugs(root)) {
|
|
2706
|
+
if (!isSafeName(slug2)) continue;
|
|
2707
|
+
const agentResponsibility = readAgentResponsibilityFolder(root, slug2);
|
|
2748
2708
|
if (!agentResponsibility) continue;
|
|
2749
|
-
const action = agentResponsibility.config.action ??
|
|
2709
|
+
const action = agentResponsibility.config.action ?? slug2;
|
|
2750
2710
|
const { agentAction, cliArgs } = resolveAgentResponsibilityExecution(agentResponsibility);
|
|
2751
2711
|
out.push({
|
|
2752
2712
|
action,
|
|
2753
|
-
agentResponsibility:
|
|
2713
|
+
agentResponsibility: slug2,
|
|
2754
2714
|
agentAction,
|
|
2755
2715
|
cliArgs,
|
|
2756
2716
|
source,
|
|
@@ -2765,15 +2725,15 @@ function listFolderAgentResponsibilityActions(root, source) {
|
|
|
2765
2725
|
function listBuiltinAgentResponsibilityActions(root = getBuiltinAgentResponsibilitiesRoot()) {
|
|
2766
2726
|
if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
|
|
2767
2727
|
const out = [];
|
|
2768
|
-
for (const
|
|
2769
|
-
if (!isSafeName(
|
|
2770
|
-
const agentResponsibility = readAgentResponsibilityFolder(root,
|
|
2728
|
+
for (const slug2 of listAgentResponsibilityFolderSlugs(root)) {
|
|
2729
|
+
if (!isSafeName(slug2)) continue;
|
|
2730
|
+
const agentResponsibility = readAgentResponsibilityFolder(root, slug2);
|
|
2771
2731
|
if (!agentResponsibility) continue;
|
|
2772
|
-
const action = agentResponsibility.config.action ??
|
|
2773
|
-
const agentAction = agentResponsibility.config.agentAction ??
|
|
2732
|
+
const action = agentResponsibility.config.action ?? slug2;
|
|
2733
|
+
const agentAction = agentResponsibility.config.agentAction ?? slug2;
|
|
2774
2734
|
out.push({
|
|
2775
2735
|
action,
|
|
2776
|
-
agentResponsibility:
|
|
2736
|
+
agentResponsibility: slug2,
|
|
2777
2737
|
agentAction,
|
|
2778
2738
|
cliArgs: {},
|
|
2779
2739
|
source: "builtin",
|
|
@@ -3199,8 +3159,8 @@ function stripFrontmatter(raw) {
|
|
|
3199
3159
|
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
3200
3160
|
return (match ? match[1] : raw).trim();
|
|
3201
3161
|
}
|
|
3202
|
-
function loadAgentIdentity(cwd,
|
|
3203
|
-
const trimmed =
|
|
3162
|
+
function loadAgentIdentity(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3163
|
+
const trimmed = slug2.trim();
|
|
3204
3164
|
if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
|
|
3205
3165
|
const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
|
|
3206
3166
|
if (fs16.existsSync(agentPath)) {
|
|
@@ -3214,21 +3174,21 @@ function loadAgentIdentity(cwd, slug, agentsDir = DEFAULT_AGENT_DIR) {
|
|
|
3214
3174
|
if (builtin) return builtin;
|
|
3215
3175
|
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
3216
3176
|
}
|
|
3217
|
-
function resolveAgentFile(cwd,
|
|
3218
|
-
const localPath = path16.join(cwd, agentsDir, `${
|
|
3177
|
+
function resolveAgentFile(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3178
|
+
const localPath = path16.join(cwd, agentsDir, `${slug2}.md`);
|
|
3219
3179
|
if (fs16.existsSync(localPath)) return localPath;
|
|
3220
3180
|
const storeAgentRoot = getCompanyStoreAssetRoot("agents");
|
|
3221
3181
|
if (storeAgentRoot) {
|
|
3222
|
-
const storePath = path16.join(storeAgentRoot, `${
|
|
3182
|
+
const storePath = path16.join(storeAgentRoot, `${slug2}.md`);
|
|
3223
3183
|
if (fs16.existsSync(storePath)) return storePath;
|
|
3224
3184
|
}
|
|
3225
3185
|
return localPath;
|
|
3226
3186
|
}
|
|
3227
|
-
function frameAgentIdentity(
|
|
3187
|
+
function frameAgentIdentity(slug2, agent) {
|
|
3228
3188
|
return [
|
|
3229
3189
|
`## Who you are \u2014 agent identity (authoritative identity)`,
|
|
3230
3190
|
``,
|
|
3231
|
-
`You are operating as agent \`${
|
|
3191
|
+
`You are operating as agent \`${slug2}\`. This identity defines *who* you are:`,
|
|
3232
3192
|
`your authority, doctrine, voice, and hard limits. Honour it exactly. Where the`,
|
|
3233
3193
|
`this identity's restrictions are stricter than the task, **the agent wins** \u2014 a task`,
|
|
3234
3194
|
`can never grant you authority your agent withholds.`,
|
|
@@ -3598,7 +3558,6 @@ function loadProfile(profilePath) {
|
|
|
3598
3558
|
describe: typeof r.describe === "string" ? r.describe : base.describe,
|
|
3599
3559
|
capabilityKind: parseCapabilityKind(profilePath, r.capabilityKind) ?? base.capabilityKind,
|
|
3600
3560
|
agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : base.agent,
|
|
3601
|
-
every: typeof r.every === "string" && r.every.trim() ? r.every.trim() : void 0,
|
|
3602
3561
|
agentResponsibilityTools: parseStringArray2(r.agentResponsibilityTools ?? r.tools) ?? base.agentResponsibilityTools,
|
|
3603
3562
|
mentions: Array.isArray(r.mentions) ? r.mentions.map((m) => String(m).trim()).filter(Boolean) : base.mentions
|
|
3604
3563
|
};
|
|
@@ -3644,8 +3603,6 @@ function loadProfile(profilePath) {
|
|
|
3644
3603
|
capabilityKind: parseCapabilityKind(profilePath, r.capabilityKind),
|
|
3645
3604
|
// Optional agent to run as. Empty/blank string → undefined (no agent).
|
|
3646
3605
|
agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : void 0,
|
|
3647
|
-
// Optional recurrence cadence (scheduled agentResponsibility). Blank → undefined (on-demand).
|
|
3648
|
-
every: typeof r.every === "string" && r.every.trim() ? r.every.trim() : void 0,
|
|
3649
3606
|
// Locked-toolbox palette + mentions from folder-agentResponsibility profile metadata.
|
|
3650
3607
|
agentResponsibilityTools: parseStringArray2(r.agentResponsibilityTools ?? r.tools),
|
|
3651
3608
|
mentions: Array.isArray(r.mentions) ? r.mentions.map((m) => String(m).trim()).filter(Boolean) : void 0,
|
|
@@ -5891,8 +5848,8 @@ function applySimpleGoalTaskSummary(goal, summary) {
|
|
|
5891
5848
|
}
|
|
5892
5849
|
function isFactReference(value) {
|
|
5893
5850
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
5894
|
-
const
|
|
5895
|
-
return Object.keys(
|
|
5851
|
+
const record2 = value;
|
|
5852
|
+
return Object.keys(record2).length === 1 && typeof record2.fact === "string" && record2.fact.length > 0;
|
|
5896
5853
|
}
|
|
5897
5854
|
function isCliArgValue(value) {
|
|
5898
5855
|
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
@@ -5967,7 +5924,8 @@ function planManagedGoalTick(goal) {
|
|
|
5967
5924
|
stage: step.stage,
|
|
5968
5925
|
agentResponsibility: step.agentResponsibility,
|
|
5969
5926
|
agentAction: step.agentAction,
|
|
5970
|
-
cliArgs: resolved.cliArgs
|
|
5927
|
+
cliArgs: resolved.cliArgs,
|
|
5928
|
+
...step.saveReport === true ? { saveReport: true } : {}
|
|
5971
5929
|
};
|
|
5972
5930
|
}
|
|
5973
5931
|
function asStringArray(value) {
|
|
@@ -5994,7 +5952,8 @@ function asRoute(value) {
|
|
|
5994
5952
|
stage: raw.stage,
|
|
5995
5953
|
agentResponsibility: raw.agentResponsibility,
|
|
5996
5954
|
agentAction: typeof raw.agentAction === "string" ? raw.agentAction : void 0,
|
|
5997
|
-
args: args ?? void 0
|
|
5955
|
+
args: args ?? void 0,
|
|
5956
|
+
saveReport: raw.saveReport === true
|
|
5998
5957
|
});
|
|
5999
5958
|
}
|
|
6000
5959
|
return route;
|
|
@@ -6088,10 +6047,10 @@ var init_state2 = __esm({
|
|
|
6088
6047
|
"use strict";
|
|
6089
6048
|
VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
|
|
6090
6049
|
GoalStateError = class extends Error {
|
|
6091
|
-
constructor(
|
|
6092
|
-
super(`Invalid goal state at ${
|
|
6050
|
+
constructor(path46, message) {
|
|
6051
|
+
super(`Invalid goal state at ${path46}:
|
|
6093
6052
|
${message}`);
|
|
6094
|
-
this.path =
|
|
6053
|
+
this.path = path46;
|
|
6095
6054
|
this.name = "GoalStateError";
|
|
6096
6055
|
}
|
|
6097
6056
|
path;
|
|
@@ -6336,8 +6295,8 @@ function isStateUnchanged(prev, next) {
|
|
|
6336
6295
|
if (prev.done !== next.done) return false;
|
|
6337
6296
|
return JSON.stringify(prev.data) === JSON.stringify(next.data);
|
|
6338
6297
|
}
|
|
6339
|
-
function stateFilePath(jobsDir,
|
|
6340
|
-
return `${jobsDir.replace(/\/+$/, "")}/${
|
|
6298
|
+
function stateFilePath(jobsDir, slug2) {
|
|
6299
|
+
return `${jobsDir.replace(/\/+$/, "")}/${slug2}/state.json`;
|
|
6341
6300
|
}
|
|
6342
6301
|
function slugFromStateFilePath(filePath) {
|
|
6343
6302
|
if (/\/state\.json$/i.test(filePath)) {
|
|
@@ -6379,8 +6338,8 @@ var init_contentsApiBackend = __esm({
|
|
|
6379
6338
|
this.jobsDir = stateRepoJobsDir(opts.jobsDir);
|
|
6380
6339
|
this.cwd = opts.cwd;
|
|
6381
6340
|
}
|
|
6382
|
-
load(
|
|
6383
|
-
const filePath = stateFilePath(this.jobsDir,
|
|
6341
|
+
load(slug2) {
|
|
6342
|
+
const filePath = stateFilePath(this.jobsDir, slug2);
|
|
6384
6343
|
const loaded = readStateText(this.config, this.cwd, filePath);
|
|
6385
6344
|
if (!loaded) {
|
|
6386
6345
|
return { path: filePath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
@@ -6400,20 +6359,20 @@ var init_contentsApiBackend = __esm({
|
|
|
6400
6359
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
6401
6360
|
return false;
|
|
6402
6361
|
}
|
|
6403
|
-
const
|
|
6362
|
+
const slug2 = slugFromStateFilePath(loaded.path);
|
|
6404
6363
|
const body = `${JSON.stringify(next, null, 2)}
|
|
6405
6364
|
`;
|
|
6406
|
-
const message = `chore(jobs): update state for ${
|
|
6365
|
+
const message = `chore(jobs): update state for ${slug2} (rev ${next.rev})`;
|
|
6407
6366
|
const sha = typeof loaded.handle === "string" ? loaded.handle : void 0;
|
|
6408
6367
|
try {
|
|
6409
6368
|
writeStateText(this.config, this.cwd, loaded.path, body, message, sha);
|
|
6410
6369
|
} catch (err) {
|
|
6411
6370
|
if (!isShaConflict(err)) throw err;
|
|
6412
|
-
const current = this.load(
|
|
6371
|
+
const current = this.load(slug2);
|
|
6413
6372
|
if (!current.created && isStateUnchanged(current.state, next)) return false;
|
|
6414
6373
|
const currentSha = typeof current.handle === "string" ? current.handle : void 0;
|
|
6415
6374
|
process.stderr.write(
|
|
6416
|
-
`[kody] jobState: concurrent write detected for ${
|
|
6375
|
+
`[kody] jobState: concurrent write detected for ${slug2}; reloaded SHA and retrying (last-write-wins)
|
|
6417
6376
|
`
|
|
6418
6377
|
);
|
|
6419
6378
|
writeStateText(this.config, this.cwd, loaded.path, body, message, currentSha);
|
|
@@ -6540,8 +6499,8 @@ var init_localFileBackend = __esm({
|
|
|
6540
6499
|
`);
|
|
6541
6500
|
}
|
|
6542
6501
|
}
|
|
6543
|
-
load(
|
|
6544
|
-
const relPath = stateFilePath(this.jobsDir,
|
|
6502
|
+
load(slug2) {
|
|
6503
|
+
const relPath = stateFilePath(this.jobsDir, slug2);
|
|
6545
6504
|
const absPath = path24.join(this.cwd, relPath);
|
|
6546
6505
|
if (!fs25.existsSync(absPath)) {
|
|
6547
6506
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
@@ -6614,28 +6573,27 @@ function isAgentResponsibilityCadenceGoal(goal, extra) {
|
|
|
6614
6573
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.agentResponsibilities.length > 0;
|
|
6615
6574
|
}
|
|
6616
6575
|
async function planGoalAgentResponsibilitySchedule(opts) {
|
|
6617
|
-
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
6618
|
-
const at = now.toISOString();
|
|
6619
6576
|
const jobsDir = opts.jobsDir ?? ".kody/agent-responsibilities";
|
|
6620
6577
|
const jobsRoot = path25.join(opts.cwd, jobsDir);
|
|
6578
|
+
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
6579
|
+
const at = now.toISOString();
|
|
6621
6580
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
6622
6581
|
const statuses = {};
|
|
6623
6582
|
const blockers = [];
|
|
6624
|
-
for (const
|
|
6625
|
-
const agentResponsibility2 = resolveAgentResponsibilityFolder(
|
|
6583
|
+
for (const slug2 of opts.goal.agentResponsibilities) {
|
|
6584
|
+
const agentResponsibility2 = resolveAgentResponsibilityFolder(slug2, jobsRoot);
|
|
6626
6585
|
const status = await describeAgentResponsibilitySchedule(
|
|
6627
6586
|
agentResponsibility2,
|
|
6628
|
-
|
|
6587
|
+
slug2,
|
|
6629
6588
|
backend,
|
|
6630
|
-
|
|
6631
|
-
opts.previousScheduleState?.agentResponsibilities[slug]
|
|
6589
|
+
opts.previousScheduleState?.agentResponsibilities[slug2]
|
|
6632
6590
|
);
|
|
6633
|
-
statuses[
|
|
6634
|
-
if (status.state === "blocked") blockers.push(`${
|
|
6591
|
+
statuses[slug2] = status;
|
|
6592
|
+
if (status.state === "blocked") blockers.push(`${slug2}: ${status.reason}`);
|
|
6635
6593
|
}
|
|
6636
|
-
const due = opts.goal.agentResponsibilities.map((
|
|
6594
|
+
const due = opts.goal.agentResponsibilities.map((slug2) => statuses[slug2]).filter((status) => status?.state === "due").sort(compareOldestLastFired)[0];
|
|
6637
6595
|
if (!due) {
|
|
6638
|
-
const reason = blockers.length > 0 ? "no runnable
|
|
6596
|
+
const reason = blockers.length > 0 ? "no runnable agentResponsibility; blocked agentResponsibilities need attention" : "no runnable agentResponsibility";
|
|
6639
6597
|
const kind = blockers.length > 0 ? "blocked" : "idle";
|
|
6640
6598
|
return {
|
|
6641
6599
|
kind,
|
|
@@ -6682,29 +6640,19 @@ async function planGoalAgentResponsibilitySchedule(opts) {
|
|
|
6682
6640
|
}
|
|
6683
6641
|
};
|
|
6684
6642
|
}
|
|
6685
|
-
async function describeAgentResponsibilitySchedule(agentResponsibility,
|
|
6686
|
-
if (!agentResponsibility) return { slug, state: "blocked", reason: "agentResponsibility folder missing" };
|
|
6643
|
+
async function describeAgentResponsibilitySchedule(agentResponsibility, slug2, backend, previous) {
|
|
6644
|
+
if (!agentResponsibility) return { slug: slug2, state: "blocked", reason: "agentResponsibility folder missing" };
|
|
6687
6645
|
const { config } = agentResponsibility;
|
|
6688
6646
|
if (config.disabled === true) {
|
|
6689
|
-
return { slug, title: agentResponsibility.title,
|
|
6690
|
-
}
|
|
6691
|
-
if (config.every === "manual" || !config.every && !config.agent && config.agentAction) {
|
|
6692
|
-
return { slug, title: agentResponsibility.title, cadence: config.every, state: "manual", reason: "manual only" };
|
|
6647
|
+
return { slug: slug2, title: agentResponsibility.title, state: "disabled", reason: "disabled" };
|
|
6693
6648
|
}
|
|
6694
6649
|
if (!config.agent || config.agent.trim().length === 0) {
|
|
6695
|
-
return {
|
|
6696
|
-
slug,
|
|
6697
|
-
title: agentResponsibility.title,
|
|
6698
|
-
cadence: config.every,
|
|
6699
|
-
state: "blocked",
|
|
6700
|
-
reason: "no agent assigned"
|
|
6701
|
-
};
|
|
6650
|
+
return { slug: slug2, title: agentResponsibility.title, state: "blocked", reason: "no agent assigned" };
|
|
6702
6651
|
}
|
|
6703
6652
|
if (config.agentActions && config.agentActions.length > 1) {
|
|
6704
6653
|
return {
|
|
6705
|
-
slug,
|
|
6654
|
+
slug: slug2,
|
|
6706
6655
|
title: agentResponsibility.title,
|
|
6707
|
-
cadence: config.every,
|
|
6708
6656
|
state: "blocked",
|
|
6709
6657
|
reason: "multi-agentAction agentResponsibility needs task-jobs route"
|
|
6710
6658
|
};
|
|
@@ -6712,79 +6660,46 @@ async function describeAgentResponsibilitySchedule(agentResponsibility, slug, ba
|
|
|
6712
6660
|
let lastFiredAt = validIso(previous?.lastFiredAt) ? previous?.lastFiredAt : void 0;
|
|
6713
6661
|
try {
|
|
6714
6662
|
if (!lastFiredAt) {
|
|
6715
|
-
const loaded = await backend.load(
|
|
6663
|
+
const loaded = await backend.load(slug2);
|
|
6716
6664
|
const raw = loaded.state.data?.lastFiredAt;
|
|
6717
6665
|
if (typeof raw === "string" && validIso(raw)) lastFiredAt = raw;
|
|
6718
6666
|
}
|
|
6719
6667
|
} catch {
|
|
6720
6668
|
return {
|
|
6721
|
-
slug,
|
|
6722
|
-
title: agentResponsibility.title,
|
|
6723
|
-
cadence: config.every,
|
|
6724
|
-
state: "due",
|
|
6725
|
-
reason: "state unreadable; run to refresh"
|
|
6726
|
-
};
|
|
6727
|
-
}
|
|
6728
|
-
if (!config.every) {
|
|
6729
|
-
return {
|
|
6730
|
-
slug,
|
|
6669
|
+
slug: slug2,
|
|
6731
6670
|
title: agentResponsibility.title,
|
|
6732
6671
|
state: "due",
|
|
6733
|
-
reason: "
|
|
6734
|
-
lastFiredAt
|
|
6735
|
-
};
|
|
6736
|
-
}
|
|
6737
|
-
if (!lastFiredAt) {
|
|
6738
|
-
return {
|
|
6739
|
-
slug,
|
|
6740
|
-
title: agentResponsibility.title,
|
|
6741
|
-
cadence: config.every,
|
|
6742
|
-
state: "due",
|
|
6743
|
-
reason: `first check for ${config.every}`
|
|
6744
|
-
};
|
|
6745
|
-
}
|
|
6746
|
-
const last = Date.parse(lastFiredAt);
|
|
6747
|
-
const interval = scheduleEveryToMs(config.every);
|
|
6748
|
-
const next = new Date(last + interval).toISOString();
|
|
6749
|
-
if (now - last >= interval) {
|
|
6750
|
-
return {
|
|
6751
|
-
slug,
|
|
6752
|
-
title: agentResponsibility.title,
|
|
6753
|
-
cadence: config.every,
|
|
6754
|
-
state: "due",
|
|
6755
|
-
reason: `due ${config.every}`,
|
|
6756
|
-
lastFiredAt,
|
|
6757
|
-
nextEligibleAt: next
|
|
6672
|
+
reason: "state unreadable; ready for loop tick"
|
|
6758
6673
|
};
|
|
6759
6674
|
}
|
|
6760
6675
|
return {
|
|
6761
|
-
slug,
|
|
6676
|
+
slug: slug2,
|
|
6762
6677
|
title: agentResponsibility.title,
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
lastFiredAt,
|
|
6767
|
-
nextEligibleAt: next
|
|
6678
|
+
state: "due",
|
|
6679
|
+
reason: "ready for loop tick",
|
|
6680
|
+
lastFiredAt
|
|
6768
6681
|
};
|
|
6769
6682
|
}
|
|
6770
6683
|
function dutyDispatch(agentResponsibility) {
|
|
6771
6684
|
const { agentAction, cliArgs } = resolveAgentResponsibilityExecution(agentResponsibility);
|
|
6772
6685
|
return { agentResponsibility: agentResponsibility.slug, agentAction, cliArgs };
|
|
6773
6686
|
}
|
|
6687
|
+
function compareOldestLastFired(a, b) {
|
|
6688
|
+
const aTime = validIso(a.lastFiredAt) ? Date.parse(a.lastFiredAt) : Number.NEGATIVE_INFINITY;
|
|
6689
|
+
const bTime = validIso(b.lastFiredAt) ? Date.parse(b.lastFiredAt) : Number.NEGATIVE_INFINITY;
|
|
6690
|
+
return aTime - bTime;
|
|
6691
|
+
}
|
|
6774
6692
|
function validIso(value) {
|
|
6775
6693
|
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
6776
6694
|
}
|
|
6777
6695
|
function markAgentResponsibilitySelected(status, now) {
|
|
6778
|
-
|
|
6779
|
-
const nextEligibleAt = status.cadence && status.cadence !== "manual" ? new Date(now.getTime() + scheduleEveryToMs(status.cadence)).toISOString() : status.nextEligibleAt;
|
|
6780
|
-
return { ...status, lastFiredAt, nextEligibleAt };
|
|
6696
|
+
return { ...status, lastFiredAt: now.toISOString() };
|
|
6781
6697
|
}
|
|
6782
6698
|
var init_goalAgentResponsibilityScheduling = __esm({
|
|
6783
6699
|
"src/scripts/goalAgentResponsibilityScheduling.ts"() {
|
|
6784
6700
|
"use strict";
|
|
6785
6701
|
init_registry();
|
|
6786
6702
|
init_jobState();
|
|
6787
|
-
init_scheduleEvery();
|
|
6788
6703
|
}
|
|
6789
6704
|
});
|
|
6790
6705
|
|
|
@@ -6812,8 +6727,8 @@ function routeNeedsIssueFact(goal) {
|
|
|
6812
6727
|
return goal.route.some(
|
|
6813
6728
|
(step) => Object.values(step.args ?? {}).some((value) => {
|
|
6814
6729
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
6815
|
-
const
|
|
6816
|
-
return Object.keys(
|
|
6730
|
+
const record2 = value;
|
|
6731
|
+
return Object.keys(record2).length === 1 && record2.fact === "issue";
|
|
6817
6732
|
})
|
|
6818
6733
|
);
|
|
6819
6734
|
}
|
|
@@ -6907,7 +6822,8 @@ var init_advanceManagedGoal = __esm({
|
|
|
6907
6822
|
ctx.output.nextDispatch = {
|
|
6908
6823
|
agentResponsibility: decision2.dispatch.agentResponsibility,
|
|
6909
6824
|
agentAction: decision2.dispatch.agentAction,
|
|
6910
|
-
cliArgs: decision2.dispatch.cliArgs
|
|
6825
|
+
cliArgs: decision2.dispatch.cliArgs,
|
|
6826
|
+
...goal.raw.extra.saveReport === true ? { saveReport: true } : {}
|
|
6911
6827
|
};
|
|
6912
6828
|
}
|
|
6913
6829
|
ctx.output.reason = decision2.reason;
|
|
@@ -6930,7 +6846,8 @@ var init_advanceManagedGoal = __esm({
|
|
|
6930
6846
|
ctx.output.nextDispatch = {
|
|
6931
6847
|
agentResponsibility: decision.agentResponsibility,
|
|
6932
6848
|
agentAction: decision.agentAction,
|
|
6933
|
-
cliArgs: decision.cliArgs
|
|
6849
|
+
cliArgs: decision.cliArgs,
|
|
6850
|
+
...decision.saveReport === true ? { saveReport: true } : {}
|
|
6934
6851
|
};
|
|
6935
6852
|
ctx.output.reason = `dispatch ${decision.agentResponsibility} for ${decision.evidence}`;
|
|
6936
6853
|
};
|
|
@@ -6944,9 +6861,9 @@ function resolveTrigger(force) {
|
|
|
6944
6861
|
if (force || event === "issue_comment" || event === "workflow_dispatch") return "manual";
|
|
6945
6862
|
return "event";
|
|
6946
6863
|
}
|
|
6947
|
-
function appendLine(ctx,
|
|
6948
|
-
const filePath = `activity/${
|
|
6949
|
-
appendStateLine(ctx.config, ctx.cwd, filePath, JSON.stringify(
|
|
6864
|
+
function appendLine(ctx, record2) {
|
|
6865
|
+
const filePath = `activity/${record2.ts.slice(0, 10)}.jsonl`;
|
|
6866
|
+
appendStateLine(ctx.config, ctx.cwd, filePath, JSON.stringify(record2), `chore(activity): ${record2.action}`);
|
|
6950
6867
|
}
|
|
6951
6868
|
var appendCompanyActivity;
|
|
6952
6869
|
var init_appendCompanyActivity = __esm({
|
|
@@ -6962,7 +6879,7 @@ var init_appendCompanyActivity = __esm({
|
|
|
6962
6879
|
const agent = ctx.data.agentSlug || null;
|
|
6963
6880
|
const agentTitle = ctx.data.agentTitle || null;
|
|
6964
6881
|
const force = ctx.args?.force === true;
|
|
6965
|
-
const
|
|
6882
|
+
const record2 = {
|
|
6966
6883
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6967
6884
|
action: `Ran agentResponsibility: ${agentResponsibilityTitle ?? agentResponsibility}`,
|
|
6968
6885
|
agentResponsibility,
|
|
@@ -6976,7 +6893,7 @@ var init_appendCompanyActivity = __esm({
|
|
|
6976
6893
|
durationMs: agentResult?.durationMs ?? null,
|
|
6977
6894
|
runUrl: getRunUrl() || null
|
|
6978
6895
|
};
|
|
6979
|
-
appendLine(ctx,
|
|
6896
|
+
appendLine(ctx, record2);
|
|
6980
6897
|
} catch (err) {
|
|
6981
6898
|
process.stderr.write(
|
|
6982
6899
|
`[activity] company-activity append failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -6987,6 +6904,338 @@ var init_appendCompanyActivity = __esm({
|
|
|
6987
6904
|
}
|
|
6988
6905
|
});
|
|
6989
6906
|
|
|
6907
|
+
// src/companyManagerDecision.ts
|
|
6908
|
+
function parseCompanyManagerDecisionText(finalText) {
|
|
6909
|
+
const raw = extractDecisionJson(finalText);
|
|
6910
|
+
const parsed = JSON.parse(raw);
|
|
6911
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6912
|
+
throw new Error("company-manager decision must be JSON object");
|
|
6913
|
+
}
|
|
6914
|
+
const input = parsed;
|
|
6915
|
+
const actions = Array.isArray(input.actions) ? input.actions.map(parseAction) : [];
|
|
6916
|
+
return {
|
|
6917
|
+
summary: typeof input.summary === "string" ? input.summary.trim() : "",
|
|
6918
|
+
actions
|
|
6919
|
+
};
|
|
6920
|
+
}
|
|
6921
|
+
function buildManagedGoalState(action) {
|
|
6922
|
+
const at = nowIso();
|
|
6923
|
+
return {
|
|
6924
|
+
state: "active",
|
|
6925
|
+
createdAt: at,
|
|
6926
|
+
updatedAt: at,
|
|
6927
|
+
extra: {
|
|
6928
|
+
type: action.goalType ?? "release",
|
|
6929
|
+
destination: { outcome: action.outcome, evidence: action.evidence },
|
|
6930
|
+
agentResponsibilities: action.agentResponsibilities,
|
|
6931
|
+
route: action.route,
|
|
6932
|
+
facts: action.facts ?? {},
|
|
6933
|
+
blockers: [],
|
|
6934
|
+
createdByIntent: action.intentId,
|
|
6935
|
+
manager: "cto"
|
|
6936
|
+
}
|
|
6937
|
+
};
|
|
6938
|
+
}
|
|
6939
|
+
function buildAgentLoopState(action) {
|
|
6940
|
+
const at = nowIso();
|
|
6941
|
+
return {
|
|
6942
|
+
state: "active",
|
|
6943
|
+
createdAt: at,
|
|
6944
|
+
updatedAt: at,
|
|
6945
|
+
extra: {
|
|
6946
|
+
type: "agentLoop",
|
|
6947
|
+
scheduleMode: "agentLoop",
|
|
6948
|
+
schedule: action.every,
|
|
6949
|
+
destination: { outcome: action.outcome, evidence: [] },
|
|
6950
|
+
agentResponsibilities: action.agentResponsibilities,
|
|
6951
|
+
route: [],
|
|
6952
|
+
facts: {},
|
|
6953
|
+
blockers: [],
|
|
6954
|
+
createdByIntent: action.intentId,
|
|
6955
|
+
manager: "cto"
|
|
6956
|
+
}
|
|
6957
|
+
};
|
|
6958
|
+
}
|
|
6959
|
+
function extractDecisionJson(finalText) {
|
|
6960
|
+
const fence = finalText.match(/```(?:kody-company-manager-decision|json)\s*([\s\S]*?)```/i);
|
|
6961
|
+
if (fence?.[1]) return fence[1].trim();
|
|
6962
|
+
const line = finalText.match(/KODY_COMPANY_MANAGER_DECISION=(\{[\s\S]*\})/);
|
|
6963
|
+
if (line?.[1]) return line[1].trim();
|
|
6964
|
+
throw new Error("missing kody-company-manager-decision JSON");
|
|
6965
|
+
}
|
|
6966
|
+
function parseAction(value) {
|
|
6967
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6968
|
+
throw new Error("company-manager action must be object");
|
|
6969
|
+
}
|
|
6970
|
+
const input = value;
|
|
6971
|
+
const kind = input.kind;
|
|
6972
|
+
if (kind === "createManagedGoal") return parseCreateManagedGoal(input);
|
|
6973
|
+
if (kind === "createAgentLoop") return parseCreateAgentLoop(input);
|
|
6974
|
+
if (kind === "setGoalLifecycle") return parseSetGoalLifecycle(input);
|
|
6975
|
+
if (kind === "updateIntentPortfolio") return parseUpdateIntentPortfolio(input);
|
|
6976
|
+
if (kind === "note") return parseNote(input);
|
|
6977
|
+
throw new Error(`unsupported company-manager action kind: ${String(kind)}`);
|
|
6978
|
+
}
|
|
6979
|
+
function parseCreateManagedGoal(input) {
|
|
6980
|
+
const route = Array.isArray(input.route) ? input.route.map(parseRouteStep) : [];
|
|
6981
|
+
if (route.length === 0) throw new Error("createManagedGoal requires route");
|
|
6982
|
+
const evidence = stringArray2(input.evidence);
|
|
6983
|
+
if (evidence.length === 0) throw new Error("createManagedGoal requires evidence");
|
|
6984
|
+
return {
|
|
6985
|
+
kind: "createManagedGoal",
|
|
6986
|
+
intentId: slug(input.intentId, "intentId"),
|
|
6987
|
+
id: slug(input.id, "id"),
|
|
6988
|
+
outcome: requiredString(input.outcome, "outcome"),
|
|
6989
|
+
goalType: typeof input.goalType === "string" && input.goalType.trim() ? input.goalType.trim() : void 0,
|
|
6990
|
+
evidence,
|
|
6991
|
+
agentResponsibilities: nonEmptyStringArray(input.agentResponsibilities, "agentResponsibilities"),
|
|
6992
|
+
route,
|
|
6993
|
+
facts: record(input.facts) ?? {},
|
|
6994
|
+
reason: requiredString(input.reason, "reason")
|
|
6995
|
+
};
|
|
6996
|
+
}
|
|
6997
|
+
function parseCreateAgentLoop(input) {
|
|
6998
|
+
return {
|
|
6999
|
+
kind: "createAgentLoop",
|
|
7000
|
+
intentId: slug(input.intentId, "intentId"),
|
|
7001
|
+
id: slug(input.id, "id"),
|
|
7002
|
+
outcome: requiredString(input.outcome, "outcome"),
|
|
7003
|
+
every: oneOf(input.every, ["manual", "1h", "1d", "7d", "30d"], "1d"),
|
|
7004
|
+
agentResponsibilities: nonEmptyStringArray(input.agentResponsibilities, "agentResponsibilities"),
|
|
7005
|
+
reason: requiredString(input.reason, "reason")
|
|
7006
|
+
};
|
|
7007
|
+
}
|
|
7008
|
+
function parseSetGoalLifecycle(input) {
|
|
7009
|
+
return {
|
|
7010
|
+
kind: "setGoalLifecycle",
|
|
7011
|
+
intentId: slug(input.intentId, "intentId"),
|
|
7012
|
+
id: slug(input.id, "id"),
|
|
7013
|
+
state: oneOf(input.state, ["active", "closed", "abandoned"], "active"),
|
|
7014
|
+
reason: requiredString(input.reason, "reason")
|
|
7015
|
+
};
|
|
7016
|
+
}
|
|
7017
|
+
function parseUpdateIntentPortfolio(input) {
|
|
7018
|
+
return {
|
|
7019
|
+
kind: "updateIntentPortfolio",
|
|
7020
|
+
intentId: slug(input.intentId, "intentId"),
|
|
7021
|
+
goals: stringArray2(input.goals).filter(isSlug),
|
|
7022
|
+
loops: stringArray2(input.loops).filter(isSlug),
|
|
7023
|
+
responsibilities: stringArray2(input.responsibilities).filter(isSlug),
|
|
7024
|
+
reason: requiredString(input.reason, "reason")
|
|
7025
|
+
};
|
|
7026
|
+
}
|
|
7027
|
+
function parseNote(input) {
|
|
7028
|
+
return {
|
|
7029
|
+
kind: "note",
|
|
7030
|
+
intentId: typeof input.intentId === "string" && isSlug(input.intentId) ? input.intentId : void 0,
|
|
7031
|
+
message: requiredString(input.message ?? input.content, "message")
|
|
7032
|
+
};
|
|
7033
|
+
}
|
|
7034
|
+
function parseRouteStep(value) {
|
|
7035
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("route step must be object");
|
|
7036
|
+
const input = value;
|
|
7037
|
+
return {
|
|
7038
|
+
stage: requiredString(input.stage, "route.stage"),
|
|
7039
|
+
evidence: requiredString(input.evidence, "route.evidence"),
|
|
7040
|
+
agentResponsibility: slug(input.agentResponsibility, "route.agentResponsibility"),
|
|
7041
|
+
...typeof input.agentAction === "string" && input.agentAction.trim() ? { agentAction: input.agentAction.trim() } : {},
|
|
7042
|
+
...record(input.args) ? { args: record(input.args) } : {}
|
|
7043
|
+
};
|
|
7044
|
+
}
|
|
7045
|
+
function slug(value, field) {
|
|
7046
|
+
const text = requiredString(value, field);
|
|
7047
|
+
if (!isSlug(text)) throw new Error(`${field} must be lowercase slug`);
|
|
7048
|
+
return text;
|
|
7049
|
+
}
|
|
7050
|
+
function isSlug(value) {
|
|
7051
|
+
return SLUG_RE.test(value);
|
|
7052
|
+
}
|
|
7053
|
+
function requiredString(value, field) {
|
|
7054
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`${field} is required`);
|
|
7055
|
+
return value.trim();
|
|
7056
|
+
}
|
|
7057
|
+
function stringArray2(value) {
|
|
7058
|
+
if (!Array.isArray(value)) return [];
|
|
7059
|
+
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
7060
|
+
}
|
|
7061
|
+
function nonEmptyStringArray(value, field) {
|
|
7062
|
+
const values = stringArray2(value);
|
|
7063
|
+
if (values.length === 0) throw new Error(`${field} must not be empty`);
|
|
7064
|
+
return values;
|
|
7065
|
+
}
|
|
7066
|
+
function record(value) {
|
|
7067
|
+
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : null;
|
|
7068
|
+
}
|
|
7069
|
+
function oneOf(value, allowed, fallback) {
|
|
7070
|
+
return typeof value === "string" && allowed.includes(value) ? value : fallback;
|
|
7071
|
+
}
|
|
7072
|
+
var SLUG_RE;
|
|
7073
|
+
var init_companyManagerDecision = __esm({
|
|
7074
|
+
"src/companyManagerDecision.ts"() {
|
|
7075
|
+
"use strict";
|
|
7076
|
+
init_state2();
|
|
7077
|
+
SLUG_RE = /^[a-z][a-z0-9-]{0,63}$/;
|
|
7078
|
+
}
|
|
7079
|
+
});
|
|
7080
|
+
|
|
7081
|
+
// src/companyIntent.ts
|
|
7082
|
+
function isCompanyIntentId(value) {
|
|
7083
|
+
return SLUG_RE2.test(value);
|
|
7084
|
+
}
|
|
7085
|
+
function companyIntentPath(id) {
|
|
7086
|
+
assertIntentId(id);
|
|
7087
|
+
return `intents/${id}/intent.json`;
|
|
7088
|
+
}
|
|
7089
|
+
function normalizeCompanyIntent(path46, raw) {
|
|
7090
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
7091
|
+
throw new Error(`${path46}: intent must be JSON object`);
|
|
7092
|
+
}
|
|
7093
|
+
const input = raw;
|
|
7094
|
+
const id = stringField2(input.id);
|
|
7095
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path46}: invalid intent id`);
|
|
7096
|
+
const createdAt = stringField2(input.createdAt) || nowIso();
|
|
7097
|
+
const updatedAt = stringField2(input.updatedAt) || createdAt;
|
|
7098
|
+
return {
|
|
7099
|
+
version: 1,
|
|
7100
|
+
id,
|
|
7101
|
+
status: oneOf2(input.status, ["active", "paused", "archived"], "active"),
|
|
7102
|
+
for: stringField2(input.for),
|
|
7103
|
+
priority: numberField(input.priority, 100),
|
|
7104
|
+
posture: oneOf2(
|
|
7105
|
+
input.posture,
|
|
7106
|
+
["confidence", "speed", "stability-recovery", "maintenance", "balanced"],
|
|
7107
|
+
"balanced"
|
|
7108
|
+
),
|
|
7109
|
+
scope: {
|
|
7110
|
+
repos: stringArray3(recordField(input.scope)?.repos),
|
|
7111
|
+
areas: stringArray3(recordField(input.scope)?.areas)
|
|
7112
|
+
},
|
|
7113
|
+
principles: stringArray3(input.principles),
|
|
7114
|
+
metrics: stringArray3(input.metrics),
|
|
7115
|
+
policy: {
|
|
7116
|
+
release: normalizeReleasePolicy(recordField(recordField(input.policy)?.release)),
|
|
7117
|
+
automation: normalizeAutomationPolicy(recordField(recordField(input.policy)?.automation))
|
|
7118
|
+
},
|
|
7119
|
+
portfolio: {
|
|
7120
|
+
goals: stringArray3(recordField(input.portfolio)?.goals).filter(isCompanyIntentId),
|
|
7121
|
+
loops: stringArray3(recordField(input.portfolio)?.loops).filter(isCompanyIntentId),
|
|
7122
|
+
responsibilities: stringArray3(recordField(input.portfolio)?.responsibilities).filter(isCompanyIntentId)
|
|
7123
|
+
},
|
|
7124
|
+
manager: normalizeManager(recordField(input.manager)),
|
|
7125
|
+
createdAt,
|
|
7126
|
+
updatedAt
|
|
7127
|
+
};
|
|
7128
|
+
}
|
|
7129
|
+
function listCompanyIntents(config, cwd) {
|
|
7130
|
+
const entries = listStateDirectory(config, cwd, "intents");
|
|
7131
|
+
const records = [];
|
|
7132
|
+
for (const entry of entries) {
|
|
7133
|
+
if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
|
|
7134
|
+
const path46 = companyIntentPath(entry.name);
|
|
7135
|
+
const file = readStateText(config, cwd, path46);
|
|
7136
|
+
if (!file) continue;
|
|
7137
|
+
records.push({
|
|
7138
|
+
id: entry.name,
|
|
7139
|
+
path: file.path,
|
|
7140
|
+
intent: normalizeCompanyIntent(file.path, JSON.parse(file.content))
|
|
7141
|
+
});
|
|
7142
|
+
}
|
|
7143
|
+
return records.sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
|
|
7144
|
+
}
|
|
7145
|
+
function readCompanyIntent(config, cwd, id) {
|
|
7146
|
+
const path46 = companyIntentPath(id);
|
|
7147
|
+
const file = readStateText(config, cwd, path46);
|
|
7148
|
+
if (!file) return null;
|
|
7149
|
+
return { id, path: file.path, intent: normalizeCompanyIntent(file.path, JSON.parse(file.content)) };
|
|
7150
|
+
}
|
|
7151
|
+
function writeCompanyIntent(config, cwd, intent, message = `chore(intents): update ${intent.id}`) {
|
|
7152
|
+
upsertStateText(config, cwd, companyIntentPath(intent.id), `${JSON.stringify(intent, null, 2)}
|
|
7153
|
+
`, message);
|
|
7154
|
+
}
|
|
7155
|
+
function appendCompanyIntentDecision(config, cwd, intentId, entry) {
|
|
7156
|
+
assertIntentId(intentId);
|
|
7157
|
+
appendStateLine(config, cwd, `intents/${intentId}/decisions.jsonl`, JSON.stringify(entry), `chore(intents): log ${intentId} decision`);
|
|
7158
|
+
}
|
|
7159
|
+
function listCompanyPortfolio(config, cwd) {
|
|
7160
|
+
const entries = listStateDirectory(config, cwd, "goals/instances");
|
|
7161
|
+
const goals = [];
|
|
7162
|
+
for (const entry of entries) {
|
|
7163
|
+
if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
|
|
7164
|
+
const file = readStateText(config, cwd, `goals/instances/${entry.name}/state.json`);
|
|
7165
|
+
if (!file) continue;
|
|
7166
|
+
const state = parseGoalState(file.path, JSON.parse(file.content));
|
|
7167
|
+
const destination = recordField(state.extra.destination);
|
|
7168
|
+
goals.push({
|
|
7169
|
+
id: entry.name,
|
|
7170
|
+
state: state.state,
|
|
7171
|
+
type: stringField2(state.extra.type) || void 0,
|
|
7172
|
+
outcome: stringField2(destination?.outcome) || void 0,
|
|
7173
|
+
agentResponsibilities: stringArray3(state.extra.agentResponsibilities),
|
|
7174
|
+
isLoop: state.extra.scheduleMode === "agentLoop" || state.extra.type === "agentLoop",
|
|
7175
|
+
updatedAt: state.updatedAt
|
|
7176
|
+
});
|
|
7177
|
+
}
|
|
7178
|
+
return { goals: goals.sort((a, b) => a.id.localeCompare(b.id)) };
|
|
7179
|
+
}
|
|
7180
|
+
function writeCompanyGoalState(config, cwd, id, state, message) {
|
|
7181
|
+
assertIntentId(id);
|
|
7182
|
+
upsertStateText(config, cwd, `goals/instances/${id}/state.json`, serializeGoalState(state), message);
|
|
7183
|
+
}
|
|
7184
|
+
function assertIntentId(id) {
|
|
7185
|
+
if (!isCompanyIntentId(id)) throw new Error(`invalid intent/portfolio id: ${id}`);
|
|
7186
|
+
}
|
|
7187
|
+
function stringField2(value) {
|
|
7188
|
+
return typeof value === "string" ? value.trim() : "";
|
|
7189
|
+
}
|
|
7190
|
+
function numberField(value, fallback) {
|
|
7191
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
7192
|
+
}
|
|
7193
|
+
function recordField(value) {
|
|
7194
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7195
|
+
}
|
|
7196
|
+
function stringArray3(value) {
|
|
7197
|
+
if (!Array.isArray(value)) return [];
|
|
7198
|
+
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
7199
|
+
}
|
|
7200
|
+
function oneOf2(value, allowed, fallback) {
|
|
7201
|
+
return typeof value === "string" && allowed.includes(value) ? value : fallback;
|
|
7202
|
+
}
|
|
7203
|
+
function normalizeReleasePolicy(raw) {
|
|
7204
|
+
if (!raw) return void 0;
|
|
7205
|
+
return {
|
|
7206
|
+
cadence: oneOf2(raw.cadence, ["manual", "1d", "1w"], "manual"),
|
|
7207
|
+
qaDepth: oneOf2(raw.qaDepth, ["light", "standard", "strict"], "standard"),
|
|
7208
|
+
blockerLevel: oneOf2(raw.blockerLevel, ["low", "standard", "strict"], "standard"),
|
|
7209
|
+
approval: oneOf2(raw.approval, ["none", "before-production", "before-risky-actions"], "before-risky-actions")
|
|
7210
|
+
};
|
|
7211
|
+
}
|
|
7212
|
+
function normalizeAutomationPolicy(raw) {
|
|
7213
|
+
return {
|
|
7214
|
+
authority: "full-auto",
|
|
7215
|
+
maxConcurrentGoals: Math.max(1, Math.floor(numberField(raw?.maxConcurrentGoals, 1))),
|
|
7216
|
+
maxDailyActions: Math.max(1, Math.floor(numberField(raw?.maxDailyActions, 6))),
|
|
7217
|
+
requiresHumanFor: stringArray3(raw?.requiresHumanFor)
|
|
7218
|
+
};
|
|
7219
|
+
}
|
|
7220
|
+
function normalizeManager(raw) {
|
|
7221
|
+
return {
|
|
7222
|
+
agent: "cto",
|
|
7223
|
+
loop: "company-manager-loop",
|
|
7224
|
+
responsibility: "company-manager",
|
|
7225
|
+
reviewEvery: oneOf2(raw?.reviewEvery, ["1d", "1w"], "1d"),
|
|
7226
|
+
...typeof raw?.lastReviewedAt === "string" ? { lastReviewedAt: raw.lastReviewedAt } : {}
|
|
7227
|
+
};
|
|
7228
|
+
}
|
|
7229
|
+
var SLUG_RE2;
|
|
7230
|
+
var init_companyIntent = __esm({
|
|
7231
|
+
"src/companyIntent.ts"() {
|
|
7232
|
+
"use strict";
|
|
7233
|
+
init_state2();
|
|
7234
|
+
init_stateRepo();
|
|
7235
|
+
SLUG_RE2 = /^[a-z][a-z0-9-]{0,63}$/;
|
|
7236
|
+
}
|
|
7237
|
+
});
|
|
7238
|
+
|
|
6990
7239
|
// src/goal/stateStore.ts
|
|
6991
7240
|
function statePath(goalId) {
|
|
6992
7241
|
return `goals/instances/${goalId}/state.json`;
|
|
@@ -7008,6 +7257,133 @@ var init_stateStore = __esm({
|
|
|
7008
7257
|
}
|
|
7009
7258
|
});
|
|
7010
7259
|
|
|
7260
|
+
// src/scripts/applyCompanyManagerDecision.ts
|
|
7261
|
+
function applyAction(config, cwd, action) {
|
|
7262
|
+
if (action.kind === "createManagedGoal") {
|
|
7263
|
+
const existing = fetchGoalState(config, action.id, cwd);
|
|
7264
|
+
if (existing) return applied(action, false, "goal already exists");
|
|
7265
|
+
writeCompanyGoalState(config, cwd, action.id, buildManagedGoalState(action), `chore(goals): create ${action.id} from intent ${action.intentId}`);
|
|
7266
|
+
return applied(action, true, action.reason, action.id);
|
|
7267
|
+
}
|
|
7268
|
+
if (action.kind === "createAgentLoop") {
|
|
7269
|
+
const existing = fetchGoalState(config, action.id, cwd);
|
|
7270
|
+
if (existing) return applied(action, false, "loop already exists");
|
|
7271
|
+
writeCompanyGoalState(config, cwd, action.id, buildAgentLoopState(action), `chore(goals): create loop ${action.id} from intent ${action.intentId}`);
|
|
7272
|
+
return applied(action, true, action.reason, action.id);
|
|
7273
|
+
}
|
|
7274
|
+
if (action.kind === "setGoalLifecycle") {
|
|
7275
|
+
const state = fetchGoalState(config, action.id, cwd);
|
|
7276
|
+
if (!state) return applied(action, false, "goal/loop missing", action.id);
|
|
7277
|
+
const before = state.state;
|
|
7278
|
+
if (before === action.state) return applied(action, false, "state already set", action.id);
|
|
7279
|
+
const next = {
|
|
7280
|
+
...state,
|
|
7281
|
+
state: action.state,
|
|
7282
|
+
updatedAt: nowIso(),
|
|
7283
|
+
extra: {
|
|
7284
|
+
...state.extra,
|
|
7285
|
+
lifecycleChangedByIntent: action.intentId,
|
|
7286
|
+
lifecycleChangeReason: action.reason
|
|
7287
|
+
}
|
|
7288
|
+
};
|
|
7289
|
+
writeCompanyGoalState(config, cwd, action.id, next, `chore(goals): ${action.state} ${action.id} from intent ${action.intentId}`);
|
|
7290
|
+
return applied(action, true, action.reason, action.id);
|
|
7291
|
+
}
|
|
7292
|
+
if (action.kind === "updateIntentPortfolio") {
|
|
7293
|
+
const record2 = readCompanyIntent(config, cwd, action.intentId);
|
|
7294
|
+
if (!record2) return applied(action, false, "intent missing");
|
|
7295
|
+
const intent = {
|
|
7296
|
+
...record2.intent,
|
|
7297
|
+
portfolio: {
|
|
7298
|
+
goals: mergeUnique(record2.intent.portfolio.goals, action.goals ?? []),
|
|
7299
|
+
loops: mergeUnique(record2.intent.portfolio.loops, action.loops ?? []),
|
|
7300
|
+
responsibilities: mergeUnique(record2.intent.portfolio.responsibilities, action.responsibilities ?? [])
|
|
7301
|
+
},
|
|
7302
|
+
updatedAt: nowIso()
|
|
7303
|
+
};
|
|
7304
|
+
writeCompanyIntent(config, cwd, intent, `chore(intents): update ${action.intentId} portfolio`);
|
|
7305
|
+
return applied(action, true, action.reason);
|
|
7306
|
+
}
|
|
7307
|
+
if (action.kind === "note") {
|
|
7308
|
+
return {
|
|
7309
|
+
kind: action.kind,
|
|
7310
|
+
intentId: action.intentId,
|
|
7311
|
+
changed: false,
|
|
7312
|
+
reason: action.message
|
|
7313
|
+
};
|
|
7314
|
+
}
|
|
7315
|
+
return { kind: "unknown", changed: false, reason: "unsupported action" };
|
|
7316
|
+
}
|
|
7317
|
+
function applied(action, changed, reason, resource) {
|
|
7318
|
+
return {
|
|
7319
|
+
kind: action.kind,
|
|
7320
|
+
intentId: "intentId" in action ? action.intentId : void 0,
|
|
7321
|
+
resource,
|
|
7322
|
+
changed,
|
|
7323
|
+
reason
|
|
7324
|
+
};
|
|
7325
|
+
}
|
|
7326
|
+
function mergeUnique(left, right) {
|
|
7327
|
+
return [.../* @__PURE__ */ new Set([...left, ...right])].sort();
|
|
7328
|
+
}
|
|
7329
|
+
function logAppliedCompanyManagerActions(config, cwd, appliedActions) {
|
|
7330
|
+
const at = nowIso();
|
|
7331
|
+
for (const action of appliedActions) {
|
|
7332
|
+
if (!action.intentId) continue;
|
|
7333
|
+
appendCompanyIntentDecision(config, cwd, action.intentId, {
|
|
7334
|
+
at,
|
|
7335
|
+
agent: "cto",
|
|
7336
|
+
intentId: action.intentId,
|
|
7337
|
+
action: action.kind,
|
|
7338
|
+
reason: action.reason,
|
|
7339
|
+
after: { changed: action.changed },
|
|
7340
|
+
resources: action.resource ? [action.resource] : []
|
|
7341
|
+
});
|
|
7342
|
+
}
|
|
7343
|
+
}
|
|
7344
|
+
var applyCompanyManagerDecision;
|
|
7345
|
+
var init_applyCompanyManagerDecision = __esm({
|
|
7346
|
+
"src/scripts/applyCompanyManagerDecision.ts"() {
|
|
7347
|
+
"use strict";
|
|
7348
|
+
init_companyManagerDecision();
|
|
7349
|
+
init_companyIntent();
|
|
7350
|
+
init_stateStore();
|
|
7351
|
+
init_state2();
|
|
7352
|
+
applyCompanyManagerDecision = async (ctx) => {
|
|
7353
|
+
const decision = ctx.data.companyManagerDecision;
|
|
7354
|
+
if (!decision || !Array.isArray(decision.actions)) return;
|
|
7355
|
+
if (ctx.output.exitCode !== 0) return;
|
|
7356
|
+
const applied2 = [];
|
|
7357
|
+
for (const action of decision.actions) {
|
|
7358
|
+
applied2.push(applyAction(ctx.config, ctx.cwd, action));
|
|
7359
|
+
}
|
|
7360
|
+
ctx.data.companyManagerApplied = applied2;
|
|
7361
|
+
ctx.data.companyManagerApplySummary = `company-manager applied ${applied2.filter((item) => item.changed).length}/${applied2.length} action(s)`;
|
|
7362
|
+
};
|
|
7363
|
+
}
|
|
7364
|
+
});
|
|
7365
|
+
|
|
7366
|
+
// src/scripts/appendCompanyIntentDecision.ts
|
|
7367
|
+
var appendCompanyIntentDecision2;
|
|
7368
|
+
var init_appendCompanyIntentDecision = __esm({
|
|
7369
|
+
"src/scripts/appendCompanyIntentDecision.ts"() {
|
|
7370
|
+
"use strict";
|
|
7371
|
+
init_applyCompanyManagerDecision();
|
|
7372
|
+
appendCompanyIntentDecision2 = async (ctx) => {
|
|
7373
|
+
const applied2 = ctx.data.companyManagerApplied;
|
|
7374
|
+
if (!applied2 || applied2.length === 0) return;
|
|
7375
|
+
try {
|
|
7376
|
+
logAppliedCompanyManagerActions(ctx.config, ctx.cwd, applied2);
|
|
7377
|
+
} catch (err) {
|
|
7378
|
+
process.stderr.write(
|
|
7379
|
+
`[company-manager] failed append intent decision log: ${err instanceof Error ? err.message : String(err)}
|
|
7380
|
+
`
|
|
7381
|
+
);
|
|
7382
|
+
}
|
|
7383
|
+
};
|
|
7384
|
+
}
|
|
7385
|
+
});
|
|
7386
|
+
|
|
7011
7387
|
// src/scripts/applyAgentResponsibilityReports.ts
|
|
7012
7388
|
function collectReports(raw, agentResult) {
|
|
7013
7389
|
const out = [];
|
|
@@ -8214,7 +8590,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
8214
8590
|
const content = fs29.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
8215
8591
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
8216
8592
|
if (!slugMatch) continue;
|
|
8217
|
-
const
|
|
8593
|
+
const slug2 = slugMatch[1];
|
|
8218
8594
|
const name = file.replace(/\.(ts|tsx)$/, "");
|
|
8219
8595
|
const fields = [];
|
|
8220
8596
|
const fieldMatches = content.matchAll(/name:\s*['"]([a-zA-Z_][a-zA-Z0-9_]*)['"]/g);
|
|
@@ -8224,7 +8600,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
8224
8600
|
const hasAdmin = /components:\s*\{/.test(content) || /Field:\s*['"]/.test(content) || /Cell:\s*['"]/.test(content) || /views:\s*\{/.test(content);
|
|
8225
8601
|
out.push({
|
|
8226
8602
|
name,
|
|
8227
|
-
slug,
|
|
8603
|
+
slug: slug2,
|
|
8228
8604
|
filePath: path29.relative(cwd, filePath),
|
|
8229
8605
|
fields: fields.slice(0, 20),
|
|
8230
8606
|
hasAdmin
|
|
@@ -8621,425 +8997,34 @@ var init_dispatch = __esm({
|
|
|
8621
8997
|
};
|
|
8622
8998
|
ctx.data.action = action;
|
|
8623
8999
|
if (state) state.core.lastOutcome = action;
|
|
8624
|
-
return;
|
|
8625
|
-
}
|
|
8626
|
-
if (state?.flow) {
|
|
8627
|
-
state.flow.step = next;
|
|
8628
|
-
}
|
|
8629
|
-
const usePr = target === "pr" && state?.core.prUrl;
|
|
8630
|
-
const targetNumber = usePr ? parsePr(state.core.prUrl) ?? issueNumber : issueNumber;
|
|
8631
|
-
ctx.output.nextDispatch = {
|
|
8632
|
-
action: next,
|
|
8633
|
-
cliArgs: usePr ? { pr: targetNumber } : { issue: targetNumber }
|
|
8634
|
-
};
|
|
8635
|
-
};
|
|
8636
|
-
}
|
|
8637
|
-
});
|
|
8638
|
-
|
|
8639
|
-
// src/jobIdentity.ts
|
|
8640
|
-
function stableJobKey(job) {
|
|
8641
|
-
const agentResponsibility = job.agentResponsibility ?? job.action;
|
|
8642
|
-
const agentAction = job.agentAction ?? agentResponsibility ?? "unknown";
|
|
8643
|
-
if (job.flavor === "scheduled" && job.agentResponsibility)
|
|
8644
|
-
return `scheduled:${job.agentResponsibility}:${agentAction}`;
|
|
8645
|
-
const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
|
|
8646
|
-
const work = agentResponsibility && agentAction && agentAction !== agentResponsibility ? `${agentResponsibility}:${agentAction}` : agentResponsibility ?? agentAction;
|
|
8647
|
-
return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
|
|
8648
|
-
}
|
|
8649
|
-
function targetFromCliArgs(cliArgs) {
|
|
8650
|
-
if (!cliArgs) return void 0;
|
|
8651
|
-
for (const key of ["issue", "pr", "target", "issue_number"]) {
|
|
8652
|
-
const value = cliArgs[key];
|
|
8653
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
8654
|
-
}
|
|
8655
|
-
return void 0;
|
|
8656
|
-
}
|
|
8657
|
-
var init_jobIdentity = __esm({
|
|
8658
|
-
"src/jobIdentity.ts"() {
|
|
8659
|
-
"use strict";
|
|
8660
|
-
}
|
|
8661
|
-
});
|
|
8662
|
-
|
|
8663
|
-
// src/scripts/planTaskJobs.ts
|
|
8664
|
-
function parseTaskJobSpecs(body) {
|
|
8665
|
-
const match = body.match(new RegExp(`<!--\\s*${TASK_JOBS_MARKER}\\s*([\\s\\S]*?)-->`));
|
|
8666
|
-
if (!match) return [];
|
|
8667
|
-
let parsed;
|
|
8668
|
-
try {
|
|
8669
|
-
parsed = JSON.parse(match[1].trim());
|
|
8670
|
-
} catch (err) {
|
|
8671
|
-
throw new Error(`task job plan is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
8672
|
-
}
|
|
8673
|
-
if (!Array.isArray(parsed)) throw new Error("task job plan must be a JSON array");
|
|
8674
|
-
return parsed.map((entry, index) => normalizeSpec(entry, index));
|
|
8675
|
-
}
|
|
8676
|
-
function taskJobSpecToJob(spec, issueNumber) {
|
|
8677
|
-
const cliArgs = spec.cliArgs ?? { issue: issueNumber };
|
|
8678
|
-
const target = typeof spec.target === "number" ? spec.target : targetFromCliArgs(cliArgs) ?? issueNumber;
|
|
8679
|
-
return {
|
|
8680
|
-
agentResponsibility: spec.agentResponsibility ?? spec.agentAction,
|
|
8681
|
-
agentAction: spec.agentAction,
|
|
8682
|
-
why: spec.reason,
|
|
8683
|
-
agent: spec.agent,
|
|
8684
|
-
schedule: spec.schedule,
|
|
8685
|
-
target,
|
|
8686
|
-
cliArgs,
|
|
8687
|
-
flavor: spec.flavor ?? "instant"
|
|
8688
|
-
};
|
|
8689
|
-
}
|
|
8690
|
-
function normalizeSpec(input, index) {
|
|
8691
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
8692
|
-
throw new Error(`task job plan entry ${index} must be an object`);
|
|
8693
|
-
}
|
|
8694
|
-
const raw = input;
|
|
8695
|
-
const agentAction = typeof raw.agentAction === "string" ? raw.agentAction.trim() : "";
|
|
8696
|
-
if (!/^[a-z][a-z0-9-]*$/.test(agentAction)) {
|
|
8697
|
-
throw new Error(`task job plan entry ${index} must have a valid agentAction`);
|
|
8698
|
-
}
|
|
8699
|
-
const cliArgs = raw.cliArgs;
|
|
8700
|
-
if (cliArgs !== void 0 && (!cliArgs || typeof cliArgs !== "object" || Array.isArray(cliArgs))) {
|
|
8701
|
-
throw new Error(`task job plan entry ${index} cliArgs must be an object`);
|
|
8702
|
-
}
|
|
8703
|
-
const flavor = raw.flavor;
|
|
8704
|
-
if (flavor !== void 0 && flavor !== "instant" && flavor !== "scheduled") {
|
|
8705
|
-
throw new Error(`task job plan entry ${index} flavor must be "instant" or "scheduled"`);
|
|
8706
|
-
}
|
|
8707
|
-
return {
|
|
8708
|
-
agentAction,
|
|
8709
|
-
...typeof raw.agentResponsibility === "string" && raw.agentResponsibility.trim() ? { agentResponsibility: raw.agentResponsibility.trim() } : {},
|
|
8710
|
-
...typeof raw.reason === "string" && raw.reason.trim() ? { reason: raw.reason.trim() } : {},
|
|
8711
|
-
...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
|
|
8712
|
-
...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
|
|
8713
|
-
...cliArgs ? { cliArgs } : {},
|
|
8714
|
-
...typeof raw.target === "number" && Number.isFinite(raw.target) ? { target: raw.target } : {},
|
|
8715
|
-
...flavor === "instant" || flavor === "scheduled" ? { flavor } : {},
|
|
8716
|
-
...typeof raw.schedule === "string" && raw.schedule.trim() ? { schedule: raw.schedule.trim() } : {}
|
|
8717
|
-
};
|
|
8718
|
-
}
|
|
8719
|
-
function jobToPlannedTaskJob(job) {
|
|
8720
|
-
return {
|
|
8721
|
-
id: stableJobKey(job),
|
|
8722
|
-
agentAction: job.agentAction ?? job.agentResponsibility ?? "unknown",
|
|
8723
|
-
agentResponsibility: job.agentResponsibility ?? job.action ?? job.agentAction ?? "unknown",
|
|
8724
|
-
...job.agent ? { agent: job.agent } : {},
|
|
8725
|
-
...job.flavor ? { flavor: job.flavor } : {},
|
|
8726
|
-
...job.schedule ? { schedule: job.schedule } : {},
|
|
8727
|
-
...typeof job.target === "number" ? { target: job.target } : {},
|
|
8728
|
-
...job.why ? { reason: job.why } : {}
|
|
8729
|
-
};
|
|
8730
|
-
}
|
|
8731
|
-
function assertUniqueJobIds(planned) {
|
|
8732
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8733
|
-
for (const job of planned) {
|
|
8734
|
-
if (seen.has(job.id)) throw new Error(`duplicate planned task job id: ${job.id}`);
|
|
8735
|
-
seen.add(job.id);
|
|
8736
|
-
}
|
|
8737
|
-
}
|
|
8738
|
-
var TASK_JOBS_MARKER, planTaskJobs;
|
|
8739
|
-
var init_planTaskJobs = __esm({
|
|
8740
|
-
"src/scripts/planTaskJobs.ts"() {
|
|
8741
|
-
"use strict";
|
|
8742
|
-
init_jobIdentity();
|
|
8743
|
-
init_state();
|
|
8744
|
-
TASK_JOBS_MARKER = "kody:task-jobs:v1";
|
|
8745
|
-
planTaskJobs = async (ctx) => {
|
|
8746
|
-
const issueNumber = ctx.args.issue;
|
|
8747
|
-
if (!issueNumber) {
|
|
8748
|
-
ctx.skipAgent = true;
|
|
8749
|
-
ctx.output.exitCode = 64;
|
|
8750
|
-
ctx.output.reason = "planTaskJobs requires --issue";
|
|
8751
|
-
return;
|
|
8752
|
-
}
|
|
8753
|
-
const issue = ctx.data.issue;
|
|
8754
|
-
const specs = parseTaskJobSpecs(issue?.body ?? "");
|
|
8755
|
-
if (specs.length === 0) {
|
|
8756
|
-
ctx.skipAgent = true;
|
|
8757
|
-
ctx.output.exitCode = 64;
|
|
8758
|
-
ctx.output.reason = `no ${TASK_JOBS_MARKER} block found on issue #${issueNumber}`;
|
|
8759
|
-
return;
|
|
8760
|
-
}
|
|
8761
|
-
const jobs = specs.map((spec) => taskJobSpecToJob(spec, issueNumber));
|
|
8762
|
-
const planned = jobs.map(jobToPlannedTaskJob);
|
|
8763
|
-
assertUniqueJobIds(planned);
|
|
8764
|
-
const prior = ctx.data.taskState ?? emptyState();
|
|
8765
|
-
const next = upsertTaskJobs(prior, planned, (/* @__PURE__ */ new Date()).toISOString());
|
|
8766
|
-
ctx.data.taskState = next;
|
|
8767
|
-
ctx.data.plannedTaskJobs = jobs;
|
|
8768
|
-
ctx.data.plannedTaskJobIds = planned.map((job) => job.id);
|
|
8769
|
-
const target = ctx.data.commentTargetType;
|
|
8770
|
-
const number = ctx.data.commentTargetNumber;
|
|
8771
|
-
if (target && number) writeTaskState(target, number, next, ctx.cwd, ctx.config);
|
|
8772
|
-
};
|
|
8773
|
-
}
|
|
8774
|
-
});
|
|
8775
|
-
|
|
8776
|
-
// src/scripts/dispatchAgentResponsibilityFileTicks.ts
|
|
8777
|
-
import * as path31 from "path";
|
|
8778
|
-
async function decideShouldFire(every, slug, backend, now) {
|
|
8779
|
-
if (!every) return { skip: false, reason: "no schedule (every cron tick)" };
|
|
8780
|
-
if (every === "manual") {
|
|
8781
|
-
return { skip: true, reason: "manual-only (no auto-fire; trigger via dashboard Run now)" };
|
|
8782
|
-
}
|
|
8783
|
-
let lastFiredAt = null;
|
|
8784
|
-
try {
|
|
8785
|
-
const loaded = await backend.load(slug);
|
|
8786
|
-
const raw = loaded.state.data?.lastFiredAt;
|
|
8787
|
-
if (typeof raw === "string") {
|
|
8788
|
-
const ms = Date.parse(raw);
|
|
8789
|
-
if (!Number.isNaN(ms)) lastFiredAt = ms;
|
|
8790
|
-
}
|
|
8791
|
-
} catch {
|
|
8792
|
-
return { skip: false, reason: "state unreadable; firing" };
|
|
8793
|
-
}
|
|
8794
|
-
if (lastFiredAt === null) {
|
|
8795
|
-
return { skip: false, reason: `first tick (every ${every})` };
|
|
8796
|
-
}
|
|
8797
|
-
const intervalMs = scheduleEveryToMs(every);
|
|
8798
|
-
const elapsedMs = now - lastFiredAt;
|
|
8799
|
-
if (elapsedMs >= intervalMs) {
|
|
8800
|
-
return { skip: false, reason: `due (every ${every}, last ${formatAgo(elapsedMs)} ago)` };
|
|
8801
|
-
}
|
|
8802
|
-
const remainingMs = intervalMs - elapsedMs;
|
|
8803
|
-
return {
|
|
8804
|
-
skip: true,
|
|
8805
|
-
reason: `every ${every}; ${formatAgo(elapsedMs)} since last tick, next in ${formatAgo(remainingMs)}`
|
|
8806
|
-
};
|
|
8807
|
-
}
|
|
8808
|
-
function formatAgo(ms) {
|
|
8809
|
-
const sec = Math.max(0, Math.round(ms / 1e3));
|
|
8810
|
-
if (sec < 60) return `${sec}s`;
|
|
8811
|
-
const min = Math.round(sec / 60);
|
|
8812
|
-
if (min < 60) return `${min}m`;
|
|
8813
|
-
const hr = Math.round(min / 60);
|
|
8814
|
-
if (hr < 48) return `${hr}h`;
|
|
8815
|
-
const day = Math.round(hr / 24);
|
|
8816
|
-
return `${day}d`;
|
|
8817
|
-
}
|
|
8818
|
-
function parseAgentResponsibilityFilter(raw) {
|
|
8819
|
-
return typeof raw === "string" && raw.trim().length > 0 ? raw.trim() : void 0;
|
|
8820
|
-
}
|
|
8821
|
-
function filterSlugs(slugs, onlyAgentResponsibility) {
|
|
8822
|
-
return onlyAgentResponsibility ? slugs.filter((slug) => slug === onlyAgentResponsibility) : slugs;
|
|
8823
|
-
}
|
|
8824
|
-
function listActivatedAgentResponsibilitySlugs(projectRoot, storeRoot, activeStoreAgentResponsibilities) {
|
|
8825
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8826
|
-
const out = [];
|
|
8827
|
-
for (const slug of listAgentResponsibilityFolderSlugs(projectRoot)) {
|
|
8828
|
-
if (seen.has(slug)) continue;
|
|
8829
|
-
seen.add(slug);
|
|
8830
|
-
out.push(slug);
|
|
8831
|
-
}
|
|
8832
|
-
const active = new Set(activeStoreAgentResponsibilities ?? []);
|
|
8833
|
-
if (storeRoot && active.size > 0) {
|
|
8834
|
-
for (const slug of listAgentResponsibilityFolderSlugs(storeRoot)) {
|
|
8835
|
-
if (!active.has(slug) || seen.has(slug)) continue;
|
|
8836
|
-
seen.add(slug);
|
|
8837
|
-
out.push(slug);
|
|
8838
|
-
}
|
|
8839
|
-
}
|
|
8840
|
-
return out.sort();
|
|
8841
|
-
}
|
|
8842
|
-
function createAgentResponsibilityTaskIssue(opts) {
|
|
8843
|
-
const title = `AgentResponsibility ${opts.slug} - multi-agentAction task`;
|
|
8844
|
-
const body = buildAgentResponsibilityTaskIssueBody(opts.slug, opts.body, opts.config);
|
|
8845
|
-
const out = gh(["issue", "create", "--title", title, "--body-file", "-"], { input: body, cwd: opts.cwd });
|
|
8846
|
-
const url = out.split("\n").map((line) => line.trim()).filter(Boolean).pop() ?? "";
|
|
8847
|
-
const match = url.match(/\/issues\/(\d+)\b/);
|
|
8848
|
-
if (!match) throw new Error(`gh issue create returned unexpected output: ${out}`);
|
|
8849
|
-
return { number: Number(match[1]), url };
|
|
8850
|
-
}
|
|
8851
|
-
function buildAgentResponsibilityTaskIssueBody(slug, agentResponsibilityBody, config) {
|
|
8852
|
-
const specs = (config.agentActions ?? []).map((agentAction) => ({
|
|
8853
|
-
agentAction,
|
|
8854
|
-
agentResponsibility: slug,
|
|
8855
|
-
...config.agent ? { agent: config.agent } : {},
|
|
8856
|
-
reason: `AgentResponsibility \`${slug}\` slice for \`${agentAction}\`.`,
|
|
8857
|
-
flavor: "scheduled",
|
|
8858
|
-
...config.every ? { schedule: config.every } : {}
|
|
8859
|
-
}));
|
|
8860
|
-
return [
|
|
8861
|
-
`# AgentResponsibility task: ${slug}`,
|
|
8862
|
-
"",
|
|
8863
|
-
agentResponsibilityBody.trim() || "(no agentResponsibility body)",
|
|
8864
|
-
"",
|
|
8865
|
-
`<!-- ${TASK_JOBS_MARKER}`,
|
|
8866
|
-
JSON.stringify(specs, null, 2),
|
|
8867
|
-
"-->",
|
|
8868
|
-
""
|
|
8869
|
-
].join("\n");
|
|
8870
|
-
}
|
|
8871
|
-
async function stampFired(backend, slug, now, task) {
|
|
8872
|
-
try {
|
|
8873
|
-
const loaded = await backend.load(slug);
|
|
8874
|
-
const nextData = {
|
|
8875
|
-
...loaded.state.data ?? {},
|
|
8876
|
-
lastFiredAt: new Date(now).toISOString(),
|
|
8877
|
-
...task ? { lastTaskIssue: task.number, lastTaskUrl: task.url } : {}
|
|
8878
|
-
};
|
|
8879
|
-
await backend.save(loaded, { ...loaded.state, data: nextData });
|
|
8880
|
-
} catch (err) {
|
|
8881
|
-
process.stderr.write(`[jobs] failed to stamp lastFiredAt for ${slug}: ${String(err)}
|
|
8882
|
-
`);
|
|
8883
|
-
}
|
|
8884
|
-
}
|
|
8885
|
-
var dispatchAgentResponsibilityFileTicks;
|
|
8886
|
-
var init_dispatchAgentResponsibilityFileTicks = __esm({
|
|
8887
|
-
"src/scripts/dispatchAgentResponsibilityFileTicks.ts"() {
|
|
8888
|
-
"use strict";
|
|
8889
|
-
init_agent_responsibilityFolders();
|
|
8890
|
-
init_issue();
|
|
8891
|
-
init_job();
|
|
8892
|
-
init_registry();
|
|
8893
|
-
init_jobState();
|
|
8894
|
-
init_planTaskJobs();
|
|
8895
|
-
init_scheduleEvery();
|
|
8896
|
-
dispatchAgentResponsibilityFileTicks = async (ctx, _profile, args) => {
|
|
8897
|
-
ctx.skipAgent = true;
|
|
8898
|
-
const targetAgentAction = String(args?.targetAgentAction ?? "");
|
|
8899
|
-
if (!targetAgentAction) {
|
|
8900
|
-
throw new Error("dispatchAgentResponsibilityFileTicks: `with.targetAgentAction` is required");
|
|
8901
|
-
}
|
|
8902
|
-
const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
|
|
8903
|
-
const scriptedAgentAction = String(args?.scriptedAgentAction ?? "agent-responsibility-tick-scripted");
|
|
8904
|
-
const slugArg = String(args?.slugArg ?? "agentResponsibility");
|
|
8905
|
-
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
8906
|
-
if (backend.hydrate) {
|
|
8907
|
-
await backend.hydrate();
|
|
8908
|
-
}
|
|
8909
|
-
try {
|
|
8910
|
-
const onlyAgentResponsibility = parseAgentResponsibilityFilter(ctx.args.agentResponsibility);
|
|
8911
|
-
if (args?.requireExplicitAgentResponsibility === true && !onlyAgentResponsibility) {
|
|
8912
|
-
ctx.output.exitCode = 0;
|
|
8913
|
-
ctx.output.reason = "scheduled agentResponsibility fan-out is owned by goal-scheduler";
|
|
8914
|
-
process.stdout.write(
|
|
8915
|
-
"[jobs] no flat agentResponsibility fan-out; goal-scheduler owns scheduled agentResponsibility decisions\n"
|
|
8916
|
-
);
|
|
8917
|
-
return;
|
|
8918
|
-
}
|
|
8919
|
-
const jobsPath = path31.join(ctx.cwd, jobsDir);
|
|
8920
|
-
const storeJobsPath = getCompanyStoreAgentResponsibilitiesRoot();
|
|
8921
|
-
const slugs = filterSlugs(
|
|
8922
|
-
listActivatedAgentResponsibilitySlugs(jobsPath, storeJobsPath, ctx.config.company?.activeAgentResponsibilities),
|
|
8923
|
-
onlyAgentResponsibility
|
|
8924
|
-
);
|
|
8925
|
-
ctx.data.jobSlugCount = slugs.length;
|
|
8926
|
-
if (slugs.length === 0) {
|
|
8927
|
-
const filter = onlyAgentResponsibility ? ` matching ${onlyAgentResponsibility}` : "";
|
|
8928
|
-
process.stdout.write(`[jobs] no agentResponsibility folders${filter} in ${jobsDir}
|
|
8929
|
-
`);
|
|
8930
|
-
return;
|
|
8931
|
-
}
|
|
8932
|
-
const filtered = onlyAgentResponsibility ? ` matching ${onlyAgentResponsibility}` : "";
|
|
8933
|
-
process.stdout.write(
|
|
8934
|
-
`[jobs] ticking ${slugs.length} agent responsibility/ies${filtered} via ${targetAgentAction}
|
|
8935
|
-
`
|
|
8936
|
-
);
|
|
8937
|
-
const results = [];
|
|
8938
|
-
const now = Date.now();
|
|
8939
|
-
for (const slug of slugs) {
|
|
8940
|
-
const agentResponsibility = resolveAgentResponsibilityFolder(slug, jobsPath);
|
|
8941
|
-
if (!agentResponsibility) {
|
|
8942
|
-
process.stderr.write(
|
|
8943
|
-
`[jobs] \u23ED skip ${slug}: agentResponsibility folder is missing profile.json or agent-responsibility.md
|
|
8944
|
-
`
|
|
8945
|
-
);
|
|
8946
|
-
results.push({ slug, exitCode: 0, skipped: true, reason: "incomplete agentResponsibility folder" });
|
|
8947
|
-
continue;
|
|
8948
|
-
}
|
|
8949
|
-
const config = agentResponsibility.config;
|
|
8950
|
-
if (config.disabled === true) {
|
|
8951
|
-
process.stdout.write(`[jobs] \u23ED skip ${slug}: disabled in profile.json
|
|
8952
|
-
`);
|
|
8953
|
-
results.push({ slug, exitCode: 0, skipped: true, reason: "disabled" });
|
|
8954
|
-
continue;
|
|
8955
|
-
}
|
|
8956
|
-
if (!config.agent || config.agent.trim().length === 0) {
|
|
8957
|
-
process.stderr.write(`[jobs] \u23ED skip ${slug}: no agent assigned (add "agent" to profile.json)
|
|
8958
|
-
`);
|
|
8959
|
-
results.push({ slug, exitCode: 0, skipped: true, reason: "no agent assigned" });
|
|
8960
|
-
continue;
|
|
8961
|
-
}
|
|
8962
|
-
const decision = await decideShouldFire(config.every, slug, backend, now);
|
|
8963
|
-
if (decision.skip) {
|
|
8964
|
-
process.stdout.write(`[jobs] \u23ED skip ${slug}: ${decision.reason}
|
|
8965
|
-
`);
|
|
8966
|
-
results.push({ slug, exitCode: 0, skipped: true, reason: decision.reason });
|
|
8967
|
-
continue;
|
|
8968
|
-
}
|
|
8969
|
-
if (config.agentActions && config.agentActions.length > 0) {
|
|
8970
|
-
try {
|
|
8971
|
-
const task = createAgentResponsibilityTaskIssue({
|
|
8972
|
-
slug,
|
|
8973
|
-
body: agentResponsibility.body,
|
|
8974
|
-
config,
|
|
8975
|
-
cwd: ctx.cwd
|
|
8976
|
-
});
|
|
8977
|
-
await stampFired(backend, slug, now, task);
|
|
8978
|
-
process.stdout.write(`[jobs] \u2192 run ${slug} multi-agentAction task #${task.number} (task-jobs)
|
|
8979
|
-
`);
|
|
8980
|
-
const out = await runJob(
|
|
8981
|
-
mintScheduledJob({
|
|
8982
|
-
agentResponsibility: slug,
|
|
8983
|
-
agentAction: "task-jobs",
|
|
8984
|
-
schedule: config.every,
|
|
8985
|
-
agent: config.agent,
|
|
8986
|
-
cliArgs: { issue: task.number }
|
|
8987
|
-
}),
|
|
8988
|
-
{ cwd: ctx.cwd, config: ctx.config, verbose: ctx.verbose, quiet: ctx.quiet }
|
|
8989
|
-
);
|
|
8990
|
-
results.push({ slug, exitCode: out.exitCode, reason: out.reason });
|
|
8991
|
-
if (out.exitCode !== 0) {
|
|
8992
|
-
process.stderr.write(`[jobs] task ${slug} failed (exit ${out.exitCode}): ${out.reason ?? ""}
|
|
8993
|
-
`);
|
|
8994
|
-
}
|
|
8995
|
-
} catch (err) {
|
|
8996
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
8997
|
-
process.stderr.write(`[jobs] task ${slug} crashed: ${msg}
|
|
8998
|
-
`);
|
|
8999
|
-
results.push({ slug, exitCode: 99, reason: msg });
|
|
9000
|
-
}
|
|
9001
|
-
continue;
|
|
9002
|
-
}
|
|
9003
|
-
const slugTarget = config.tickScript ? scriptedAgentAction : config.agentAction ?? targetAgentAction;
|
|
9004
|
-
const cliArgs = config.agentAction && !config.tickScript ? {} : { [slugArg]: slug };
|
|
9005
|
-
process.stdout.write(`[jobs] \u2192 tick ${slug} (${slugTarget})
|
|
9006
|
-
`);
|
|
9007
|
-
try {
|
|
9008
|
-
const out = await runJob(
|
|
9009
|
-
mintScheduledJob({
|
|
9010
|
-
agentResponsibility: slug,
|
|
9011
|
-
agentAction: slugTarget,
|
|
9012
|
-
schedule: config.every,
|
|
9013
|
-
agent: config.agent,
|
|
9014
|
-
cliArgs
|
|
9015
|
-
}),
|
|
9016
|
-
{ cwd: ctx.cwd, config: ctx.config, verbose: ctx.verbose, quiet: ctx.quiet, chain: false }
|
|
9017
|
-
);
|
|
9018
|
-
results.push({ slug, exitCode: out.exitCode, reason: out.reason });
|
|
9019
|
-
if (out.exitCode !== 0) {
|
|
9020
|
-
process.stderr.write(`[jobs] tick ${slug} failed (exit ${out.exitCode}): ${out.reason ?? ""}
|
|
9021
|
-
`);
|
|
9022
|
-
}
|
|
9023
|
-
} catch (err) {
|
|
9024
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
9025
|
-
process.stderr.write(`[jobs] tick ${slug} crashed: ${msg}
|
|
9026
|
-
`);
|
|
9027
|
-
results.push({ slug, exitCode: 99, reason: msg });
|
|
9028
|
-
}
|
|
9029
|
-
}
|
|
9030
|
-
ctx.data.jobTickResults = results;
|
|
9031
|
-
ctx.output.exitCode = 0;
|
|
9032
|
-
} finally {
|
|
9033
|
-
if (backend.persist) {
|
|
9034
|
-
try {
|
|
9035
|
-
await backend.persist();
|
|
9036
|
-
} catch (err) {
|
|
9037
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
9038
|
-
process.stderr.write(`[jobs] backend persist failed: ${msg}
|
|
9039
|
-
`);
|
|
9040
|
-
}
|
|
9041
|
-
}
|
|
9000
|
+
return;
|
|
9001
|
+
}
|
|
9002
|
+
if (state?.flow) {
|
|
9003
|
+
state.flow.step = next;
|
|
9042
9004
|
}
|
|
9005
|
+
const usePr = target === "pr" && state?.core.prUrl;
|
|
9006
|
+
const targetNumber = usePr ? parsePr(state.core.prUrl) ?? issueNumber : issueNumber;
|
|
9007
|
+
ctx.output.nextDispatch = {
|
|
9008
|
+
action: next,
|
|
9009
|
+
cliArgs: usePr ? { pr: targetNumber } : { issue: targetNumber }
|
|
9010
|
+
};
|
|
9011
|
+
};
|
|
9012
|
+
}
|
|
9013
|
+
});
|
|
9014
|
+
|
|
9015
|
+
// src/scripts/dispatchAgentResponsibilityFileTicks.ts
|
|
9016
|
+
var dispatchAgentResponsibilityFileTicks;
|
|
9017
|
+
var init_dispatchAgentResponsibilityFileTicks = __esm({
|
|
9018
|
+
"src/scripts/dispatchAgentResponsibilityFileTicks.ts"() {
|
|
9019
|
+
"use strict";
|
|
9020
|
+
dispatchAgentResponsibilityFileTicks = async (ctx) => {
|
|
9021
|
+
ctx.skipAgent = true;
|
|
9022
|
+
ctx.data.jobTickResults = [];
|
|
9023
|
+
ctx.output.exitCode = 0;
|
|
9024
|
+
ctx.output.reason = "responsibility scheduling is owned by goals and loops";
|
|
9025
|
+
process.stdout.write(
|
|
9026
|
+
"[jobs] no flat agentResponsibility fan-out; goals and loops own scheduled responsibility decisions\n"
|
|
9027
|
+
);
|
|
9043
9028
|
};
|
|
9044
9029
|
}
|
|
9045
9030
|
});
|
|
@@ -9147,6 +9132,30 @@ var init_dispatchClassified = __esm({
|
|
|
9147
9132
|
}
|
|
9148
9133
|
});
|
|
9149
9134
|
|
|
9135
|
+
// src/jobIdentity.ts
|
|
9136
|
+
function stableJobKey(job) {
|
|
9137
|
+
const agentResponsibility = job.agentResponsibility ?? job.action;
|
|
9138
|
+
const agentAction = job.agentAction ?? agentResponsibility ?? "unknown";
|
|
9139
|
+
if (job.flavor === "scheduled" && job.agentResponsibility)
|
|
9140
|
+
return `scheduled:${job.agentResponsibility}:${agentAction}`;
|
|
9141
|
+
const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
|
|
9142
|
+
const work = agentResponsibility && agentAction && agentAction !== agentResponsibility ? `${agentResponsibility}:${agentAction}` : agentResponsibility ?? agentAction;
|
|
9143
|
+
return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
|
|
9144
|
+
}
|
|
9145
|
+
function targetFromCliArgs(cliArgs) {
|
|
9146
|
+
if (!cliArgs) return void 0;
|
|
9147
|
+
for (const key of ["issue", "pr", "target", "issue_number"]) {
|
|
9148
|
+
const value = cliArgs[key];
|
|
9149
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
9150
|
+
}
|
|
9151
|
+
return void 0;
|
|
9152
|
+
}
|
|
9153
|
+
var init_jobIdentity = __esm({
|
|
9154
|
+
"src/jobIdentity.ts"() {
|
|
9155
|
+
"use strict";
|
|
9156
|
+
}
|
|
9157
|
+
});
|
|
9158
|
+
|
|
9150
9159
|
// src/scripts/dispatchNextTaskJob.ts
|
|
9151
9160
|
function taskJobToJob(job, issueArg) {
|
|
9152
9161
|
const target = typeof job.target === "number" ? job.target : typeof issueArg === "number" ? issueArg : void 0;
|
|
@@ -9669,8 +9678,8 @@ function git3(args, cwd) {
|
|
|
9669
9678
|
}).trim();
|
|
9670
9679
|
}
|
|
9671
9680
|
function deriveBranchName(issueNumber, title) {
|
|
9672
|
-
const
|
|
9673
|
-
return
|
|
9681
|
+
const slug2 = title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 50).replace(/-$/, "");
|
|
9682
|
+
return slug2 ? `${issueNumber}-${slug2}` : `${issueNumber}-task`;
|
|
9674
9683
|
}
|
|
9675
9684
|
function getCurrentBranch(cwd) {
|
|
9676
9685
|
return git3(["branch", "--show-current"], cwd);
|
|
@@ -10076,11 +10085,11 @@ var init_fixFlow = __esm({
|
|
|
10076
10085
|
// src/scripts/initFlow.ts
|
|
10077
10086
|
import { execFileSync as execFileSync15 } from "child_process";
|
|
10078
10087
|
import * as fs31 from "fs";
|
|
10079
|
-
import * as
|
|
10088
|
+
import * as path31 from "path";
|
|
10080
10089
|
function detectPackageManager(cwd) {
|
|
10081
|
-
if (fs31.existsSync(
|
|
10082
|
-
if (fs31.existsSync(
|
|
10083
|
-
if (fs31.existsSync(
|
|
10090
|
+
if (fs31.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
10091
|
+
if (fs31.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
|
|
10092
|
+
if (fs31.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
|
|
10084
10093
|
return "npm";
|
|
10085
10094
|
}
|
|
10086
10095
|
function qualityCommandsFor(pm) {
|
|
@@ -10152,7 +10161,7 @@ function performInit(cwd, force) {
|
|
|
10152
10161
|
const pm = detectPackageManager(cwd);
|
|
10153
10162
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
10154
10163
|
const defaultBranch2 = defaultBranchFromGit(cwd);
|
|
10155
|
-
const configPath =
|
|
10164
|
+
const configPath = path31.join(cwd, "kody.config.json");
|
|
10156
10165
|
if (fs31.existsSync(configPath) && !force) {
|
|
10157
10166
|
skipped.push("kody.config.json");
|
|
10158
10167
|
} else {
|
|
@@ -10161,8 +10170,8 @@ function performInit(cwd, force) {
|
|
|
10161
10170
|
`);
|
|
10162
10171
|
wrote.push("kody.config.json");
|
|
10163
10172
|
}
|
|
10164
|
-
const workflowDir =
|
|
10165
|
-
const workflowPath =
|
|
10173
|
+
const workflowDir = path31.join(cwd, ".github", "workflows");
|
|
10174
|
+
const workflowPath = path31.join(workflowDir, "kody.yml");
|
|
10166
10175
|
if (fs31.existsSync(workflowPath) && !force) {
|
|
10167
10176
|
skipped.push(".github/workflows/kody.yml");
|
|
10168
10177
|
} else {
|
|
@@ -10170,8 +10179,8 @@ function performInit(cwd, force) {
|
|
|
10170
10179
|
fs31.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
10171
10180
|
wrote.push(".github/workflows/kody.yml");
|
|
10172
10181
|
}
|
|
10173
|
-
const agentsDir =
|
|
10174
|
-
const agentPath =
|
|
10182
|
+
const agentsDir = path31.join(cwd, ".kody", "agents");
|
|
10183
|
+
const agentPath = path31.join(agentsDir, "kody.md");
|
|
10175
10184
|
if (fs31.existsSync(agentPath) && !force) {
|
|
10176
10185
|
skipped.push(".kody/agents/kody.md");
|
|
10177
10186
|
} else {
|
|
@@ -10187,7 +10196,7 @@ function performInit(cwd, force) {
|
|
|
10187
10196
|
continue;
|
|
10188
10197
|
}
|
|
10189
10198
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
10190
|
-
const target =
|
|
10199
|
+
const target = path31.join(workflowDir, `kody-${exe.name}.yml`);
|
|
10191
10200
|
if (fs31.existsSync(target) && !force) {
|
|
10192
10201
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
10193
10202
|
continue;
|
|
@@ -10385,7 +10394,7 @@ function stripDirective(body) {
|
|
|
10385
10394
|
}
|
|
10386
10395
|
return lines.slice(start).join("\n").trim();
|
|
10387
10396
|
}
|
|
10388
|
-
function parseAgentFile(raw,
|
|
10397
|
+
function parseAgentFile(raw, slug2) {
|
|
10389
10398
|
const stripped = stripLeadingFrontmatter(raw);
|
|
10390
10399
|
const trimmed = stripped.trim();
|
|
10391
10400
|
const firstLine2 = trimmed.split("\n", 1)[0] ?? "";
|
|
@@ -10394,14 +10403,14 @@ function parseAgentFile(raw, slug) {
|
|
|
10394
10403
|
const rest = trimmed.slice(firstLine2.length).replace(/^\n+/, "");
|
|
10395
10404
|
return { title: h1[1].trim(), body: rest };
|
|
10396
10405
|
}
|
|
10397
|
-
return { title: humanizeSlug2(
|
|
10406
|
+
return { title: humanizeSlug2(slug2), body: trimmed };
|
|
10398
10407
|
}
|
|
10399
10408
|
function stripLeadingFrontmatter(raw) {
|
|
10400
10409
|
const match = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/.exec(raw);
|
|
10401
10410
|
return match ? raw.slice(match[0].length) : raw;
|
|
10402
10411
|
}
|
|
10403
|
-
function humanizeSlug2(
|
|
10404
|
-
return
|
|
10412
|
+
function humanizeSlug2(slug2) {
|
|
10413
|
+
return slug2.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
|
|
10405
10414
|
}
|
|
10406
10415
|
var loadAgentAdhoc;
|
|
10407
10416
|
var init_loadAgentAdhoc = __esm({
|
|
@@ -10444,19 +10453,19 @@ var init_loadAgentResponsibilityState = __esm({
|
|
|
10444
10453
|
AGENT_RESPONSIBILITY_TOOL_PALETTE = new Set(AGENT_RESPONSIBILITY_MCP_TOOL_NAMES);
|
|
10445
10454
|
loadAgentResponsibilityState = async (ctx, profile, args) => {
|
|
10446
10455
|
const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
|
|
10447
|
-
const
|
|
10456
|
+
const slug2 = profile.name;
|
|
10448
10457
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
10449
10458
|
if (backend.hydrate) await backend.hydrate();
|
|
10450
|
-
const loaded = await backend.load(
|
|
10451
|
-
ctx.data.jobSlug =
|
|
10459
|
+
const loaded = await backend.load(slug2);
|
|
10460
|
+
ctx.data.jobSlug = slug2;
|
|
10452
10461
|
ctx.data.jobState = loaded;
|
|
10453
10462
|
ctx.data.jobStateJson = JSON.stringify(loaded.state, null, 2);
|
|
10454
|
-
ctx.data.agentResponsibilitySlug =
|
|
10463
|
+
ctx.data.agentResponsibilitySlug = slug2;
|
|
10455
10464
|
ctx.data.agentResponsibilityTitle = profile.describe;
|
|
10456
10465
|
ctx.data.agentActionSlug = profile.agentAction ?? profile.name;
|
|
10457
10466
|
ctx.data.agentSlug = profile.agent ?? "";
|
|
10458
10467
|
ctx.data.agentTitle = "";
|
|
10459
|
-
ctx.data.agentResponsibilitySchedule =
|
|
10468
|
+
ctx.data.agentResponsibilitySchedule = String(ctx.data.jobSchedule ?? "");
|
|
10460
10469
|
const mentions = (profile.mentions ?? []).map((l) => `@${l}`).join(" ");
|
|
10461
10470
|
ctx.data.mentions = mentions;
|
|
10462
10471
|
const declaredTools = profile.agentResponsibilityTools ?? [];
|
|
@@ -10464,7 +10473,7 @@ var init_loadAgentResponsibilityState = __esm({
|
|
|
10464
10473
|
const unknown = declaredTools.filter((name) => !AGENT_RESPONSIBILITY_TOOL_PALETTE.has(name));
|
|
10465
10474
|
if (unknown.length > 0) {
|
|
10466
10475
|
throw new Error(
|
|
10467
|
-
`loadAgentResponsibilityState: agentResponsibility '${
|
|
10476
|
+
`loadAgentResponsibilityState: agentResponsibility '${slug2}' declared agentResponsibilityTools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
|
|
10468
10477
|
);
|
|
10469
10478
|
}
|
|
10470
10479
|
ctx.data.agentResponsibilityTools = declaredTools;
|
|
@@ -10478,6 +10487,43 @@ var init_loadAgentResponsibilityState = __esm({
|
|
|
10478
10487
|
}
|
|
10479
10488
|
});
|
|
10480
10489
|
|
|
10490
|
+
// src/scripts/loadCompanyIntents.ts
|
|
10491
|
+
var loadCompanyIntents;
|
|
10492
|
+
var init_loadCompanyIntents = __esm({
|
|
10493
|
+
"src/scripts/loadCompanyIntents.ts"() {
|
|
10494
|
+
"use strict";
|
|
10495
|
+
init_companyIntent();
|
|
10496
|
+
loadCompanyIntents = async (ctx) => {
|
|
10497
|
+
const intents = listCompanyIntents(ctx.config, ctx.cwd);
|
|
10498
|
+
const active = intents.filter((record2) => record2.intent.status === "active");
|
|
10499
|
+
ctx.data.companyIntents = intents;
|
|
10500
|
+
ctx.data.companyActiveIntents = active;
|
|
10501
|
+
ctx.data.companyIntentsJson = JSON.stringify(
|
|
10502
|
+
active.map((record2) => record2.intent),
|
|
10503
|
+
null,
|
|
10504
|
+
2
|
|
10505
|
+
);
|
|
10506
|
+
if (active.length === 0) {
|
|
10507
|
+
ctx.output.reason = "no active company intents";
|
|
10508
|
+
}
|
|
10509
|
+
};
|
|
10510
|
+
}
|
|
10511
|
+
});
|
|
10512
|
+
|
|
10513
|
+
// src/scripts/loadCompanyPortfolio.ts
|
|
10514
|
+
var loadCompanyPortfolio;
|
|
10515
|
+
var init_loadCompanyPortfolio = __esm({
|
|
10516
|
+
"src/scripts/loadCompanyPortfolio.ts"() {
|
|
10517
|
+
"use strict";
|
|
10518
|
+
init_companyIntent();
|
|
10519
|
+
loadCompanyPortfolio = async (ctx) => {
|
|
10520
|
+
const portfolio = listCompanyPortfolio(ctx.config, ctx.cwd);
|
|
10521
|
+
ctx.data.companyPortfolio = portfolio;
|
|
10522
|
+
ctx.data.companyPortfolioJson = JSON.stringify(portfolio, null, 2);
|
|
10523
|
+
};
|
|
10524
|
+
}
|
|
10525
|
+
});
|
|
10526
|
+
|
|
10481
10527
|
// src/scripts/loadGoalState.ts
|
|
10482
10528
|
function retryDelaysMs() {
|
|
10483
10529
|
const raw = process.env.KODY_GOAL_STATE_RETRY_DELAYS_MS?.trim();
|
|
@@ -10620,8 +10666,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
10620
10666
|
|
|
10621
10667
|
// src/scripts/loadJobFromFile.ts
|
|
10622
10668
|
import * as fs33 from "fs";
|
|
10623
|
-
import * as
|
|
10624
|
-
function parseJobFile(raw,
|
|
10669
|
+
import * as path32 from "path";
|
|
10670
|
+
function parseJobFile(raw, slug2) {
|
|
10625
10671
|
let stripped = raw;
|
|
10626
10672
|
if (stripped.startsWith("---\n")) {
|
|
10627
10673
|
const end = stripped.indexOf("\n---\n", 4);
|
|
@@ -10636,10 +10682,10 @@ function parseJobFile(raw, slug) {
|
|
|
10636
10682
|
const rest = trimmed.slice(firstLine2.length).replace(/^\n+/, "");
|
|
10637
10683
|
return { title: h1[1].trim(), body: rest };
|
|
10638
10684
|
}
|
|
10639
|
-
return { title: humanizeSlug3(
|
|
10685
|
+
return { title: humanizeSlug3(slug2), body: trimmed };
|
|
10640
10686
|
}
|
|
10641
|
-
function humanizeSlug3(
|
|
10642
|
-
return
|
|
10687
|
+
function humanizeSlug3(slug2) {
|
|
10688
|
+
return slug2.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
|
|
10643
10689
|
}
|
|
10644
10690
|
var AGENT_RESPONSIBILITY_TOOL_PALETTE2, loadJobFromFile;
|
|
10645
10691
|
var init_loadJobFromFile = __esm({
|
|
@@ -10654,14 +10700,14 @@ var init_loadJobFromFile = __esm({
|
|
|
10654
10700
|
const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
|
|
10655
10701
|
const agentsDir = String(args?.agentsDir ?? ".kody/agents");
|
|
10656
10702
|
const slugArg = String(args?.slugArg ?? "job");
|
|
10657
|
-
const
|
|
10658
|
-
if (!
|
|
10703
|
+
const slug2 = String(ctx.args[slugArg] ?? "").trim();
|
|
10704
|
+
if (!slug2) {
|
|
10659
10705
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
10660
10706
|
}
|
|
10661
|
-
const agentResponsibility = resolveAgentResponsibilityFolder(
|
|
10707
|
+
const agentResponsibility = resolveAgentResponsibilityFolder(slug2, path32.join(ctx.cwd, jobsDir));
|
|
10662
10708
|
if (!agentResponsibility) {
|
|
10663
10709
|
throw new Error(
|
|
10664
|
-
`loadJobFromFile: agentResponsibility folder not found or incomplete: ${
|
|
10710
|
+
`loadJobFromFile: agentResponsibility folder not found or incomplete: ${path32.join(ctx.cwd, jobsDir, slug2)}`
|
|
10665
10711
|
);
|
|
10666
10712
|
}
|
|
10667
10713
|
const { title, body, config } = agentResponsibility;
|
|
@@ -10673,7 +10719,7 @@ var init_loadJobFromFile = __esm({
|
|
|
10673
10719
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
10674
10720
|
if (!fs33.existsSync(agentPath)) {
|
|
10675
10721
|
throw new Error(
|
|
10676
|
-
`loadJobFromFile: agentResponsibility '${
|
|
10722
|
+
`loadJobFromFile: agentResponsibility '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
10677
10723
|
);
|
|
10678
10724
|
}
|
|
10679
10725
|
const agentRaw = fs33.readFileSync(agentPath, "utf-8");
|
|
@@ -10682,28 +10728,28 @@ var init_loadJobFromFile = __esm({
|
|
|
10682
10728
|
agentIdentity = parsed.body;
|
|
10683
10729
|
}
|
|
10684
10730
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
10685
|
-
const loaded = await backend.load(
|
|
10686
|
-
ctx.data.jobSlug =
|
|
10731
|
+
const loaded = await backend.load(slug2);
|
|
10732
|
+
ctx.data.jobSlug = slug2;
|
|
10687
10733
|
ctx.data.jobTitle = title;
|
|
10688
|
-
ctx.data.jobIntent = body.replace(/\{\{\s*mentions\s*\}\}/g, mentions).replace(/\{\{\s*agentResponsibility\s*\}\}/g,
|
|
10734
|
+
ctx.data.jobIntent = body.replace(/\{\{\s*mentions\s*\}\}/g, mentions).replace(/\{\{\s*agentResponsibility\s*\}\}/g, slug2);
|
|
10689
10735
|
ctx.data.jobState = loaded;
|
|
10690
10736
|
ctx.data.jobStateJson = JSON.stringify(loaded.state, null, 2);
|
|
10691
10737
|
ctx.data.agentSlug = agentSlug;
|
|
10692
10738
|
ctx.data.agentTitle = agentTitle;
|
|
10693
10739
|
ctx.data.agentIdentity = agentIdentity;
|
|
10694
10740
|
ctx.data.mentions = mentions;
|
|
10695
|
-
ctx.data.agentResponsibilitySlug =
|
|
10741
|
+
ctx.data.agentResponsibilitySlug = slug2;
|
|
10696
10742
|
ctx.data.agentResponsibilityTitle = title;
|
|
10697
10743
|
ctx.data.agentSlug = agentSlug;
|
|
10698
10744
|
ctx.data.agentTitle = agentTitle;
|
|
10699
10745
|
ctx.data.agentActionSlug = profile.name;
|
|
10700
|
-
ctx.data.agentResponsibilitySchedule =
|
|
10746
|
+
ctx.data.agentResponsibilitySchedule = String(ctx.data.jobSchedule ?? "");
|
|
10701
10747
|
const declaredTools = config.tools ?? [];
|
|
10702
10748
|
if (declaredTools.length > 0) {
|
|
10703
10749
|
const unknown = declaredTools.filter((name) => !AGENT_RESPONSIBILITY_TOOL_PALETTE2.has(name));
|
|
10704
10750
|
if (unknown.length > 0) {
|
|
10705
10751
|
throw new Error(
|
|
10706
|
-
`loadJobFromFile: agentResponsibility '${
|
|
10752
|
+
`loadJobFromFile: agentResponsibility '${slug2}' declared tools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
|
|
10707
10753
|
);
|
|
10708
10754
|
}
|
|
10709
10755
|
const mcpToolNames = declaredTools.map((name) => `mcp__kody-agent-responsibility__${name}`);
|
|
@@ -10751,9 +10797,9 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
10751
10797
|
|
|
10752
10798
|
// src/scripts/kodyVariables.ts
|
|
10753
10799
|
import * as fs34 from "fs";
|
|
10754
|
-
import * as
|
|
10800
|
+
import * as path33 from "path";
|
|
10755
10801
|
function readKodyVariables(cwd) {
|
|
10756
|
-
const full =
|
|
10802
|
+
const full = path33.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
10757
10803
|
let raw;
|
|
10758
10804
|
try {
|
|
10759
10805
|
raw = fs34.readFileSync(full, "utf-8");
|
|
@@ -10782,7 +10828,7 @@ var init_kodyVariables = __esm({
|
|
|
10782
10828
|
|
|
10783
10829
|
// src/scripts/loadQaContext.ts
|
|
10784
10830
|
import * as fs35 from "fs";
|
|
10785
|
-
import * as
|
|
10831
|
+
import * as path34 from "path";
|
|
10786
10832
|
function parseSlugList(value) {
|
|
10787
10833
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
10788
10834
|
return inner.split(",").map(
|
|
@@ -10811,7 +10857,7 @@ function readProfileAgents(raw) {
|
|
|
10811
10857
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
10812
10858
|
}
|
|
10813
10859
|
function readProfile(cwd) {
|
|
10814
|
-
const dir =
|
|
10860
|
+
const dir = path34.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
10815
10861
|
if (!fs35.existsSync(dir)) return "";
|
|
10816
10862
|
let entries;
|
|
10817
10863
|
try {
|
|
@@ -10822,7 +10868,7 @@ function readProfile(cwd) {
|
|
|
10822
10868
|
const blocks = [];
|
|
10823
10869
|
for (const file of entries) {
|
|
10824
10870
|
try {
|
|
10825
|
-
const raw = fs35.readFileSync(
|
|
10871
|
+
const raw = fs35.readFileSync(path34.join(dir, file), "utf-8");
|
|
10826
10872
|
const { agent, body } = readProfileAgents(raw);
|
|
10827
10873
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
10828
10874
|
blocks.push(`## ${file}
|
|
@@ -10869,7 +10915,7 @@ var init_loadQaContext = __esm({
|
|
|
10869
10915
|
|
|
10870
10916
|
// src/taskContext.ts
|
|
10871
10917
|
import * as fs36 from "fs";
|
|
10872
|
-
import * as
|
|
10918
|
+
import * as path35 from "path";
|
|
10873
10919
|
function buildTaskContext(args) {
|
|
10874
10920
|
return {
|
|
10875
10921
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -10886,7 +10932,7 @@ function persistTaskContext(cwd, ctx) {
|
|
|
10886
10932
|
try {
|
|
10887
10933
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
10888
10934
|
fs36.mkdirSync(dir, { recursive: true });
|
|
10889
|
-
const file =
|
|
10935
|
+
const file = path35.join(dir, "task-context.json");
|
|
10890
10936
|
fs36.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
10891
10937
|
`);
|
|
10892
10938
|
return file;
|
|
@@ -11303,8 +11349,8 @@ function parseAgentFactoryBundle(raw) {
|
|
|
11303
11349
|
return { title, summary, files };
|
|
11304
11350
|
}
|
|
11305
11351
|
function buildAgentFactoryBranchName(issueNumber, title, now = Date.now()) {
|
|
11306
|
-
const
|
|
11307
|
-
const suffix =
|
|
11352
|
+
const slug2 = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48).replace(/-+$/g, "");
|
|
11353
|
+
const suffix = slug2 ? `-${slug2}` : "";
|
|
11308
11354
|
return `agent-factory/issue-${issueNumber}-${now.toString(36)}${suffix}`;
|
|
11309
11355
|
}
|
|
11310
11356
|
function normalizeBundleFiles(ctx, bundle) {
|
|
@@ -11537,21 +11583,21 @@ var init_openQaIssue = __esm({
|
|
|
11537
11583
|
ctx.data.action = failedAction3(reason);
|
|
11538
11584
|
return;
|
|
11539
11585
|
}
|
|
11540
|
-
const
|
|
11541
|
-
if (!
|
|
11586
|
+
const reportBody2 = agentResult.finalText.trim();
|
|
11587
|
+
if (!reportBody2) {
|
|
11542
11588
|
process.stderr.write("qa-engineer: agent produced no report body\n");
|
|
11543
11589
|
ctx.output.exitCode = 1;
|
|
11544
11590
|
ctx.output.reason = "empty report body";
|
|
11545
11591
|
ctx.data.action = failedAction3("empty report body");
|
|
11546
11592
|
return;
|
|
11547
11593
|
}
|
|
11548
|
-
const verdict = detectVerdict(
|
|
11594
|
+
const verdict = detectVerdict(reportBody2);
|
|
11549
11595
|
ctx.data.qaVerdict = verdict;
|
|
11550
|
-
ctx.data.qaReport =
|
|
11596
|
+
ctx.data.qaReport = reportBody2;
|
|
11551
11597
|
const existingIssue = ctx.args.issue;
|
|
11552
11598
|
if (typeof existingIssue === "number" && Number.isFinite(existingIssue) && existingIssue > 0) {
|
|
11553
11599
|
try {
|
|
11554
|
-
postIssueComment(existingIssue,
|
|
11600
|
+
postIssueComment(existingIssue, reportBody2, ctx.cwd);
|
|
11555
11601
|
} catch (err) {
|
|
11556
11602
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11557
11603
|
ctx.output.exitCode = 4;
|
|
@@ -11573,7 +11619,7 @@ QA_REPORT_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.gith
|
|
|
11573
11619
|
const hasLabel = ensureLabel2(ctx.cwd);
|
|
11574
11620
|
let created;
|
|
11575
11621
|
try {
|
|
11576
|
-
created = createQaIssue(title,
|
|
11622
|
+
created = createQaIssue(title, reportBody2, hasLabel, ctx.cwd);
|
|
11577
11623
|
} catch (err) {
|
|
11578
11624
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11579
11625
|
ctx.output.exitCode = 4;
|
|
@@ -11636,6 +11682,39 @@ var init_parseAgentResult = __esm({
|
|
|
11636
11682
|
}
|
|
11637
11683
|
});
|
|
11638
11684
|
|
|
11685
|
+
// src/scripts/parseCompanyManagerDecision.ts
|
|
11686
|
+
function makeAction3(type, payload) {
|
|
11687
|
+
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11688
|
+
}
|
|
11689
|
+
var parseCompanyManagerDecision;
|
|
11690
|
+
var init_parseCompanyManagerDecision = __esm({
|
|
11691
|
+
"src/scripts/parseCompanyManagerDecision.ts"() {
|
|
11692
|
+
"use strict";
|
|
11693
|
+
init_companyManagerDecision();
|
|
11694
|
+
parseCompanyManagerDecision = async (ctx, _profile, agentResult) => {
|
|
11695
|
+
if (!agentResult) {
|
|
11696
|
+
ctx.data.companyManagerDecision = { summary: "", actions: [] };
|
|
11697
|
+
ctx.data.action = makeAction3("COMPANY_MANAGER_NOT_RUN", { reason: "no agent result" });
|
|
11698
|
+
return;
|
|
11699
|
+
}
|
|
11700
|
+
try {
|
|
11701
|
+
const decision = parseCompanyManagerDecisionText(agentResult.finalText);
|
|
11702
|
+
ctx.data.companyManagerDecision = decision;
|
|
11703
|
+
ctx.data.action = makeAction3("COMPANY_MANAGER_DECIDED", {
|
|
11704
|
+
summary: decision.summary,
|
|
11705
|
+
actionCount: decision.actions.length
|
|
11706
|
+
});
|
|
11707
|
+
} catch (err) {
|
|
11708
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11709
|
+
ctx.data.companyManagerDecisionError = reason;
|
|
11710
|
+
ctx.data.action = makeAction3("COMPANY_MANAGER_FAILED", { reason });
|
|
11711
|
+
ctx.output.exitCode = 1;
|
|
11712
|
+
ctx.output.reason = reason;
|
|
11713
|
+
}
|
|
11714
|
+
};
|
|
11715
|
+
}
|
|
11716
|
+
});
|
|
11717
|
+
|
|
11639
11718
|
// src/scripts/stateEnvelope.ts
|
|
11640
11719
|
function isPartialEnvelope(x) {
|
|
11641
11720
|
if (x === null || typeof x !== "object") return false;
|
|
@@ -11896,6 +11975,119 @@ var init_persistFlowState = __esm({
|
|
|
11896
11975
|
}
|
|
11897
11976
|
});
|
|
11898
11977
|
|
|
11978
|
+
// src/scripts/planTaskJobs.ts
|
|
11979
|
+
function parseTaskJobSpecs(body) {
|
|
11980
|
+
const match = body.match(new RegExp(`<!--\\s*${TASK_JOBS_MARKER}\\s*([\\s\\S]*?)-->`));
|
|
11981
|
+
if (!match) return [];
|
|
11982
|
+
let parsed;
|
|
11983
|
+
try {
|
|
11984
|
+
parsed = JSON.parse(match[1].trim());
|
|
11985
|
+
} catch (err) {
|
|
11986
|
+
throw new Error(`task job plan is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
11987
|
+
}
|
|
11988
|
+
if (!Array.isArray(parsed)) throw new Error("task job plan must be a JSON array");
|
|
11989
|
+
return parsed.map((entry, index) => normalizeSpec(entry, index));
|
|
11990
|
+
}
|
|
11991
|
+
function taskJobSpecToJob(spec, issueNumber) {
|
|
11992
|
+
const cliArgs = spec.cliArgs ?? { issue: issueNumber };
|
|
11993
|
+
const target = typeof spec.target === "number" ? spec.target : targetFromCliArgs(cliArgs) ?? issueNumber;
|
|
11994
|
+
return {
|
|
11995
|
+
agentResponsibility: spec.agentResponsibility ?? spec.agentAction,
|
|
11996
|
+
agentAction: spec.agentAction,
|
|
11997
|
+
why: spec.reason,
|
|
11998
|
+
agent: spec.agent,
|
|
11999
|
+
schedule: spec.schedule,
|
|
12000
|
+
target,
|
|
12001
|
+
cliArgs,
|
|
12002
|
+
flavor: spec.flavor ?? "instant"
|
|
12003
|
+
};
|
|
12004
|
+
}
|
|
12005
|
+
function normalizeSpec(input, index) {
|
|
12006
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
12007
|
+
throw new Error(`task job plan entry ${index} must be an object`);
|
|
12008
|
+
}
|
|
12009
|
+
const raw = input;
|
|
12010
|
+
const agentAction = typeof raw.agentAction === "string" ? raw.agentAction.trim() : "";
|
|
12011
|
+
if (!/^[a-z][a-z0-9-]*$/.test(agentAction)) {
|
|
12012
|
+
throw new Error(`task job plan entry ${index} must have a valid agentAction`);
|
|
12013
|
+
}
|
|
12014
|
+
const cliArgs = raw.cliArgs;
|
|
12015
|
+
if (cliArgs !== void 0 && (!cliArgs || typeof cliArgs !== "object" || Array.isArray(cliArgs))) {
|
|
12016
|
+
throw new Error(`task job plan entry ${index} cliArgs must be an object`);
|
|
12017
|
+
}
|
|
12018
|
+
const flavor = raw.flavor;
|
|
12019
|
+
if (flavor !== void 0 && flavor !== "instant" && flavor !== "scheduled") {
|
|
12020
|
+
throw new Error(`task job plan entry ${index} flavor must be "instant" or "scheduled"`);
|
|
12021
|
+
}
|
|
12022
|
+
return {
|
|
12023
|
+
agentAction,
|
|
12024
|
+
...typeof raw.agentResponsibility === "string" && raw.agentResponsibility.trim() ? { agentResponsibility: raw.agentResponsibility.trim() } : {},
|
|
12025
|
+
...typeof raw.reason === "string" && raw.reason.trim() ? { reason: raw.reason.trim() } : {},
|
|
12026
|
+
...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
|
|
12027
|
+
...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
|
|
12028
|
+
...cliArgs ? { cliArgs } : {},
|
|
12029
|
+
...typeof raw.target === "number" && Number.isFinite(raw.target) ? { target: raw.target } : {},
|
|
12030
|
+
...flavor === "instant" || flavor === "scheduled" ? { flavor } : {},
|
|
12031
|
+
...typeof raw.schedule === "string" && raw.schedule.trim() ? { schedule: raw.schedule.trim() } : {}
|
|
12032
|
+
};
|
|
12033
|
+
}
|
|
12034
|
+
function jobToPlannedTaskJob(job) {
|
|
12035
|
+
return {
|
|
12036
|
+
id: stableJobKey(job),
|
|
12037
|
+
agentAction: job.agentAction ?? job.agentResponsibility ?? "unknown",
|
|
12038
|
+
agentResponsibility: job.agentResponsibility ?? job.action ?? job.agentAction ?? "unknown",
|
|
12039
|
+
...job.agent ? { agent: job.agent } : {},
|
|
12040
|
+
...job.flavor ? { flavor: job.flavor } : {},
|
|
12041
|
+
...job.schedule ? { schedule: job.schedule } : {},
|
|
12042
|
+
...typeof job.target === "number" ? { target: job.target } : {},
|
|
12043
|
+
...job.why ? { reason: job.why } : {}
|
|
12044
|
+
};
|
|
12045
|
+
}
|
|
12046
|
+
function assertUniqueJobIds(planned) {
|
|
12047
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12048
|
+
for (const job of planned) {
|
|
12049
|
+
if (seen.has(job.id)) throw new Error(`duplicate planned task job id: ${job.id}`);
|
|
12050
|
+
seen.add(job.id);
|
|
12051
|
+
}
|
|
12052
|
+
}
|
|
12053
|
+
var TASK_JOBS_MARKER, planTaskJobs;
|
|
12054
|
+
var init_planTaskJobs = __esm({
|
|
12055
|
+
"src/scripts/planTaskJobs.ts"() {
|
|
12056
|
+
"use strict";
|
|
12057
|
+
init_jobIdentity();
|
|
12058
|
+
init_state();
|
|
12059
|
+
TASK_JOBS_MARKER = "kody:task-jobs:v1";
|
|
12060
|
+
planTaskJobs = async (ctx) => {
|
|
12061
|
+
const issueNumber = ctx.args.issue;
|
|
12062
|
+
if (!issueNumber) {
|
|
12063
|
+
ctx.skipAgent = true;
|
|
12064
|
+
ctx.output.exitCode = 64;
|
|
12065
|
+
ctx.output.reason = "planTaskJobs requires --issue";
|
|
12066
|
+
return;
|
|
12067
|
+
}
|
|
12068
|
+
const issue = ctx.data.issue;
|
|
12069
|
+
const specs = parseTaskJobSpecs(issue?.body ?? "");
|
|
12070
|
+
if (specs.length === 0) {
|
|
12071
|
+
ctx.skipAgent = true;
|
|
12072
|
+
ctx.output.exitCode = 64;
|
|
12073
|
+
ctx.output.reason = `no ${TASK_JOBS_MARKER} block found on issue #${issueNumber}`;
|
|
12074
|
+
return;
|
|
12075
|
+
}
|
|
12076
|
+
const jobs = specs.map((spec) => taskJobSpecToJob(spec, issueNumber));
|
|
12077
|
+
const planned = jobs.map(jobToPlannedTaskJob);
|
|
12078
|
+
assertUniqueJobIds(planned);
|
|
12079
|
+
const prior = ctx.data.taskState ?? emptyState();
|
|
12080
|
+
const next = upsertTaskJobs(prior, planned, (/* @__PURE__ */ new Date()).toISOString());
|
|
12081
|
+
ctx.data.taskState = next;
|
|
12082
|
+
ctx.data.plannedTaskJobs = jobs;
|
|
12083
|
+
ctx.data.plannedTaskJobIds = planned.map((job) => job.id);
|
|
12084
|
+
const target = ctx.data.commentTargetType;
|
|
12085
|
+
const number = ctx.data.commentTargetNumber;
|
|
12086
|
+
if (target && number) writeTaskState(target, number, next, ctx.cwd, ctx.config);
|
|
12087
|
+
};
|
|
12088
|
+
}
|
|
12089
|
+
});
|
|
12090
|
+
|
|
11899
12091
|
// src/scripts/postAgentSummaryComment.ts
|
|
11900
12092
|
function postAgentSummaryComment(ctx, opts = {}) {
|
|
11901
12093
|
if (!ctx.data.agentDone) return;
|
|
@@ -12195,7 +12387,7 @@ function tryAuditComment(issueNumber, body, cwd) {
|
|
|
12195
12387
|
} catch {
|
|
12196
12388
|
}
|
|
12197
12389
|
}
|
|
12198
|
-
function
|
|
12390
|
+
function makeAction4(type, payload) {
|
|
12199
12391
|
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
12200
12392
|
}
|
|
12201
12393
|
function failedAction4(reason) {
|
|
@@ -12232,7 +12424,7 @@ var init_recordClassification = __esm({
|
|
|
12232
12424
|
ctx.output.reason = "classify: no decision";
|
|
12233
12425
|
return;
|
|
12234
12426
|
}
|
|
12235
|
-
ctx.data.action =
|
|
12427
|
+
ctx.data.action = makeAction4(`CLASSIFIED_AS_${classification.toUpperCase()}`, {
|
|
12236
12428
|
classification,
|
|
12237
12429
|
reason: reason ?? "",
|
|
12238
12430
|
source: ctx.data.classificationSource ?? "agent"
|
|
@@ -13075,12 +13267,12 @@ fi
|
|
|
13075
13267
|
|
|
13076
13268
|
// src/scripts/runPreviewBuild.ts
|
|
13077
13269
|
import { copyFile, writeFile } from "fs/promises";
|
|
13078
|
-
import * as
|
|
13270
|
+
import * as path36 from "path";
|
|
13079
13271
|
import { fileURLToPath } from "url";
|
|
13080
13272
|
function bundledDockerfilePath(mode) {
|
|
13081
|
-
const here =
|
|
13273
|
+
const here = path36.dirname(fileURLToPath(import.meta.url));
|
|
13082
13274
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
13083
|
-
return
|
|
13275
|
+
return path36.join(here, "preview-build-templates", file);
|
|
13084
13276
|
}
|
|
13085
13277
|
function required(name) {
|
|
13086
13278
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -13339,10 +13531,10 @@ var init_runPreviewBuild = __esm({
|
|
|
13339
13531
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
13340
13532
|
if (Object.keys(buildEnv).length > 0) {
|
|
13341
13533
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
13342
|
-
await writeFile(
|
|
13534
|
+
await writeFile(path36.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
13343
13535
|
`, "utf8");
|
|
13344
13536
|
}
|
|
13345
|
-
const consumerDockerfile =
|
|
13537
|
+
const consumerDockerfile = path36.join(ctx.cwd, "Dockerfile.preview");
|
|
13346
13538
|
const { stat } = await import("fs/promises");
|
|
13347
13539
|
let hasConsumerDockerfile = false;
|
|
13348
13540
|
try {
|
|
@@ -13527,7 +13719,7 @@ var init_tickShellRunner = __esm({
|
|
|
13527
13719
|
|
|
13528
13720
|
// src/scripts/runScheduledAgentActionTick.ts
|
|
13529
13721
|
import * as fs37 from "fs";
|
|
13530
|
-
import * as
|
|
13722
|
+
import * as path37 from "path";
|
|
13531
13723
|
var runScheduledAgentActionTick;
|
|
13532
13724
|
var init_runScheduledAgentActionTick = __esm({
|
|
13533
13725
|
"src/scripts/runScheduledAgentActionTick.ts"() {
|
|
@@ -13541,19 +13733,19 @@ var init_runScheduledAgentActionTick = __esm({
|
|
|
13541
13733
|
const slugArg = String(args?.slugArg ?? "agentResponsibility");
|
|
13542
13734
|
const fenceLabel = String(args?.fenceLabel ?? "kody-job-next-state");
|
|
13543
13735
|
const shell = String(args?.shell ?? "tick.sh");
|
|
13544
|
-
const
|
|
13545
|
-
if (!
|
|
13736
|
+
const slug2 = String(args?.slug ?? ctx.args[slugArg] ?? "").trim();
|
|
13737
|
+
if (!slug2) {
|
|
13546
13738
|
ctx.output.exitCode = 99;
|
|
13547
13739
|
ctx.output.reason = `runScheduledAgentActionTick: args.slug or ctx.args.${slugArg} must be non-empty agentResponsibility slug`;
|
|
13548
13740
|
return;
|
|
13549
13741
|
}
|
|
13550
|
-
const agentResponsibility = resolveAgentResponsibilityFolder(
|
|
13742
|
+
const agentResponsibility = resolveAgentResponsibilityFolder(slug2, path37.join(ctx.cwd, jobsDir));
|
|
13551
13743
|
if (!agentResponsibility) {
|
|
13552
13744
|
ctx.output.exitCode = 99;
|
|
13553
|
-
ctx.output.reason = `runScheduledAgentActionTick: agentResponsibility folder not found or incomplete: ${
|
|
13745
|
+
ctx.output.reason = `runScheduledAgentActionTick: agentResponsibility folder not found or incomplete: ${slug2} (searched ${jobsDir} and company store)`;
|
|
13554
13746
|
return;
|
|
13555
13747
|
}
|
|
13556
|
-
const shellPath =
|
|
13748
|
+
const shellPath = path37.join(profile.dir, shell);
|
|
13557
13749
|
if (!fs37.existsSync(shellPath)) {
|
|
13558
13750
|
ctx.output.exitCode = 99;
|
|
13559
13751
|
ctx.output.reason = `runScheduledAgentActionTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
@@ -13562,14 +13754,14 @@ var init_runScheduledAgentActionTick = __esm({
|
|
|
13562
13754
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
13563
13755
|
let loaded;
|
|
13564
13756
|
try {
|
|
13565
|
-
loaded = await backend.load(
|
|
13757
|
+
loaded = await backend.load(slug2);
|
|
13566
13758
|
} catch (err) {
|
|
13567
13759
|
ctx.output.exitCode = 99;
|
|
13568
13760
|
ctx.output.reason = `runScheduledAgentActionTick: state load failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
13569
13761
|
return;
|
|
13570
13762
|
}
|
|
13571
|
-
ctx.data.jobSlug =
|
|
13572
|
-
ctx.data.agentResponsibilitySlug =
|
|
13763
|
+
ctx.data.jobSlug = slug2;
|
|
13764
|
+
ctx.data.agentResponsibilitySlug = slug2;
|
|
13573
13765
|
ctx.data.agentActionSlug = profile.name;
|
|
13574
13766
|
ctx.data.jobState = loaded;
|
|
13575
13767
|
runTickShellAndParse({
|
|
@@ -13586,7 +13778,7 @@ var init_runScheduledAgentActionTick = __esm({
|
|
|
13586
13778
|
|
|
13587
13779
|
// src/scripts/runTickScript.ts
|
|
13588
13780
|
import * as fs38 from "fs";
|
|
13589
|
-
import * as
|
|
13781
|
+
import * as path38 from "path";
|
|
13590
13782
|
var runTickScript;
|
|
13591
13783
|
var init_runTickScript = __esm({
|
|
13592
13784
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -13599,25 +13791,25 @@ var init_runTickScript = __esm({
|
|
|
13599
13791
|
const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
|
|
13600
13792
|
const slugArg = String(args?.slugArg ?? "job");
|
|
13601
13793
|
const fenceLabel = String(args?.fenceLabel ?? "kody-job-next-state");
|
|
13602
|
-
const
|
|
13603
|
-
if (!
|
|
13794
|
+
const slug2 = String(ctx.args[slugArg] ?? "").trim();
|
|
13795
|
+
if (!slug2) {
|
|
13604
13796
|
ctx.output.exitCode = 99;
|
|
13605
13797
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
13606
13798
|
return;
|
|
13607
13799
|
}
|
|
13608
|
-
const agentResponsibility = readAgentResponsibilityFolder(
|
|
13800
|
+
const agentResponsibility = readAgentResponsibilityFolder(path38.join(ctx.cwd, jobsDir), slug2);
|
|
13609
13801
|
if (!agentResponsibility) {
|
|
13610
13802
|
ctx.output.exitCode = 99;
|
|
13611
|
-
ctx.output.reason = `runTickScript: agentResponsibility folder not found or incomplete: ${
|
|
13803
|
+
ctx.output.reason = `runTickScript: agentResponsibility folder not found or incomplete: ${path38.join(ctx.cwd, jobsDir, slug2)}`;
|
|
13612
13804
|
return;
|
|
13613
13805
|
}
|
|
13614
13806
|
const tickScript = agentResponsibility.config.tickScript;
|
|
13615
13807
|
if (!tickScript) {
|
|
13616
13808
|
ctx.output.exitCode = 99;
|
|
13617
|
-
ctx.output.reason = `runTickScript: agentResponsibility ${
|
|
13809
|
+
ctx.output.reason = `runTickScript: agentResponsibility ${slug2} has no \`tickScript\` in profile.json \u2014 route via agent-responsibility-tick instead`;
|
|
13618
13810
|
return;
|
|
13619
13811
|
}
|
|
13620
|
-
const scriptPath =
|
|
13812
|
+
const scriptPath = path38.isAbsolute(tickScript) ? tickScript : path38.join(ctx.cwd, tickScript);
|
|
13621
13813
|
if (!fs38.existsSync(scriptPath)) {
|
|
13622
13814
|
ctx.output.exitCode = 99;
|
|
13623
13815
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
@@ -13626,13 +13818,13 @@ var init_runTickScript = __esm({
|
|
|
13626
13818
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
13627
13819
|
let loaded;
|
|
13628
13820
|
try {
|
|
13629
|
-
loaded = await backend.load(
|
|
13821
|
+
loaded = await backend.load(slug2);
|
|
13630
13822
|
} catch (err) {
|
|
13631
13823
|
ctx.output.exitCode = 99;
|
|
13632
13824
|
ctx.output.reason = `runTickScript: state load failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
13633
13825
|
return;
|
|
13634
13826
|
}
|
|
13635
|
-
ctx.data.jobSlug =
|
|
13827
|
+
ctx.data.jobSlug = slug2;
|
|
13636
13828
|
ctx.data.jobState = loaded;
|
|
13637
13829
|
runTickShellAndParse({
|
|
13638
13830
|
ctx,
|
|
@@ -14577,6 +14769,86 @@ var init_writeJobStateFile = __esm({
|
|
|
14577
14769
|
}
|
|
14578
14770
|
});
|
|
14579
14771
|
|
|
14772
|
+
// src/scripts/writeResponsibilityReport.ts
|
|
14773
|
+
function writeReport(ctx, profile, agentResult) {
|
|
14774
|
+
const slug2 = responsibilitySlug(ctx);
|
|
14775
|
+
if (!slug2) {
|
|
14776
|
+
fail2(ctx, "writeResponsibilityReport: missing responsibility slug");
|
|
14777
|
+
return;
|
|
14778
|
+
}
|
|
14779
|
+
if (!REPORT_SLUG_RE.test(slug2)) {
|
|
14780
|
+
fail2(ctx, `writeResponsibilityReport: invalid responsibility slug "${slug2}"`);
|
|
14781
|
+
return;
|
|
14782
|
+
}
|
|
14783
|
+
const body = reportBody(ctx, agentResult, profile);
|
|
14784
|
+
if (!body.trim()) {
|
|
14785
|
+
fail2(ctx, `writeResponsibilityReport: ${slug2} produced no report output`);
|
|
14786
|
+
return;
|
|
14787
|
+
}
|
|
14788
|
+
const filePath = `reports/${slug2}.md`;
|
|
14789
|
+
const current = readStateText(ctx.config, ctx.cwd, filePath);
|
|
14790
|
+
if (current?.content === body) {
|
|
14791
|
+
ctx.data.responsibilityReport = { slug: slug2, path: current.path, changed: false };
|
|
14792
|
+
return;
|
|
14793
|
+
}
|
|
14794
|
+
upsertStateText(
|
|
14795
|
+
ctx.config,
|
|
14796
|
+
ctx.cwd,
|
|
14797
|
+
filePath,
|
|
14798
|
+
body,
|
|
14799
|
+
`chore(reports): refresh ${slug2}`
|
|
14800
|
+
);
|
|
14801
|
+
ctx.data.responsibilityReport = { slug: slug2, path: filePath, changed: true };
|
|
14802
|
+
}
|
|
14803
|
+
function responsibilitySlug(ctx) {
|
|
14804
|
+
const candidates = [
|
|
14805
|
+
ctx.data.jobAgentResponsibility,
|
|
14806
|
+
ctx.data.agentResponsibilitySlug,
|
|
14807
|
+
ctx.data.jobSlug
|
|
14808
|
+
];
|
|
14809
|
+
for (const candidate of candidates) {
|
|
14810
|
+
if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
|
|
14811
|
+
}
|
|
14812
|
+
return null;
|
|
14813
|
+
}
|
|
14814
|
+
function reportBody(ctx, agentResult, profile) {
|
|
14815
|
+
const prSummary = ctx.data.prSummary;
|
|
14816
|
+
if (typeof prSummary === "string" && prSummary.trim()) return ensureTrailingNewline(prSummary.trim());
|
|
14817
|
+
if (agentResult?.finalText.trim()) return ensureTrailingNewline(agentResult.finalText.trim());
|
|
14818
|
+
const reason = ctx.output.reason || ctx.data.agentFailureReason || agentResult?.error;
|
|
14819
|
+
if (typeof reason === "string" && reason.trim()) {
|
|
14820
|
+
return `# ${profile.name}
|
|
14821
|
+
|
|
14822
|
+
FAILED: ${reason.trim()}
|
|
14823
|
+
`;
|
|
14824
|
+
}
|
|
14825
|
+
return "";
|
|
14826
|
+
}
|
|
14827
|
+
function fail2(ctx, reason) {
|
|
14828
|
+
ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; ${reason}` : reason;
|
|
14829
|
+
if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
|
|
14830
|
+
}
|
|
14831
|
+
function ensureTrailingNewline(value) {
|
|
14832
|
+
return value.endsWith("\n") ? value : `${value}
|
|
14833
|
+
`;
|
|
14834
|
+
}
|
|
14835
|
+
var REPORT_SLUG_RE, writeResponsibilityReport;
|
|
14836
|
+
var init_writeResponsibilityReport = __esm({
|
|
14837
|
+
"src/scripts/writeResponsibilityReport.ts"() {
|
|
14838
|
+
"use strict";
|
|
14839
|
+
init_stateRepo();
|
|
14840
|
+
REPORT_SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
14841
|
+
writeResponsibilityReport = async (ctx, profile, agentResult) => {
|
|
14842
|
+
if (ctx.data.jobSaveReport !== true) return;
|
|
14843
|
+
try {
|
|
14844
|
+
writeReport(ctx, profile, agentResult);
|
|
14845
|
+
} catch (err) {
|
|
14846
|
+
fail2(ctx, `writeResponsibilityReport: ${err instanceof Error ? err.message : String(err)}`);
|
|
14847
|
+
}
|
|
14848
|
+
};
|
|
14849
|
+
}
|
|
14850
|
+
});
|
|
14851
|
+
|
|
14580
14852
|
// src/scripts/index.ts
|
|
14581
14853
|
var preflightScripts, postflightScripts, allScriptNames;
|
|
14582
14854
|
var init_scripts = __esm({
|
|
@@ -14586,7 +14858,9 @@ var init_scripts = __esm({
|
|
|
14586
14858
|
init_advanceFlow();
|
|
14587
14859
|
init_advanceManagedGoal();
|
|
14588
14860
|
init_appendCompanyActivity();
|
|
14861
|
+
init_appendCompanyIntentDecision();
|
|
14589
14862
|
init_applyAgentResponsibilityReports();
|
|
14863
|
+
init_applyCompanyManagerDecision();
|
|
14590
14864
|
init_buildSyntheticPlugin();
|
|
14591
14865
|
init_checkCoverageWithRetry();
|
|
14592
14866
|
init_classifyByLabel();
|
|
@@ -14611,6 +14885,8 @@ var init_scripts = __esm({
|
|
|
14611
14885
|
init_initFlow();
|
|
14612
14886
|
init_loadAgentAdhoc();
|
|
14613
14887
|
init_loadAgentResponsibilityState();
|
|
14888
|
+
init_loadCompanyIntents();
|
|
14889
|
+
init_loadCompanyPortfolio();
|
|
14614
14890
|
init_loadConventions();
|
|
14615
14891
|
init_loadCoverageRules();
|
|
14616
14892
|
init_loadGoalState();
|
|
@@ -14631,6 +14907,7 @@ var init_scripts = __esm({
|
|
|
14631
14907
|
init_openAgentFactoryStatePr();
|
|
14632
14908
|
init_openQaIssue();
|
|
14633
14909
|
init_parseAgentResult();
|
|
14910
|
+
init_parseCompanyManagerDecision();
|
|
14634
14911
|
init_parseIssueStateFromAgentResult();
|
|
14635
14912
|
init_parseJobStateFromAgentResult();
|
|
14636
14913
|
init_parseReproOutput();
|
|
@@ -14673,6 +14950,7 @@ var init_scripts = __esm({
|
|
|
14673
14950
|
init_writeAgentRunSummary();
|
|
14674
14951
|
init_writeIssueStateComment();
|
|
14675
14952
|
init_writeJobStateFile();
|
|
14953
|
+
init_writeResponsibilityReport();
|
|
14676
14954
|
preflightScripts = {
|
|
14677
14955
|
runFlow,
|
|
14678
14956
|
fixFlow,
|
|
@@ -14689,6 +14967,8 @@ var init_scripts = __esm({
|
|
|
14689
14967
|
loadIssueStateComment,
|
|
14690
14968
|
loadJobFromFile,
|
|
14691
14969
|
loadAgentResponsibilityState,
|
|
14970
|
+
loadCompanyIntents,
|
|
14971
|
+
loadCompanyPortfolio,
|
|
14692
14972
|
loadAgentAdhoc,
|
|
14693
14973
|
loadConventions,
|
|
14694
14974
|
loadCoverageRules,
|
|
@@ -14723,12 +15003,15 @@ var init_scripts = __esm({
|
|
|
14723
15003
|
};
|
|
14724
15004
|
postflightScripts = {
|
|
14725
15005
|
parseAgentResult: parseAgentResult2,
|
|
15006
|
+
parseCompanyManagerDecision,
|
|
14726
15007
|
parseIssueStateFromAgentResult,
|
|
14727
15008
|
parseJobStateFromAgentResult,
|
|
14728
15009
|
parseReproOutput,
|
|
14729
15010
|
writeIssueStateComment,
|
|
14730
15011
|
writeJobStateFile,
|
|
14731
15012
|
appendCompanyActivity,
|
|
15013
|
+
appendCompanyIntentDecision: appendCompanyIntentDecision2,
|
|
15014
|
+
applyCompanyManagerDecision,
|
|
14732
15015
|
requireFeedbackActions,
|
|
14733
15016
|
requirePlanDeviations,
|
|
14734
15017
|
verify,
|
|
@@ -14746,6 +15029,7 @@ var init_scripts = __esm({
|
|
|
14746
15029
|
postReviewResult,
|
|
14747
15030
|
persistArtifacts,
|
|
14748
15031
|
writeAgentRunSummary,
|
|
15032
|
+
writeResponsibilityReport,
|
|
14749
15033
|
saveTaskState,
|
|
14750
15034
|
mirrorStateToPr,
|
|
14751
15035
|
startFlow,
|
|
@@ -14842,7 +15126,7 @@ var init_tools = __esm({
|
|
|
14842
15126
|
// src/executor.ts
|
|
14843
15127
|
import { spawn as spawn7 } from "child_process";
|
|
14844
15128
|
import * as fs40 from "fs";
|
|
14845
|
-
import * as
|
|
15129
|
+
import * as path39 from "path";
|
|
14846
15130
|
function isMutatingPostflight(scriptName) {
|
|
14847
15131
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
14848
15132
|
}
|
|
@@ -15007,13 +15291,13 @@ async function runAgentAction(profileName, input) {
|
|
|
15007
15291
|
})
|
|
15008
15292
|
};
|
|
15009
15293
|
})() : null;
|
|
15010
|
-
const ndjsonDir =
|
|
15294
|
+
const ndjsonDir = path39.join(input.cwd, ".kody");
|
|
15011
15295
|
const agentSlug = typeof profile.agent === "string" && profile.agent.length > 0 ? profile.agent : typeof ctx.data.jobAgent === "string" && ctx.data.jobAgent.length > 0 ? ctx.data.jobAgent : null;
|
|
15012
15296
|
const agentIdentityBlock = agentSlug ? frameAgentIdentity(agentSlug, loadAgentIdentity(input.cwd, agentSlug)) : null;
|
|
15013
15297
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
15014
15298
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
15015
15299
|
const invokeAgent = async (prompt) => {
|
|
15016
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
15300
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path39.isAbsolute(p) ? p : path39.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
15017
15301
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
15018
15302
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
15019
15303
|
const agents = loadSubagents(profile);
|
|
@@ -15248,6 +15532,7 @@ async function runAgentAction(profileName, input) {
|
|
|
15248
15532
|
outcome: postOutcome
|
|
15249
15533
|
});
|
|
15250
15534
|
}
|
|
15535
|
+
await writeResponsibilityReport(ctx, profile, agentResult);
|
|
15251
15536
|
return finishAndEnd({
|
|
15252
15537
|
exitCode: ctx.output.exitCode ?? 0,
|
|
15253
15538
|
prUrl: ctx.output.prUrl,
|
|
@@ -15376,7 +15661,8 @@ function handoffToJob(handoff) {
|
|
|
15376
15661
|
agentResponsibility: handoff.agentResponsibility,
|
|
15377
15662
|
agentAction: handoff.agentAction,
|
|
15378
15663
|
cliArgs: handoff.cliArgs,
|
|
15379
|
-
flavor: "instant"
|
|
15664
|
+
flavor: "instant",
|
|
15665
|
+
saveReport: handoff.saveReport === true
|
|
15380
15666
|
};
|
|
15381
15667
|
}
|
|
15382
15668
|
function clearStampedLifecycleLabels(profile, ctx) {
|
|
@@ -15395,13 +15681,13 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
15395
15681
|
function resolveProfilePath(profileName) {
|
|
15396
15682
|
const found = resolveAgentAction(profileName);
|
|
15397
15683
|
if (found) return found;
|
|
15398
|
-
const here =
|
|
15684
|
+
const here = path39.dirname(new URL(import.meta.url).pathname);
|
|
15399
15685
|
const candidates = [
|
|
15400
|
-
|
|
15686
|
+
path39.join(here, "agent-actions", profileName, "profile.json"),
|
|
15401
15687
|
// same-dir sibling (dev)
|
|
15402
|
-
|
|
15688
|
+
path39.join(here, "..", "agent-actions", profileName, "profile.json"),
|
|
15403
15689
|
// up one (prod: dist/bin → dist/agent-actions)
|
|
15404
|
-
|
|
15690
|
+
path39.join(here, "..", "src", "agent-actions", profileName, "profile.json")
|
|
15405
15691
|
// fallback
|
|
15406
15692
|
];
|
|
15407
15693
|
for (const c of candidates) {
|
|
@@ -15503,7 +15789,7 @@ function resolveShellTimeoutMs(entry) {
|
|
|
15503
15789
|
}
|
|
15504
15790
|
async function runShellEntry(entry, ctx, profile) {
|
|
15505
15791
|
const shellName = entry.shell;
|
|
15506
|
-
const shellPath =
|
|
15792
|
+
const shellPath = path39.join(profile.dir, shellName);
|
|
15507
15793
|
if (!fs40.existsSync(shellPath)) {
|
|
15508
15794
|
ctx.skipAgent = true;
|
|
15509
15795
|
ctx.output.exitCode = 99;
|
|
@@ -15636,6 +15922,7 @@ var init_executor = __esm({
|
|
|
15636
15922
|
init_profile();
|
|
15637
15923
|
init_registry();
|
|
15638
15924
|
init_scripts();
|
|
15925
|
+
init_writeResponsibilityReport();
|
|
15639
15926
|
init_subagents();
|
|
15640
15927
|
init_task_artifacts();
|
|
15641
15928
|
init_tools();
|
|
@@ -15663,7 +15950,7 @@ __export(job_exports, {
|
|
|
15663
15950
|
stableJobKey: () => stableJobKey,
|
|
15664
15951
|
validateJob: () => validateJob
|
|
15665
15952
|
});
|
|
15666
|
-
import * as
|
|
15953
|
+
import * as path40 from "path";
|
|
15667
15954
|
function newJobId(flavor) {
|
|
15668
15955
|
localJobSeq += 1;
|
|
15669
15956
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -15694,13 +15981,14 @@ function validateJob(input) {
|
|
|
15694
15981
|
target: typeof j.target === "number" ? j.target : void 0,
|
|
15695
15982
|
cliArgs: j.cliArgs ?? {},
|
|
15696
15983
|
flavor: j.flavor,
|
|
15697
|
-
force: j.force === true
|
|
15984
|
+
force: j.force === true,
|
|
15985
|
+
saveReport: j.saveReport === true
|
|
15698
15986
|
};
|
|
15699
15987
|
}
|
|
15700
15988
|
async function runJob(job, base) {
|
|
15701
15989
|
const valid = validateJob(job);
|
|
15702
15990
|
const action = valid.action ?? valid.agentResponsibility;
|
|
15703
|
-
const projectAgentResponsibilitiesRoot =
|
|
15991
|
+
const projectAgentResponsibilitiesRoot = path40.join(base.cwd, ".kody", "agent-responsibilities");
|
|
15704
15992
|
const resolvedAgentResponsibility = action ? resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot) : null;
|
|
15705
15993
|
const agentResponsibilityIdentity = valid.agentResponsibility ?? resolvedAgentResponsibility?.agentResponsibility;
|
|
15706
15994
|
const agentResponsibilityContext = loadAgentResponsibilityContext(agentResponsibilityIdentity, base.cwd);
|
|
@@ -15727,6 +16015,7 @@ async function runJob(job, base) {
|
|
|
15727
16015
|
if (executableIdentity !== void 0 && executableIdentity.length > 0)
|
|
15728
16016
|
preloadedData.jobAgentAction = executableIdentity;
|
|
15729
16017
|
if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
|
|
16018
|
+
if (valid.saveReport === true) preloadedData.jobSaveReport = true;
|
|
15730
16019
|
if (agentResponsibilityContext) {
|
|
15731
16020
|
preloadedData.agentResponsibilitySlug = agentResponsibilityContext.slug;
|
|
15732
16021
|
preloadedData.agentResponsibilityTitle = agentResponsibilityContext.title;
|
|
@@ -15737,9 +16026,6 @@ async function runJob(job, base) {
|
|
|
15737
16026
|
if (agentResponsibilityContext.config.agent && preloadedData.jobAgent === void 0) {
|
|
15738
16027
|
preloadedData.jobAgent = agentResponsibilityContext.config.agent;
|
|
15739
16028
|
}
|
|
15740
|
-
if (agentResponsibilityContext.config.every && preloadedData.jobSchedule === void 0) {
|
|
15741
|
-
preloadedData.jobSchedule = agentResponsibilityContext.config.every;
|
|
15742
|
-
}
|
|
15743
16029
|
if (agentResponsibilityContext.config.mentions && agentResponsibilityContext.config.mentions.length > 0) {
|
|
15744
16030
|
preloadedData.mentions = agentResponsibilityContext.config.mentions.map((login) => `@${login}`).join(" ");
|
|
15745
16031
|
}
|
|
@@ -15760,9 +16046,9 @@ async function runJob(job, base) {
|
|
|
15760
16046
|
const run = base.chain === false ? runAgentAction : runAgentActionChain;
|
|
15761
16047
|
return run(profileName, input);
|
|
15762
16048
|
}
|
|
15763
|
-
function loadAgentResponsibilityContext(
|
|
15764
|
-
if (!
|
|
15765
|
-
return resolveAgentResponsibilityFolder(
|
|
16049
|
+
function loadAgentResponsibilityContext(slug2, cwd) {
|
|
16050
|
+
if (!slug2) return null;
|
|
16051
|
+
return resolveAgentResponsibilityFolder(slug2, path40.join(cwd, ".kody", "agent-responsibilities"));
|
|
15766
16052
|
}
|
|
15767
16053
|
function mintInstantJob(dispatch2, opts) {
|
|
15768
16054
|
return {
|
|
@@ -15784,7 +16070,8 @@ function mintScheduledJob(input) {
|
|
|
15784
16070
|
schedule: input.schedule,
|
|
15785
16071
|
agent: input.agent,
|
|
15786
16072
|
cliArgs: input.cliArgs ?? {},
|
|
15787
|
-
flavor: "scheduled"
|
|
16073
|
+
flavor: "scheduled",
|
|
16074
|
+
saveReport: input.saveReport === true
|
|
15788
16075
|
};
|
|
15789
16076
|
}
|
|
15790
16077
|
var DEFAULT_INSTANT_AGENT, localJobSeq, InvalidJobError;
|
|
@@ -15915,7 +16202,7 @@ function translateOpenAISseToBrain(opts) {
|
|
|
15915
16202
|
// src/servers/brain-serve.ts
|
|
15916
16203
|
import * as fs43 from "fs";
|
|
15917
16204
|
import { createServer } from "http";
|
|
15918
|
-
import * as
|
|
16205
|
+
import * as path43 from "path";
|
|
15919
16206
|
|
|
15920
16207
|
// src/chat/loop.ts
|
|
15921
16208
|
init_agent();
|
|
@@ -16458,7 +16745,7 @@ init_config();
|
|
|
16458
16745
|
// src/kody-cli.ts
|
|
16459
16746
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
16460
16747
|
import * as fs41 from "fs";
|
|
16461
|
-
import * as
|
|
16748
|
+
import * as path41 from "path";
|
|
16462
16749
|
|
|
16463
16750
|
// src/app-auth.ts
|
|
16464
16751
|
import { createSign } from "crypto";
|
|
@@ -17054,9 +17341,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
17054
17341
|
return void 0;
|
|
17055
17342
|
}
|
|
17056
17343
|
function detectPackageManager2(cwd) {
|
|
17057
|
-
if (fs41.existsSync(
|
|
17058
|
-
if (fs41.existsSync(
|
|
17059
|
-
if (fs41.existsSync(
|
|
17344
|
+
if (fs41.existsSync(path41.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
17345
|
+
if (fs41.existsSync(path41.join(cwd, "yarn.lock"))) return "yarn";
|
|
17346
|
+
if (fs41.existsSync(path41.join(cwd, "bun.lockb"))) return "bun";
|
|
17060
17347
|
return "npm";
|
|
17061
17348
|
}
|
|
17062
17349
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
@@ -17143,7 +17430,7 @@ function configureGitIdentity(cwd) {
|
|
|
17143
17430
|
}
|
|
17144
17431
|
function postFailureTail(issueNumber, cwd, reason) {
|
|
17145
17432
|
if (!issueNumber) return;
|
|
17146
|
-
const logPath =
|
|
17433
|
+
const logPath = path41.join(cwd, ".kody", "last-run.jsonl");
|
|
17147
17434
|
let tail = "";
|
|
17148
17435
|
try {
|
|
17149
17436
|
if (fs41.existsSync(logPath)) {
|
|
@@ -17172,7 +17459,7 @@ async function runCi(argv) {
|
|
|
17172
17459
|
return 0;
|
|
17173
17460
|
}
|
|
17174
17461
|
const args = parseCiArgs(argv);
|
|
17175
|
-
const cwd = args.cwd ?
|
|
17462
|
+
const cwd = args.cwd ? path41.resolve(args.cwd) : process.cwd();
|
|
17176
17463
|
let earlyConfig;
|
|
17177
17464
|
let earlyConfigError;
|
|
17178
17465
|
try {
|
|
@@ -17514,10 +17801,10 @@ init_repoWorkspace();
|
|
|
17514
17801
|
|
|
17515
17802
|
// src/scripts/brainTurnLog.ts
|
|
17516
17803
|
import * as fs42 from "fs";
|
|
17517
|
-
import * as
|
|
17804
|
+
import * as path42 from "path";
|
|
17518
17805
|
var live = /* @__PURE__ */ new Map();
|
|
17519
17806
|
function eventsPath2(dir, chatId) {
|
|
17520
|
-
return
|
|
17807
|
+
return path42.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
|
|
17521
17808
|
}
|
|
17522
17809
|
function lastPersistedSeq(dir, chatId) {
|
|
17523
17810
|
const p = eventsPath2(dir, chatId);
|
|
@@ -17560,7 +17847,7 @@ function beginTurn(dir, chatId) {
|
|
|
17560
17847
|
};
|
|
17561
17848
|
live.set(chatId, state);
|
|
17562
17849
|
const p = eventsPath2(dir, chatId);
|
|
17563
|
-
fs42.mkdirSync(
|
|
17850
|
+
fs42.mkdirSync(path42.dirname(p), { recursive: true });
|
|
17564
17851
|
return (event) => {
|
|
17565
17852
|
state.seq += 1;
|
|
17566
17853
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
@@ -17835,7 +18122,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
17835
18122
|
const repo = strField(body, "repo");
|
|
17836
18123
|
const repoToken = strField(body, "repoToken");
|
|
17837
18124
|
const sessionFile = sessionFilePath(opts.cwd, chatId);
|
|
17838
|
-
fs43.mkdirSync(
|
|
18125
|
+
fs43.mkdirSync(path43.dirname(sessionFile), { recursive: true });
|
|
17839
18126
|
appendTurn(sessionFile, {
|
|
17840
18127
|
role: "user",
|
|
17841
18128
|
content: message,
|
|
@@ -17882,7 +18169,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
17882
18169
|
function buildServer(opts) {
|
|
17883
18170
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
17884
18171
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
17885
|
-
const reposRoot = opts.reposRoot ??
|
|
18172
|
+
const reposRoot = opts.reposRoot ?? path43.join(path43.dirname(path43.resolve(opts.cwd)), "repos");
|
|
17886
18173
|
return createServer(async (req, res) => {
|
|
17887
18174
|
if (!req.method || !req.url) {
|
|
17888
18175
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -18478,13 +18765,13 @@ async function loadConfigSafe() {
|
|
|
18478
18765
|
// src/chat-cli.ts
|
|
18479
18766
|
import { execFileSync as execFileSync28 } from "child_process";
|
|
18480
18767
|
import * as fs45 from "fs";
|
|
18481
|
-
import * as
|
|
18768
|
+
import * as path45 from "path";
|
|
18482
18769
|
|
|
18483
18770
|
// src/chat/modes/interactive.ts
|
|
18484
18771
|
init_issue();
|
|
18485
18772
|
import { execFileSync as execFileSync27 } from "child_process";
|
|
18486
18773
|
import * as fs44 from "fs";
|
|
18487
|
-
import * as
|
|
18774
|
+
import * as path44 from "path";
|
|
18488
18775
|
|
|
18489
18776
|
// src/chat/inbox.ts
|
|
18490
18777
|
import { execFileSync as execFileSync26 } from "child_process";
|
|
@@ -18644,9 +18931,9 @@ function findNextUserTurn(turns, fromIdx) {
|
|
|
18644
18931
|
return -1;
|
|
18645
18932
|
}
|
|
18646
18933
|
function commitTurn(cwd, sessionId, _verbose) {
|
|
18647
|
-
const sessionRel =
|
|
18648
|
-
const eventsRel =
|
|
18649
|
-
const rels = [sessionRel, eventsRel].filter((p) => fs44.existsSync(
|
|
18934
|
+
const sessionRel = path44.relative(cwd, sessionFilePath(cwd, sessionId));
|
|
18935
|
+
const eventsRel = path44.relative(cwd, eventsFilePath(cwd, sessionId));
|
|
18936
|
+
const rels = [sessionRel, eventsRel].filter((p) => fs44.existsSync(path44.join(cwd, p)));
|
|
18650
18937
|
if (rels.length === 0) return;
|
|
18651
18938
|
const repository = process.env.GITHUB_REPOSITORY;
|
|
18652
18939
|
if (!repository) {
|
|
@@ -18658,8 +18945,8 @@ function commitTurn(cwd, sessionId, _verbose) {
|
|
|
18658
18945
|
}
|
|
18659
18946
|
const branch = defaultBranch(cwd) ?? "main";
|
|
18660
18947
|
for (const rel of rels) {
|
|
18661
|
-
const repoPath = rel.split(
|
|
18662
|
-
const localText = fs44.readFileSync(
|
|
18948
|
+
const repoPath = rel.split(path44.sep).join("/");
|
|
18949
|
+
const localText = fs44.readFileSync(path44.join(cwd, rel), "utf-8");
|
|
18663
18950
|
putJsonlViaContents(repository, branch, repoPath, localText, sessionId, cwd);
|
|
18664
18951
|
}
|
|
18665
18952
|
}
|
|
@@ -18804,12 +19091,12 @@ function parseChatArgs(argv, env = process.env) {
|
|
|
18804
19091
|
return result;
|
|
18805
19092
|
}
|
|
18806
19093
|
function commitChatFiles(cwd, sessionId, verbose) {
|
|
18807
|
-
const sessionFile =
|
|
18808
|
-
const eventsFile =
|
|
19094
|
+
const sessionFile = path45.relative(cwd, sessionFilePath(cwd, sessionId));
|
|
19095
|
+
const eventsFile = path45.relative(cwd, eventsFilePath(cwd, sessionId));
|
|
18809
19096
|
const safeSession = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
18810
|
-
const tasksDir =
|
|
19097
|
+
const tasksDir = path45.join(".kody", "tasks", safeSession);
|
|
18811
19098
|
const candidatePaths = [sessionFile, eventsFile, tasksDir];
|
|
18812
|
-
const paths = candidatePaths.filter((p) => fs45.existsSync(
|
|
19099
|
+
const paths = candidatePaths.filter((p) => fs45.existsSync(path45.join(cwd, p)));
|
|
18813
19100
|
if (paths.length === 0) return;
|
|
18814
19101
|
const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
|
|
18815
19102
|
try {
|
|
@@ -18853,7 +19140,7 @@ async function runChat(argv) {
|
|
|
18853
19140
|
${CHAT_HELP}`);
|
|
18854
19141
|
return 64;
|
|
18855
19142
|
}
|
|
18856
|
-
const cwd = args.cwd ?
|
|
19143
|
+
const cwd = args.cwd ? path45.resolve(args.cwd) : process.cwd();
|
|
18857
19144
|
const sessionId = args.sessionId;
|
|
18858
19145
|
const unpackedSecrets = unpackAllSecrets();
|
|
18859
19146
|
if (unpackedSecrets > 0) {
|
|
@@ -19064,8 +19351,8 @@ var FlyClient = class {
|
|
|
19064
19351
|
get fetch() {
|
|
19065
19352
|
return this.opts.fetchImpl ?? fetch;
|
|
19066
19353
|
}
|
|
19067
|
-
async call(
|
|
19068
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
19354
|
+
async call(path46, init = {}) {
|
|
19355
|
+
const res = await this.fetch(`${FLY_API_BASE}${path46}`, {
|
|
19069
19356
|
method: init.method ?? "GET",
|
|
19070
19357
|
headers: {
|
|
19071
19358
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -19076,7 +19363,7 @@ var FlyClient = class {
|
|
|
19076
19363
|
if (res.status === 404 && init.allow404) return null;
|
|
19077
19364
|
if (!res.ok) {
|
|
19078
19365
|
const text = await res.text().catch(() => "");
|
|
19079
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
19366
|
+
throw new Error(`Fly API ${res.status} on ${path46}: ${text.slice(0, 200) || res.statusText}`);
|
|
19080
19367
|
}
|
|
19081
19368
|
if (res.status === 204) return null;
|
|
19082
19369
|
const raw = await res.text();
|