@kody-ade/kody-engine 0.4.244 → 0.4.246
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 +1160 -746
- package/package.json +22 -23
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.246",
|
|
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,11 +5952,26 @@ 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;
|
|
6001
5960
|
}
|
|
5961
|
+
function asPreferredRunTime(value) {
|
|
5962
|
+
const raw = asRecord(value);
|
|
5963
|
+
if (!raw) return void 0;
|
|
5964
|
+
if (typeof raw.time !== "string" || !/^([01]\d|2[0-3]):[0-5]\d$/.test(raw.time)) return void 0;
|
|
5965
|
+
if (typeof raw.timezone !== "string" || raw.timezone.trim().length === 0) return void 0;
|
|
5966
|
+
return { time: raw.time, timezone: raw.timezone };
|
|
5967
|
+
}
|
|
5968
|
+
function asLoopTarget(value) {
|
|
5969
|
+
const raw = asRecord(value);
|
|
5970
|
+
if (!raw) return void 0;
|
|
5971
|
+
if (raw.type !== "goal" && raw.type !== "agentResponsibility") return void 0;
|
|
5972
|
+
if (typeof raw.id !== "string" || raw.id.trim().length === 0) return void 0;
|
|
5973
|
+
return { type: raw.type, id: raw.id };
|
|
5974
|
+
}
|
|
6002
5975
|
function managedGoalFromState(state) {
|
|
6003
5976
|
const extra = state.extra;
|
|
6004
5977
|
const destination = asRecord(extra.destination);
|
|
@@ -6015,6 +5988,9 @@ function managedGoalFromState(state) {
|
|
|
6015
5988
|
destination: { outcome: destination.outcome, evidence },
|
|
6016
5989
|
agentResponsibilities,
|
|
6017
5990
|
route,
|
|
5991
|
+
schedule: typeof extra.schedule === "string" ? extra.schedule : void 0,
|
|
5992
|
+
preferredRunTime: asPreferredRunTime(extra.preferredRunTime),
|
|
5993
|
+
loopTarget: asLoopTarget(extra.loopTarget),
|
|
6018
5994
|
stage: typeof extra.stage === "string" ? extra.stage : void 0,
|
|
6019
5995
|
facts,
|
|
6020
5996
|
blockers
|
|
@@ -6088,10 +6064,10 @@ var init_state2 = __esm({
|
|
|
6088
6064
|
"use strict";
|
|
6089
6065
|
VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
|
|
6090
6066
|
GoalStateError = class extends Error {
|
|
6091
|
-
constructor(
|
|
6092
|
-
super(`Invalid goal state at ${
|
|
6067
|
+
constructor(path46, message) {
|
|
6068
|
+
super(`Invalid goal state at ${path46}:
|
|
6093
6069
|
${message}`);
|
|
6094
|
-
this.path =
|
|
6070
|
+
this.path = path46;
|
|
6095
6071
|
this.name = "GoalStateError";
|
|
6096
6072
|
}
|
|
6097
6073
|
path;
|
|
@@ -6336,8 +6312,8 @@ function isStateUnchanged(prev, next) {
|
|
|
6336
6312
|
if (prev.done !== next.done) return false;
|
|
6337
6313
|
return JSON.stringify(prev.data) === JSON.stringify(next.data);
|
|
6338
6314
|
}
|
|
6339
|
-
function stateFilePath(jobsDir,
|
|
6340
|
-
return `${jobsDir.replace(/\/+$/, "")}/${
|
|
6315
|
+
function stateFilePath(jobsDir, slug2) {
|
|
6316
|
+
return `${jobsDir.replace(/\/+$/, "")}/${slug2}/state.json`;
|
|
6341
6317
|
}
|
|
6342
6318
|
function slugFromStateFilePath(filePath) {
|
|
6343
6319
|
if (/\/state\.json$/i.test(filePath)) {
|
|
@@ -6379,8 +6355,8 @@ var init_contentsApiBackend = __esm({
|
|
|
6379
6355
|
this.jobsDir = stateRepoJobsDir(opts.jobsDir);
|
|
6380
6356
|
this.cwd = opts.cwd;
|
|
6381
6357
|
}
|
|
6382
|
-
load(
|
|
6383
|
-
const filePath = stateFilePath(this.jobsDir,
|
|
6358
|
+
load(slug2) {
|
|
6359
|
+
const filePath = stateFilePath(this.jobsDir, slug2);
|
|
6384
6360
|
const loaded = readStateText(this.config, this.cwd, filePath);
|
|
6385
6361
|
if (!loaded) {
|
|
6386
6362
|
return { path: filePath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
@@ -6400,20 +6376,20 @@ var init_contentsApiBackend = __esm({
|
|
|
6400
6376
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
6401
6377
|
return false;
|
|
6402
6378
|
}
|
|
6403
|
-
const
|
|
6379
|
+
const slug2 = slugFromStateFilePath(loaded.path);
|
|
6404
6380
|
const body = `${JSON.stringify(next, null, 2)}
|
|
6405
6381
|
`;
|
|
6406
|
-
const message = `chore(jobs): update state for ${
|
|
6382
|
+
const message = `chore(jobs): update state for ${slug2} (rev ${next.rev})`;
|
|
6407
6383
|
const sha = typeof loaded.handle === "string" ? loaded.handle : void 0;
|
|
6408
6384
|
try {
|
|
6409
6385
|
writeStateText(this.config, this.cwd, loaded.path, body, message, sha);
|
|
6410
6386
|
} catch (err) {
|
|
6411
6387
|
if (!isShaConflict(err)) throw err;
|
|
6412
|
-
const current = this.load(
|
|
6388
|
+
const current = this.load(slug2);
|
|
6413
6389
|
if (!current.created && isStateUnchanged(current.state, next)) return false;
|
|
6414
6390
|
const currentSha = typeof current.handle === "string" ? current.handle : void 0;
|
|
6415
6391
|
process.stderr.write(
|
|
6416
|
-
`[kody] jobState: concurrent write detected for ${
|
|
6392
|
+
`[kody] jobState: concurrent write detected for ${slug2}; reloaded SHA and retrying (last-write-wins)
|
|
6417
6393
|
`
|
|
6418
6394
|
);
|
|
6419
6395
|
writeStateText(this.config, this.cwd, loaded.path, body, message, currentSha);
|
|
@@ -6540,8 +6516,8 @@ var init_localFileBackend = __esm({
|
|
|
6540
6516
|
`);
|
|
6541
6517
|
}
|
|
6542
6518
|
}
|
|
6543
|
-
load(
|
|
6544
|
-
const relPath = stateFilePath(this.jobsDir,
|
|
6519
|
+
load(slug2) {
|
|
6520
|
+
const relPath = stateFilePath(this.jobsDir, slug2);
|
|
6545
6521
|
const absPath = path24.join(this.cwd, relPath);
|
|
6546
6522
|
if (!fs25.existsSync(absPath)) {
|
|
6547
6523
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
@@ -6613,29 +6589,63 @@ import * as path25 from "path";
|
|
|
6613
6589
|
function isAgentResponsibilityCadenceGoal(goal, extra) {
|
|
6614
6590
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.agentResponsibilities.length > 0;
|
|
6615
6591
|
}
|
|
6616
|
-
|
|
6592
|
+
function isGoalTargetLoop(goal) {
|
|
6593
|
+
return goal.type === "agentLoop" && goal.loopTarget?.type === "goal" && goal.loopTarget.id.trim().length > 0;
|
|
6594
|
+
}
|
|
6595
|
+
function planGoalTargetLoopSchedule(opts) {
|
|
6617
6596
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
6618
6597
|
const at = now.toISOString();
|
|
6598
|
+
const targetId = opts.goal.loopTarget?.type === "goal" ? opts.goal.loopTarget.id.trim() : "";
|
|
6599
|
+
if (!targetId) {
|
|
6600
|
+
const reason = "goal target loop missing target goal";
|
|
6601
|
+
return targetLoopDecision("blocked", reason, at);
|
|
6602
|
+
}
|
|
6603
|
+
const preferred = opts.goal.preferredRunTime;
|
|
6604
|
+
if (preferred) {
|
|
6605
|
+
const gate = preferredRunTimeGate(preferred, now, opts.previousScheduleState);
|
|
6606
|
+
if (!gate.ok) return targetLoopDecision("idle", gate.reason, at);
|
|
6607
|
+
}
|
|
6608
|
+
return {
|
|
6609
|
+
kind: "dispatch",
|
|
6610
|
+
reason: `dispatch goal ${targetId}`,
|
|
6611
|
+
dispatch: { action: "goal-manager", agentAction: "goal-manager", cliArgs: { goal: targetId } },
|
|
6612
|
+
scheduleState: {
|
|
6613
|
+
mode: "agentLoop",
|
|
6614
|
+
lastGoalTickAt: at,
|
|
6615
|
+
lastDecision: {
|
|
6616
|
+
kind: "dispatch",
|
|
6617
|
+
targetType: "goal",
|
|
6618
|
+
targetId,
|
|
6619
|
+
agentAction: "goal-manager",
|
|
6620
|
+
reason: preferred ? `preferred time ${preferred.time} ${preferred.timezone}` : "ready target loop tick",
|
|
6621
|
+
at
|
|
6622
|
+
},
|
|
6623
|
+
agentResponsibilities: {}
|
|
6624
|
+
}
|
|
6625
|
+
};
|
|
6626
|
+
}
|
|
6627
|
+
async function planGoalAgentResponsibilitySchedule(opts) {
|
|
6619
6628
|
const jobsDir = opts.jobsDir ?? ".kody/agent-responsibilities";
|
|
6620
6629
|
const jobsRoot = path25.join(opts.cwd, jobsDir);
|
|
6630
|
+
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
6631
|
+
const at = now.toISOString();
|
|
6621
6632
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
6622
6633
|
const statuses = {};
|
|
6623
6634
|
const blockers = [];
|
|
6624
|
-
for (const
|
|
6625
|
-
const agentResponsibility2 = resolveAgentResponsibilityFolder(
|
|
6635
|
+
for (const slug2 of opts.goal.agentResponsibilities) {
|
|
6636
|
+
const agentResponsibility2 = resolveAgentResponsibilityFolder(slug2, jobsRoot);
|
|
6626
6637
|
const status = await describeAgentResponsibilitySchedule(
|
|
6627
6638
|
agentResponsibility2,
|
|
6628
|
-
|
|
6639
|
+
slug2,
|
|
6629
6640
|
backend,
|
|
6630
|
-
|
|
6631
|
-
opts.previousScheduleState?.agentResponsibilities[slug]
|
|
6641
|
+
opts.previousScheduleState?.agentResponsibilities[slug2]
|
|
6632
6642
|
);
|
|
6633
|
-
statuses[
|
|
6634
|
-
if (status.state === "blocked") blockers.push(`${
|
|
6643
|
+
statuses[slug2] = status;
|
|
6644
|
+
if (status.state === "blocked") blockers.push(`${slug2}: ${status.reason}`);
|
|
6635
6645
|
}
|
|
6636
|
-
const due = opts.goal.agentResponsibilities.map((
|
|
6646
|
+
const due = opts.goal.agentResponsibilities.map((slug2) => statuses[slug2]).filter((status) => status?.state === "due").sort(compareOldestLastFired)[0];
|
|
6637
6647
|
if (!due) {
|
|
6638
|
-
const reason = blockers.length > 0 ? "no runnable
|
|
6648
|
+
const reason = blockers.length > 0 ? "no runnable agentResponsibility; blocked agentResponsibilities need attention" : "no runnable agentResponsibility";
|
|
6639
6649
|
const kind = blockers.length > 0 ? "blocked" : "idle";
|
|
6640
6650
|
return {
|
|
6641
6651
|
kind,
|
|
@@ -6682,29 +6692,19 @@ async function planGoalAgentResponsibilitySchedule(opts) {
|
|
|
6682
6692
|
}
|
|
6683
6693
|
};
|
|
6684
6694
|
}
|
|
6685
|
-
async function describeAgentResponsibilitySchedule(agentResponsibility,
|
|
6686
|
-
if (!agentResponsibility) return { slug, state: "blocked", reason: "agentResponsibility folder missing" };
|
|
6695
|
+
async function describeAgentResponsibilitySchedule(agentResponsibility, slug2, backend, previous) {
|
|
6696
|
+
if (!agentResponsibility) return { slug: slug2, state: "blocked", reason: "agentResponsibility folder missing" };
|
|
6687
6697
|
const { config } = agentResponsibility;
|
|
6688
6698
|
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" };
|
|
6699
|
+
return { slug: slug2, title: agentResponsibility.title, state: "disabled", reason: "disabled" };
|
|
6693
6700
|
}
|
|
6694
6701
|
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
|
-
};
|
|
6702
|
+
return { slug: slug2, title: agentResponsibility.title, state: "blocked", reason: "no agent assigned" };
|
|
6702
6703
|
}
|
|
6703
6704
|
if (config.agentActions && config.agentActions.length > 1) {
|
|
6704
6705
|
return {
|
|
6705
|
-
slug,
|
|
6706
|
+
slug: slug2,
|
|
6706
6707
|
title: agentResponsibility.title,
|
|
6707
|
-
cadence: config.every,
|
|
6708
6708
|
state: "blocked",
|
|
6709
6709
|
reason: "multi-agentAction agentResponsibility needs task-jobs route"
|
|
6710
6710
|
};
|
|
@@ -6712,79 +6712,104 @@ async function describeAgentResponsibilitySchedule(agentResponsibility, slug, ba
|
|
|
6712
6712
|
let lastFiredAt = validIso(previous?.lastFiredAt) ? previous?.lastFiredAt : void 0;
|
|
6713
6713
|
try {
|
|
6714
6714
|
if (!lastFiredAt) {
|
|
6715
|
-
const loaded = await backend.load(
|
|
6715
|
+
const loaded = await backend.load(slug2);
|
|
6716
6716
|
const raw = loaded.state.data?.lastFiredAt;
|
|
6717
6717
|
if (typeof raw === "string" && validIso(raw)) lastFiredAt = raw;
|
|
6718
6718
|
}
|
|
6719
6719
|
} catch {
|
|
6720
6720
|
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,
|
|
6721
|
+
slug: slug2,
|
|
6731
6722
|
title: agentResponsibility.title,
|
|
6732
6723
|
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
|
|
6724
|
+
reason: "state unreadable; ready for loop tick"
|
|
6758
6725
|
};
|
|
6759
6726
|
}
|
|
6760
6727
|
return {
|
|
6761
|
-
slug,
|
|
6728
|
+
slug: slug2,
|
|
6762
6729
|
title: agentResponsibility.title,
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
lastFiredAt,
|
|
6767
|
-
nextEligibleAt: next
|
|
6730
|
+
state: "due",
|
|
6731
|
+
reason: "ready for loop tick",
|
|
6732
|
+
lastFiredAt
|
|
6768
6733
|
};
|
|
6769
6734
|
}
|
|
6770
6735
|
function dutyDispatch(agentResponsibility) {
|
|
6771
6736
|
const { agentAction, cliArgs } = resolveAgentResponsibilityExecution(agentResponsibility);
|
|
6772
6737
|
return { agentResponsibility: agentResponsibility.slug, agentAction, cliArgs };
|
|
6773
6738
|
}
|
|
6739
|
+
function compareOldestLastFired(a, b) {
|
|
6740
|
+
const aTime = validIso(a.lastFiredAt) ? Date.parse(a.lastFiredAt) : Number.NEGATIVE_INFINITY;
|
|
6741
|
+
const bTime = validIso(b.lastFiredAt) ? Date.parse(b.lastFiredAt) : Number.NEGATIVE_INFINITY;
|
|
6742
|
+
return aTime - bTime;
|
|
6743
|
+
}
|
|
6774
6744
|
function validIso(value) {
|
|
6775
6745
|
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
6776
6746
|
}
|
|
6777
6747
|
function markAgentResponsibilitySelected(status, now) {
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6748
|
+
return { ...status, lastFiredAt: now.toISOString() };
|
|
6749
|
+
}
|
|
6750
|
+
function targetLoopDecision(kind, reason, at) {
|
|
6751
|
+
return {
|
|
6752
|
+
kind,
|
|
6753
|
+
reason,
|
|
6754
|
+
scheduleState: {
|
|
6755
|
+
mode: "agentLoop",
|
|
6756
|
+
lastGoalTickAt: at,
|
|
6757
|
+
lastDecision: { kind, reason, at },
|
|
6758
|
+
agentResponsibilities: {}
|
|
6759
|
+
}
|
|
6760
|
+
};
|
|
6761
|
+
}
|
|
6762
|
+
function preferredRunTimeGate(preferred, now, previous) {
|
|
6763
|
+
const current = zonedTimeParts(now, preferred.timezone);
|
|
6764
|
+
if (!current) return { ok: false, reason: `invalid preferred timezone: ${preferred.timezone}` };
|
|
6765
|
+
const preferredMinute = preferredTimeToMinute(preferred.time);
|
|
6766
|
+
if (preferredMinute === null) return { ok: false, reason: `invalid preferred time: ${preferred.time}` };
|
|
6767
|
+
const currentMinute = current.hour * 60 + current.minute;
|
|
6768
|
+
if (currentMinute < preferredMinute) {
|
|
6769
|
+
return { ok: false, reason: `waiting preferred time ${preferred.time} ${preferred.timezone}` };
|
|
6770
|
+
}
|
|
6771
|
+
const lastDispatchAt = previous?.lastDecision.kind === "dispatch" ? previous.lastDecision.at : void 0;
|
|
6772
|
+
if (lastDispatchAt) {
|
|
6773
|
+
const last = zonedTimeParts(new Date(lastDispatchAt), preferred.timezone);
|
|
6774
|
+
if (last?.date === current.date) {
|
|
6775
|
+
return { ok: false, reason: `already dispatched today at preferred time ${preferred.time} ${preferred.timezone}` };
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6778
|
+
return { ok: true };
|
|
6779
|
+
}
|
|
6780
|
+
function preferredTimeToMinute(value) {
|
|
6781
|
+
const match = value.match(/^([01]\d|2[0-3]):([0-5]\d)$/);
|
|
6782
|
+
if (!match) return null;
|
|
6783
|
+
return Number(match[1]) * 60 + Number(match[2]);
|
|
6784
|
+
}
|
|
6785
|
+
function zonedTimeParts(date, timezone) {
|
|
6786
|
+
try {
|
|
6787
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
6788
|
+
timeZone: timezone,
|
|
6789
|
+
year: "numeric",
|
|
6790
|
+
month: "2-digit",
|
|
6791
|
+
day: "2-digit",
|
|
6792
|
+
hour: "2-digit",
|
|
6793
|
+
minute: "2-digit",
|
|
6794
|
+
hourCycle: "h23"
|
|
6795
|
+
}).formatToParts(date);
|
|
6796
|
+
const get = (type) => parts.find((part) => part.type === type)?.value;
|
|
6797
|
+
const year = get("year");
|
|
6798
|
+
const month = get("month");
|
|
6799
|
+
const day = get("day");
|
|
6800
|
+
const hour = get("hour");
|
|
6801
|
+
const minute = get("minute");
|
|
6802
|
+
if (!year || !month || !day || !hour || !minute) return null;
|
|
6803
|
+
return { date: `${year}-${month}-${day}`, hour: Number(hour), minute: Number(minute) };
|
|
6804
|
+
} catch {
|
|
6805
|
+
return null;
|
|
6806
|
+
}
|
|
6781
6807
|
}
|
|
6782
6808
|
var init_goalAgentResponsibilityScheduling = __esm({
|
|
6783
6809
|
"src/scripts/goalAgentResponsibilityScheduling.ts"() {
|
|
6784
6810
|
"use strict";
|
|
6785
6811
|
init_registry();
|
|
6786
6812
|
init_jobState();
|
|
6787
|
-
init_scheduleEvery();
|
|
6788
6813
|
}
|
|
6789
6814
|
});
|
|
6790
6815
|
|
|
@@ -6812,8 +6837,8 @@ function routeNeedsIssueFact(goal) {
|
|
|
6812
6837
|
return goal.route.some(
|
|
6813
6838
|
(step) => Object.values(step.args ?? {}).some((value) => {
|
|
6814
6839
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
6815
|
-
const
|
|
6816
|
-
return Object.keys(
|
|
6840
|
+
const record2 = value;
|
|
6841
|
+
return Object.keys(record2).length === 1 && record2.fact === "issue";
|
|
6817
6842
|
})
|
|
6818
6843
|
);
|
|
6819
6844
|
}
|
|
@@ -6891,6 +6916,23 @@ var init_advanceManagedGoal = __esm({
|
|
|
6891
6916
|
ctx.output.reason = reason;
|
|
6892
6917
|
return;
|
|
6893
6918
|
}
|
|
6919
|
+
if (isGoalTargetLoop(managed)) {
|
|
6920
|
+
const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
|
|
6921
|
+
const decision2 = planGoalTargetLoopSchedule({ goal: managed, previousScheduleState });
|
|
6922
|
+
restoreGoalIdFact();
|
|
6923
|
+
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
6924
|
+
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
6925
|
+
ctx.data.managedGoalDecision = decision2;
|
|
6926
|
+
if (decision2.kind === "dispatch" && decision2.dispatch) {
|
|
6927
|
+
ctx.output.nextDispatch = {
|
|
6928
|
+
action: decision2.dispatch.action,
|
|
6929
|
+
agentAction: decision2.dispatch.agentAction,
|
|
6930
|
+
cliArgs: decision2.dispatch.cliArgs
|
|
6931
|
+
};
|
|
6932
|
+
}
|
|
6933
|
+
ctx.output.reason = decision2.reason;
|
|
6934
|
+
return;
|
|
6935
|
+
}
|
|
6894
6936
|
if (isAgentResponsibilityCadenceGoal(managed, goal.raw.extra)) {
|
|
6895
6937
|
const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
|
|
6896
6938
|
const decision2 = await planGoalAgentResponsibilitySchedule({
|
|
@@ -6907,7 +6949,8 @@ var init_advanceManagedGoal = __esm({
|
|
|
6907
6949
|
ctx.output.nextDispatch = {
|
|
6908
6950
|
agentResponsibility: decision2.dispatch.agentResponsibility,
|
|
6909
6951
|
agentAction: decision2.dispatch.agentAction,
|
|
6910
|
-
cliArgs: decision2.dispatch.cliArgs
|
|
6952
|
+
cliArgs: decision2.dispatch.cliArgs,
|
|
6953
|
+
...goal.raw.extra.saveReport === true ? { saveReport: true } : {}
|
|
6911
6954
|
};
|
|
6912
6955
|
}
|
|
6913
6956
|
ctx.output.reason = decision2.reason;
|
|
@@ -6930,7 +6973,8 @@ var init_advanceManagedGoal = __esm({
|
|
|
6930
6973
|
ctx.output.nextDispatch = {
|
|
6931
6974
|
agentResponsibility: decision.agentResponsibility,
|
|
6932
6975
|
agentAction: decision.agentAction,
|
|
6933
|
-
cliArgs: decision.cliArgs
|
|
6976
|
+
cliArgs: decision.cliArgs,
|
|
6977
|
+
...decision.saveReport === true ? { saveReport: true } : {}
|
|
6934
6978
|
};
|
|
6935
6979
|
ctx.output.reason = `dispatch ${decision.agentResponsibility} for ${decision.evidence}`;
|
|
6936
6980
|
};
|
|
@@ -6944,9 +6988,9 @@ function resolveTrigger(force) {
|
|
|
6944
6988
|
if (force || event === "issue_comment" || event === "workflow_dispatch") return "manual";
|
|
6945
6989
|
return "event";
|
|
6946
6990
|
}
|
|
6947
|
-
function appendLine(ctx,
|
|
6948
|
-
const filePath = `activity/${
|
|
6949
|
-
appendStateLine(ctx.config, ctx.cwd, filePath, JSON.stringify(
|
|
6991
|
+
function appendLine(ctx, record2) {
|
|
6992
|
+
const filePath = `activity/${record2.ts.slice(0, 10)}.jsonl`;
|
|
6993
|
+
appendStateLine(ctx.config, ctx.cwd, filePath, JSON.stringify(record2), `chore(activity): ${record2.action}`);
|
|
6950
6994
|
}
|
|
6951
6995
|
var appendCompanyActivity;
|
|
6952
6996
|
var init_appendCompanyActivity = __esm({
|
|
@@ -6962,7 +7006,7 @@ var init_appendCompanyActivity = __esm({
|
|
|
6962
7006
|
const agent = ctx.data.agentSlug || null;
|
|
6963
7007
|
const agentTitle = ctx.data.agentTitle || null;
|
|
6964
7008
|
const force = ctx.args?.force === true;
|
|
6965
|
-
const
|
|
7009
|
+
const record2 = {
|
|
6966
7010
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6967
7011
|
action: `Ran agentResponsibility: ${agentResponsibilityTitle ?? agentResponsibility}`,
|
|
6968
7012
|
agentResponsibility,
|
|
@@ -6976,7 +7020,7 @@ var init_appendCompanyActivity = __esm({
|
|
|
6976
7020
|
durationMs: agentResult?.durationMs ?? null,
|
|
6977
7021
|
runUrl: getRunUrl() || null
|
|
6978
7022
|
};
|
|
6979
|
-
appendLine(ctx,
|
|
7023
|
+
appendLine(ctx, record2);
|
|
6980
7024
|
} catch (err) {
|
|
6981
7025
|
process.stderr.write(
|
|
6982
7026
|
`[activity] company-activity append failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -6987,6 +7031,338 @@ var init_appendCompanyActivity = __esm({
|
|
|
6987
7031
|
}
|
|
6988
7032
|
});
|
|
6989
7033
|
|
|
7034
|
+
// src/companyManagerDecision.ts
|
|
7035
|
+
function parseCompanyManagerDecisionText(finalText) {
|
|
7036
|
+
const raw = extractDecisionJson(finalText);
|
|
7037
|
+
const parsed = JSON.parse(raw);
|
|
7038
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
7039
|
+
throw new Error("company-manager decision must be JSON object");
|
|
7040
|
+
}
|
|
7041
|
+
const input = parsed;
|
|
7042
|
+
const actions = Array.isArray(input.actions) ? input.actions.map(parseAction) : [];
|
|
7043
|
+
return {
|
|
7044
|
+
summary: typeof input.summary === "string" ? input.summary.trim() : "",
|
|
7045
|
+
actions
|
|
7046
|
+
};
|
|
7047
|
+
}
|
|
7048
|
+
function buildManagedGoalState(action) {
|
|
7049
|
+
const at = nowIso();
|
|
7050
|
+
return {
|
|
7051
|
+
state: "active",
|
|
7052
|
+
createdAt: at,
|
|
7053
|
+
updatedAt: at,
|
|
7054
|
+
extra: {
|
|
7055
|
+
type: action.goalType ?? "release",
|
|
7056
|
+
destination: { outcome: action.outcome, evidence: action.evidence },
|
|
7057
|
+
agentResponsibilities: action.agentResponsibilities,
|
|
7058
|
+
route: action.route,
|
|
7059
|
+
facts: action.facts ?? {},
|
|
7060
|
+
blockers: [],
|
|
7061
|
+
createdByIntent: action.intentId,
|
|
7062
|
+
manager: "cto"
|
|
7063
|
+
}
|
|
7064
|
+
};
|
|
7065
|
+
}
|
|
7066
|
+
function buildAgentLoopState(action) {
|
|
7067
|
+
const at = nowIso();
|
|
7068
|
+
return {
|
|
7069
|
+
state: "active",
|
|
7070
|
+
createdAt: at,
|
|
7071
|
+
updatedAt: at,
|
|
7072
|
+
extra: {
|
|
7073
|
+
type: "agentLoop",
|
|
7074
|
+
scheduleMode: "agentLoop",
|
|
7075
|
+
schedule: action.every,
|
|
7076
|
+
destination: { outcome: action.outcome, evidence: [] },
|
|
7077
|
+
agentResponsibilities: action.agentResponsibilities,
|
|
7078
|
+
route: [],
|
|
7079
|
+
facts: {},
|
|
7080
|
+
blockers: [],
|
|
7081
|
+
createdByIntent: action.intentId,
|
|
7082
|
+
manager: "cto"
|
|
7083
|
+
}
|
|
7084
|
+
};
|
|
7085
|
+
}
|
|
7086
|
+
function extractDecisionJson(finalText) {
|
|
7087
|
+
const fence = finalText.match(/```(?:kody-company-manager-decision|json)\s*([\s\S]*?)```/i);
|
|
7088
|
+
if (fence?.[1]) return fence[1].trim();
|
|
7089
|
+
const line = finalText.match(/KODY_COMPANY_MANAGER_DECISION=(\{[\s\S]*\})/);
|
|
7090
|
+
if (line?.[1]) return line[1].trim();
|
|
7091
|
+
throw new Error("missing kody-company-manager-decision JSON");
|
|
7092
|
+
}
|
|
7093
|
+
function parseAction(value) {
|
|
7094
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
7095
|
+
throw new Error("company-manager action must be object");
|
|
7096
|
+
}
|
|
7097
|
+
const input = value;
|
|
7098
|
+
const kind = input.kind;
|
|
7099
|
+
if (kind === "createManagedGoal") return parseCreateManagedGoal(input);
|
|
7100
|
+
if (kind === "createAgentLoop") return parseCreateAgentLoop(input);
|
|
7101
|
+
if (kind === "setGoalLifecycle") return parseSetGoalLifecycle(input);
|
|
7102
|
+
if (kind === "updateIntentPortfolio") return parseUpdateIntentPortfolio(input);
|
|
7103
|
+
if (kind === "note") return parseNote(input);
|
|
7104
|
+
throw new Error(`unsupported company-manager action kind: ${String(kind)}`);
|
|
7105
|
+
}
|
|
7106
|
+
function parseCreateManagedGoal(input) {
|
|
7107
|
+
const route = Array.isArray(input.route) ? input.route.map(parseRouteStep) : [];
|
|
7108
|
+
if (route.length === 0) throw new Error("createManagedGoal requires route");
|
|
7109
|
+
const evidence = stringArray2(input.evidence);
|
|
7110
|
+
if (evidence.length === 0) throw new Error("createManagedGoal requires evidence");
|
|
7111
|
+
return {
|
|
7112
|
+
kind: "createManagedGoal",
|
|
7113
|
+
intentId: slug(input.intentId, "intentId"),
|
|
7114
|
+
id: slug(input.id, "id"),
|
|
7115
|
+
outcome: requiredString(input.outcome, "outcome"),
|
|
7116
|
+
goalType: typeof input.goalType === "string" && input.goalType.trim() ? input.goalType.trim() : void 0,
|
|
7117
|
+
evidence,
|
|
7118
|
+
agentResponsibilities: nonEmptyStringArray(input.agentResponsibilities, "agentResponsibilities"),
|
|
7119
|
+
route,
|
|
7120
|
+
facts: record(input.facts) ?? {},
|
|
7121
|
+
reason: requiredString(input.reason, "reason")
|
|
7122
|
+
};
|
|
7123
|
+
}
|
|
7124
|
+
function parseCreateAgentLoop(input) {
|
|
7125
|
+
return {
|
|
7126
|
+
kind: "createAgentLoop",
|
|
7127
|
+
intentId: slug(input.intentId, "intentId"),
|
|
7128
|
+
id: slug(input.id, "id"),
|
|
7129
|
+
outcome: requiredString(input.outcome, "outcome"),
|
|
7130
|
+
every: oneOf(input.every, ["manual", "1h", "1d", "7d", "30d"], "1d"),
|
|
7131
|
+
agentResponsibilities: nonEmptyStringArray(input.agentResponsibilities, "agentResponsibilities"),
|
|
7132
|
+
reason: requiredString(input.reason, "reason")
|
|
7133
|
+
};
|
|
7134
|
+
}
|
|
7135
|
+
function parseSetGoalLifecycle(input) {
|
|
7136
|
+
return {
|
|
7137
|
+
kind: "setGoalLifecycle",
|
|
7138
|
+
intentId: slug(input.intentId, "intentId"),
|
|
7139
|
+
id: slug(input.id, "id"),
|
|
7140
|
+
state: oneOf(input.state, ["active", "closed", "abandoned"], "active"),
|
|
7141
|
+
reason: requiredString(input.reason, "reason")
|
|
7142
|
+
};
|
|
7143
|
+
}
|
|
7144
|
+
function parseUpdateIntentPortfolio(input) {
|
|
7145
|
+
return {
|
|
7146
|
+
kind: "updateIntentPortfolio",
|
|
7147
|
+
intentId: slug(input.intentId, "intentId"),
|
|
7148
|
+
goals: stringArray2(input.goals).filter(isSlug),
|
|
7149
|
+
loops: stringArray2(input.loops).filter(isSlug),
|
|
7150
|
+
responsibilities: stringArray2(input.responsibilities).filter(isSlug),
|
|
7151
|
+
reason: requiredString(input.reason, "reason")
|
|
7152
|
+
};
|
|
7153
|
+
}
|
|
7154
|
+
function parseNote(input) {
|
|
7155
|
+
return {
|
|
7156
|
+
kind: "note",
|
|
7157
|
+
intentId: typeof input.intentId === "string" && isSlug(input.intentId) ? input.intentId : void 0,
|
|
7158
|
+
message: requiredString(input.message ?? input.content, "message")
|
|
7159
|
+
};
|
|
7160
|
+
}
|
|
7161
|
+
function parseRouteStep(value) {
|
|
7162
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("route step must be object");
|
|
7163
|
+
const input = value;
|
|
7164
|
+
return {
|
|
7165
|
+
stage: requiredString(input.stage, "route.stage"),
|
|
7166
|
+
evidence: requiredString(input.evidence, "route.evidence"),
|
|
7167
|
+
agentResponsibility: slug(input.agentResponsibility, "route.agentResponsibility"),
|
|
7168
|
+
...typeof input.agentAction === "string" && input.agentAction.trim() ? { agentAction: input.agentAction.trim() } : {},
|
|
7169
|
+
...record(input.args) ? { args: record(input.args) } : {}
|
|
7170
|
+
};
|
|
7171
|
+
}
|
|
7172
|
+
function slug(value, field) {
|
|
7173
|
+
const text = requiredString(value, field);
|
|
7174
|
+
if (!isSlug(text)) throw new Error(`${field} must be lowercase slug`);
|
|
7175
|
+
return text;
|
|
7176
|
+
}
|
|
7177
|
+
function isSlug(value) {
|
|
7178
|
+
return SLUG_RE.test(value);
|
|
7179
|
+
}
|
|
7180
|
+
function requiredString(value, field) {
|
|
7181
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`${field} is required`);
|
|
7182
|
+
return value.trim();
|
|
7183
|
+
}
|
|
7184
|
+
function stringArray2(value) {
|
|
7185
|
+
if (!Array.isArray(value)) return [];
|
|
7186
|
+
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
7187
|
+
}
|
|
7188
|
+
function nonEmptyStringArray(value, field) {
|
|
7189
|
+
const values = stringArray2(value);
|
|
7190
|
+
if (values.length === 0) throw new Error(`${field} must not be empty`);
|
|
7191
|
+
return values;
|
|
7192
|
+
}
|
|
7193
|
+
function record(value) {
|
|
7194
|
+
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : null;
|
|
7195
|
+
}
|
|
7196
|
+
function oneOf(value, allowed, fallback) {
|
|
7197
|
+
return typeof value === "string" && allowed.includes(value) ? value : fallback;
|
|
7198
|
+
}
|
|
7199
|
+
var SLUG_RE;
|
|
7200
|
+
var init_companyManagerDecision = __esm({
|
|
7201
|
+
"src/companyManagerDecision.ts"() {
|
|
7202
|
+
"use strict";
|
|
7203
|
+
init_state2();
|
|
7204
|
+
SLUG_RE = /^[a-z][a-z0-9-]{0,63}$/;
|
|
7205
|
+
}
|
|
7206
|
+
});
|
|
7207
|
+
|
|
7208
|
+
// src/companyIntent.ts
|
|
7209
|
+
function isCompanyIntentId(value) {
|
|
7210
|
+
return SLUG_RE2.test(value);
|
|
7211
|
+
}
|
|
7212
|
+
function companyIntentPath(id) {
|
|
7213
|
+
assertIntentId(id);
|
|
7214
|
+
return `intents/${id}/intent.json`;
|
|
7215
|
+
}
|
|
7216
|
+
function normalizeCompanyIntent(path46, raw) {
|
|
7217
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
7218
|
+
throw new Error(`${path46}: intent must be JSON object`);
|
|
7219
|
+
}
|
|
7220
|
+
const input = raw;
|
|
7221
|
+
const id = stringField2(input.id);
|
|
7222
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path46}: invalid intent id`);
|
|
7223
|
+
const createdAt = stringField2(input.createdAt) || nowIso();
|
|
7224
|
+
const updatedAt = stringField2(input.updatedAt) || createdAt;
|
|
7225
|
+
return {
|
|
7226
|
+
version: 1,
|
|
7227
|
+
id,
|
|
7228
|
+
status: oneOf2(input.status, ["active", "paused", "archived"], "active"),
|
|
7229
|
+
for: stringField2(input.for),
|
|
7230
|
+
priority: numberField(input.priority, 100),
|
|
7231
|
+
posture: oneOf2(
|
|
7232
|
+
input.posture,
|
|
7233
|
+
["confidence", "speed", "stability-recovery", "maintenance", "balanced"],
|
|
7234
|
+
"balanced"
|
|
7235
|
+
),
|
|
7236
|
+
scope: {
|
|
7237
|
+
repos: stringArray3(recordField(input.scope)?.repos),
|
|
7238
|
+
areas: stringArray3(recordField(input.scope)?.areas)
|
|
7239
|
+
},
|
|
7240
|
+
principles: stringArray3(input.principles),
|
|
7241
|
+
metrics: stringArray3(input.metrics),
|
|
7242
|
+
policy: {
|
|
7243
|
+
release: normalizeReleasePolicy(recordField(recordField(input.policy)?.release)),
|
|
7244
|
+
automation: normalizeAutomationPolicy(recordField(recordField(input.policy)?.automation))
|
|
7245
|
+
},
|
|
7246
|
+
portfolio: {
|
|
7247
|
+
goals: stringArray3(recordField(input.portfolio)?.goals).filter(isCompanyIntentId),
|
|
7248
|
+
loops: stringArray3(recordField(input.portfolio)?.loops).filter(isCompanyIntentId),
|
|
7249
|
+
responsibilities: stringArray3(recordField(input.portfolio)?.responsibilities).filter(isCompanyIntentId)
|
|
7250
|
+
},
|
|
7251
|
+
manager: normalizeManager(recordField(input.manager)),
|
|
7252
|
+
createdAt,
|
|
7253
|
+
updatedAt
|
|
7254
|
+
};
|
|
7255
|
+
}
|
|
7256
|
+
function listCompanyIntents(config, cwd) {
|
|
7257
|
+
const entries = listStateDirectory(config, cwd, "intents");
|
|
7258
|
+
const records = [];
|
|
7259
|
+
for (const entry of entries) {
|
|
7260
|
+
if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
|
|
7261
|
+
const path46 = companyIntentPath(entry.name);
|
|
7262
|
+
const file = readStateText(config, cwd, path46);
|
|
7263
|
+
if (!file) continue;
|
|
7264
|
+
records.push({
|
|
7265
|
+
id: entry.name,
|
|
7266
|
+
path: file.path,
|
|
7267
|
+
intent: normalizeCompanyIntent(file.path, JSON.parse(file.content))
|
|
7268
|
+
});
|
|
7269
|
+
}
|
|
7270
|
+
return records.sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
|
|
7271
|
+
}
|
|
7272
|
+
function readCompanyIntent(config, cwd, id) {
|
|
7273
|
+
const path46 = companyIntentPath(id);
|
|
7274
|
+
const file = readStateText(config, cwd, path46);
|
|
7275
|
+
if (!file) return null;
|
|
7276
|
+
return { id, path: file.path, intent: normalizeCompanyIntent(file.path, JSON.parse(file.content)) };
|
|
7277
|
+
}
|
|
7278
|
+
function writeCompanyIntent(config, cwd, intent, message = `chore(intents): update ${intent.id}`) {
|
|
7279
|
+
upsertStateText(config, cwd, companyIntentPath(intent.id), `${JSON.stringify(intent, null, 2)}
|
|
7280
|
+
`, message);
|
|
7281
|
+
}
|
|
7282
|
+
function appendCompanyIntentDecision(config, cwd, intentId, entry) {
|
|
7283
|
+
assertIntentId(intentId);
|
|
7284
|
+
appendStateLine(config, cwd, `intents/${intentId}/decisions.jsonl`, JSON.stringify(entry), `chore(intents): log ${intentId} decision`);
|
|
7285
|
+
}
|
|
7286
|
+
function listCompanyPortfolio(config, cwd) {
|
|
7287
|
+
const entries = listStateDirectory(config, cwd, "goals/instances");
|
|
7288
|
+
const goals = [];
|
|
7289
|
+
for (const entry of entries) {
|
|
7290
|
+
if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
|
|
7291
|
+
const file = readStateText(config, cwd, `goals/instances/${entry.name}/state.json`);
|
|
7292
|
+
if (!file) continue;
|
|
7293
|
+
const state = parseGoalState(file.path, JSON.parse(file.content));
|
|
7294
|
+
const destination = recordField(state.extra.destination);
|
|
7295
|
+
goals.push({
|
|
7296
|
+
id: entry.name,
|
|
7297
|
+
state: state.state,
|
|
7298
|
+
type: stringField2(state.extra.type) || void 0,
|
|
7299
|
+
outcome: stringField2(destination?.outcome) || void 0,
|
|
7300
|
+
agentResponsibilities: stringArray3(state.extra.agentResponsibilities),
|
|
7301
|
+
isLoop: state.extra.scheduleMode === "agentLoop" || state.extra.type === "agentLoop",
|
|
7302
|
+
updatedAt: state.updatedAt
|
|
7303
|
+
});
|
|
7304
|
+
}
|
|
7305
|
+
return { goals: goals.sort((a, b) => a.id.localeCompare(b.id)) };
|
|
7306
|
+
}
|
|
7307
|
+
function writeCompanyGoalState(config, cwd, id, state, message) {
|
|
7308
|
+
assertIntentId(id);
|
|
7309
|
+
upsertStateText(config, cwd, `goals/instances/${id}/state.json`, serializeGoalState(state), message);
|
|
7310
|
+
}
|
|
7311
|
+
function assertIntentId(id) {
|
|
7312
|
+
if (!isCompanyIntentId(id)) throw new Error(`invalid intent/portfolio id: ${id}`);
|
|
7313
|
+
}
|
|
7314
|
+
function stringField2(value) {
|
|
7315
|
+
return typeof value === "string" ? value.trim() : "";
|
|
7316
|
+
}
|
|
7317
|
+
function numberField(value, fallback) {
|
|
7318
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
7319
|
+
}
|
|
7320
|
+
function recordField(value) {
|
|
7321
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7322
|
+
}
|
|
7323
|
+
function stringArray3(value) {
|
|
7324
|
+
if (!Array.isArray(value)) return [];
|
|
7325
|
+
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
7326
|
+
}
|
|
7327
|
+
function oneOf2(value, allowed, fallback) {
|
|
7328
|
+
return typeof value === "string" && allowed.includes(value) ? value : fallback;
|
|
7329
|
+
}
|
|
7330
|
+
function normalizeReleasePolicy(raw) {
|
|
7331
|
+
if (!raw) return void 0;
|
|
7332
|
+
return {
|
|
7333
|
+
cadence: oneOf2(raw.cadence, ["manual", "1d", "1w"], "manual"),
|
|
7334
|
+
qaDepth: oneOf2(raw.qaDepth, ["light", "standard", "strict"], "standard"),
|
|
7335
|
+
blockerLevel: oneOf2(raw.blockerLevel, ["low", "standard", "strict"], "standard"),
|
|
7336
|
+
approval: oneOf2(raw.approval, ["none", "before-production", "before-risky-actions"], "before-risky-actions")
|
|
7337
|
+
};
|
|
7338
|
+
}
|
|
7339
|
+
function normalizeAutomationPolicy(raw) {
|
|
7340
|
+
return {
|
|
7341
|
+
authority: "full-auto",
|
|
7342
|
+
maxConcurrentGoals: Math.max(1, Math.floor(numberField(raw?.maxConcurrentGoals, 1))),
|
|
7343
|
+
maxDailyActions: Math.max(1, Math.floor(numberField(raw?.maxDailyActions, 6))),
|
|
7344
|
+
requiresHumanFor: stringArray3(raw?.requiresHumanFor)
|
|
7345
|
+
};
|
|
7346
|
+
}
|
|
7347
|
+
function normalizeManager(raw) {
|
|
7348
|
+
return {
|
|
7349
|
+
agent: "cto",
|
|
7350
|
+
loop: "company-manager-loop",
|
|
7351
|
+
responsibility: "company-manager",
|
|
7352
|
+
reviewEvery: oneOf2(raw?.reviewEvery, ["1d", "1w"], "1d"),
|
|
7353
|
+
...typeof raw?.lastReviewedAt === "string" ? { lastReviewedAt: raw.lastReviewedAt } : {}
|
|
7354
|
+
};
|
|
7355
|
+
}
|
|
7356
|
+
var SLUG_RE2;
|
|
7357
|
+
var init_companyIntent = __esm({
|
|
7358
|
+
"src/companyIntent.ts"() {
|
|
7359
|
+
"use strict";
|
|
7360
|
+
init_state2();
|
|
7361
|
+
init_stateRepo();
|
|
7362
|
+
SLUG_RE2 = /^[a-z][a-z0-9-]{0,63}$/;
|
|
7363
|
+
}
|
|
7364
|
+
});
|
|
7365
|
+
|
|
6990
7366
|
// src/goal/stateStore.ts
|
|
6991
7367
|
function statePath(goalId) {
|
|
6992
7368
|
return `goals/instances/${goalId}/state.json`;
|
|
@@ -7008,6 +7384,133 @@ var init_stateStore = __esm({
|
|
|
7008
7384
|
}
|
|
7009
7385
|
});
|
|
7010
7386
|
|
|
7387
|
+
// src/scripts/applyCompanyManagerDecision.ts
|
|
7388
|
+
function applyAction(config, cwd, action) {
|
|
7389
|
+
if (action.kind === "createManagedGoal") {
|
|
7390
|
+
const existing = fetchGoalState(config, action.id, cwd);
|
|
7391
|
+
if (existing) return applied(action, false, "goal already exists");
|
|
7392
|
+
writeCompanyGoalState(config, cwd, action.id, buildManagedGoalState(action), `chore(goals): create ${action.id} from intent ${action.intentId}`);
|
|
7393
|
+
return applied(action, true, action.reason, action.id);
|
|
7394
|
+
}
|
|
7395
|
+
if (action.kind === "createAgentLoop") {
|
|
7396
|
+
const existing = fetchGoalState(config, action.id, cwd);
|
|
7397
|
+
if (existing) return applied(action, false, "loop already exists");
|
|
7398
|
+
writeCompanyGoalState(config, cwd, action.id, buildAgentLoopState(action), `chore(goals): create loop ${action.id} from intent ${action.intentId}`);
|
|
7399
|
+
return applied(action, true, action.reason, action.id);
|
|
7400
|
+
}
|
|
7401
|
+
if (action.kind === "setGoalLifecycle") {
|
|
7402
|
+
const state = fetchGoalState(config, action.id, cwd);
|
|
7403
|
+
if (!state) return applied(action, false, "goal/loop missing", action.id);
|
|
7404
|
+
const before = state.state;
|
|
7405
|
+
if (before === action.state) return applied(action, false, "state already set", action.id);
|
|
7406
|
+
const next = {
|
|
7407
|
+
...state,
|
|
7408
|
+
state: action.state,
|
|
7409
|
+
updatedAt: nowIso(),
|
|
7410
|
+
extra: {
|
|
7411
|
+
...state.extra,
|
|
7412
|
+
lifecycleChangedByIntent: action.intentId,
|
|
7413
|
+
lifecycleChangeReason: action.reason
|
|
7414
|
+
}
|
|
7415
|
+
};
|
|
7416
|
+
writeCompanyGoalState(config, cwd, action.id, next, `chore(goals): ${action.state} ${action.id} from intent ${action.intentId}`);
|
|
7417
|
+
return applied(action, true, action.reason, action.id);
|
|
7418
|
+
}
|
|
7419
|
+
if (action.kind === "updateIntentPortfolio") {
|
|
7420
|
+
const record2 = readCompanyIntent(config, cwd, action.intentId);
|
|
7421
|
+
if (!record2) return applied(action, false, "intent missing");
|
|
7422
|
+
const intent = {
|
|
7423
|
+
...record2.intent,
|
|
7424
|
+
portfolio: {
|
|
7425
|
+
goals: mergeUnique(record2.intent.portfolio.goals, action.goals ?? []),
|
|
7426
|
+
loops: mergeUnique(record2.intent.portfolio.loops, action.loops ?? []),
|
|
7427
|
+
responsibilities: mergeUnique(record2.intent.portfolio.responsibilities, action.responsibilities ?? [])
|
|
7428
|
+
},
|
|
7429
|
+
updatedAt: nowIso()
|
|
7430
|
+
};
|
|
7431
|
+
writeCompanyIntent(config, cwd, intent, `chore(intents): update ${action.intentId} portfolio`);
|
|
7432
|
+
return applied(action, true, action.reason);
|
|
7433
|
+
}
|
|
7434
|
+
if (action.kind === "note") {
|
|
7435
|
+
return {
|
|
7436
|
+
kind: action.kind,
|
|
7437
|
+
intentId: action.intentId,
|
|
7438
|
+
changed: false,
|
|
7439
|
+
reason: action.message
|
|
7440
|
+
};
|
|
7441
|
+
}
|
|
7442
|
+
return { kind: "unknown", changed: false, reason: "unsupported action" };
|
|
7443
|
+
}
|
|
7444
|
+
function applied(action, changed, reason, resource) {
|
|
7445
|
+
return {
|
|
7446
|
+
kind: action.kind,
|
|
7447
|
+
intentId: "intentId" in action ? action.intentId : void 0,
|
|
7448
|
+
resource,
|
|
7449
|
+
changed,
|
|
7450
|
+
reason
|
|
7451
|
+
};
|
|
7452
|
+
}
|
|
7453
|
+
function mergeUnique(left, right) {
|
|
7454
|
+
return [.../* @__PURE__ */ new Set([...left, ...right])].sort();
|
|
7455
|
+
}
|
|
7456
|
+
function logAppliedCompanyManagerActions(config, cwd, appliedActions) {
|
|
7457
|
+
const at = nowIso();
|
|
7458
|
+
for (const action of appliedActions) {
|
|
7459
|
+
if (!action.intentId) continue;
|
|
7460
|
+
appendCompanyIntentDecision(config, cwd, action.intentId, {
|
|
7461
|
+
at,
|
|
7462
|
+
agent: "cto",
|
|
7463
|
+
intentId: action.intentId,
|
|
7464
|
+
action: action.kind,
|
|
7465
|
+
reason: action.reason,
|
|
7466
|
+
after: { changed: action.changed },
|
|
7467
|
+
resources: action.resource ? [action.resource] : []
|
|
7468
|
+
});
|
|
7469
|
+
}
|
|
7470
|
+
}
|
|
7471
|
+
var applyCompanyManagerDecision;
|
|
7472
|
+
var init_applyCompanyManagerDecision = __esm({
|
|
7473
|
+
"src/scripts/applyCompanyManagerDecision.ts"() {
|
|
7474
|
+
"use strict";
|
|
7475
|
+
init_companyManagerDecision();
|
|
7476
|
+
init_companyIntent();
|
|
7477
|
+
init_stateStore();
|
|
7478
|
+
init_state2();
|
|
7479
|
+
applyCompanyManagerDecision = async (ctx) => {
|
|
7480
|
+
const decision = ctx.data.companyManagerDecision;
|
|
7481
|
+
if (!decision || !Array.isArray(decision.actions)) return;
|
|
7482
|
+
if (ctx.output.exitCode !== 0) return;
|
|
7483
|
+
const applied2 = [];
|
|
7484
|
+
for (const action of decision.actions) {
|
|
7485
|
+
applied2.push(applyAction(ctx.config, ctx.cwd, action));
|
|
7486
|
+
}
|
|
7487
|
+
ctx.data.companyManagerApplied = applied2;
|
|
7488
|
+
ctx.data.companyManagerApplySummary = `company-manager applied ${applied2.filter((item) => item.changed).length}/${applied2.length} action(s)`;
|
|
7489
|
+
};
|
|
7490
|
+
}
|
|
7491
|
+
});
|
|
7492
|
+
|
|
7493
|
+
// src/scripts/appendCompanyIntentDecision.ts
|
|
7494
|
+
var appendCompanyIntentDecision2;
|
|
7495
|
+
var init_appendCompanyIntentDecision = __esm({
|
|
7496
|
+
"src/scripts/appendCompanyIntentDecision.ts"() {
|
|
7497
|
+
"use strict";
|
|
7498
|
+
init_applyCompanyManagerDecision();
|
|
7499
|
+
appendCompanyIntentDecision2 = async (ctx) => {
|
|
7500
|
+
const applied2 = ctx.data.companyManagerApplied;
|
|
7501
|
+
if (!applied2 || applied2.length === 0) return;
|
|
7502
|
+
try {
|
|
7503
|
+
logAppliedCompanyManagerActions(ctx.config, ctx.cwd, applied2);
|
|
7504
|
+
} catch (err) {
|
|
7505
|
+
process.stderr.write(
|
|
7506
|
+
`[company-manager] failed append intent decision log: ${err instanceof Error ? err.message : String(err)}
|
|
7507
|
+
`
|
|
7508
|
+
);
|
|
7509
|
+
}
|
|
7510
|
+
};
|
|
7511
|
+
}
|
|
7512
|
+
});
|
|
7513
|
+
|
|
7011
7514
|
// src/scripts/applyAgentResponsibilityReports.ts
|
|
7012
7515
|
function collectReports(raw, agentResult) {
|
|
7013
7516
|
const out = [];
|
|
@@ -8214,7 +8717,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
8214
8717
|
const content = fs29.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
8215
8718
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
8216
8719
|
if (!slugMatch) continue;
|
|
8217
|
-
const
|
|
8720
|
+
const slug2 = slugMatch[1];
|
|
8218
8721
|
const name = file.replace(/\.(ts|tsx)$/, "");
|
|
8219
8722
|
const fields = [];
|
|
8220
8723
|
const fieldMatches = content.matchAll(/name:\s*['"]([a-zA-Z_][a-zA-Z0-9_]*)['"]/g);
|
|
@@ -8224,7 +8727,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
8224
8727
|
const hasAdmin = /components:\s*\{/.test(content) || /Field:\s*['"]/.test(content) || /Cell:\s*['"]/.test(content) || /views:\s*\{/.test(content);
|
|
8225
8728
|
out.push({
|
|
8226
8729
|
name,
|
|
8227
|
-
slug,
|
|
8730
|
+
slug: slug2,
|
|
8228
8731
|
filePath: path29.relative(cwd, filePath),
|
|
8229
8732
|
fields: fields.slice(0, 20),
|
|
8230
8733
|
hasAdmin
|
|
@@ -8621,425 +9124,34 @@ var init_dispatch = __esm({
|
|
|
8621
9124
|
};
|
|
8622
9125
|
ctx.data.action = action;
|
|
8623
9126
|
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
|
-
}
|
|
9127
|
+
return;
|
|
9128
|
+
}
|
|
9129
|
+
if (state?.flow) {
|
|
9130
|
+
state.flow.step = next;
|
|
9042
9131
|
}
|
|
9132
|
+
const usePr = target === "pr" && state?.core.prUrl;
|
|
9133
|
+
const targetNumber = usePr ? parsePr(state.core.prUrl) ?? issueNumber : issueNumber;
|
|
9134
|
+
ctx.output.nextDispatch = {
|
|
9135
|
+
action: next,
|
|
9136
|
+
cliArgs: usePr ? { pr: targetNumber } : { issue: targetNumber }
|
|
9137
|
+
};
|
|
9138
|
+
};
|
|
9139
|
+
}
|
|
9140
|
+
});
|
|
9141
|
+
|
|
9142
|
+
// src/scripts/dispatchAgentResponsibilityFileTicks.ts
|
|
9143
|
+
var dispatchAgentResponsibilityFileTicks;
|
|
9144
|
+
var init_dispatchAgentResponsibilityFileTicks = __esm({
|
|
9145
|
+
"src/scripts/dispatchAgentResponsibilityFileTicks.ts"() {
|
|
9146
|
+
"use strict";
|
|
9147
|
+
dispatchAgentResponsibilityFileTicks = async (ctx) => {
|
|
9148
|
+
ctx.skipAgent = true;
|
|
9149
|
+
ctx.data.jobTickResults = [];
|
|
9150
|
+
ctx.output.exitCode = 0;
|
|
9151
|
+
ctx.output.reason = "responsibility scheduling is owned by goals and loops";
|
|
9152
|
+
process.stdout.write(
|
|
9153
|
+
"[jobs] no flat agentResponsibility fan-out; goals and loops own scheduled responsibility decisions\n"
|
|
9154
|
+
);
|
|
9043
9155
|
};
|
|
9044
9156
|
}
|
|
9045
9157
|
});
|
|
@@ -9147,6 +9259,30 @@ var init_dispatchClassified = __esm({
|
|
|
9147
9259
|
}
|
|
9148
9260
|
});
|
|
9149
9261
|
|
|
9262
|
+
// src/jobIdentity.ts
|
|
9263
|
+
function stableJobKey(job) {
|
|
9264
|
+
const agentResponsibility = job.agentResponsibility ?? job.action;
|
|
9265
|
+
const agentAction = job.agentAction ?? agentResponsibility ?? "unknown";
|
|
9266
|
+
if (job.flavor === "scheduled" && job.agentResponsibility)
|
|
9267
|
+
return `scheduled:${job.agentResponsibility}:${agentAction}`;
|
|
9268
|
+
const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
|
|
9269
|
+
const work = agentResponsibility && agentAction && agentAction !== agentResponsibility ? `${agentResponsibility}:${agentAction}` : agentResponsibility ?? agentAction;
|
|
9270
|
+
return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
|
|
9271
|
+
}
|
|
9272
|
+
function targetFromCliArgs(cliArgs) {
|
|
9273
|
+
if (!cliArgs) return void 0;
|
|
9274
|
+
for (const key of ["issue", "pr", "target", "issue_number"]) {
|
|
9275
|
+
const value = cliArgs[key];
|
|
9276
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
9277
|
+
}
|
|
9278
|
+
return void 0;
|
|
9279
|
+
}
|
|
9280
|
+
var init_jobIdentity = __esm({
|
|
9281
|
+
"src/jobIdentity.ts"() {
|
|
9282
|
+
"use strict";
|
|
9283
|
+
}
|
|
9284
|
+
});
|
|
9285
|
+
|
|
9150
9286
|
// src/scripts/dispatchNextTaskJob.ts
|
|
9151
9287
|
function taskJobToJob(job, issueArg) {
|
|
9152
9288
|
const target = typeof job.target === "number" ? job.target : typeof issueArg === "number" ? issueArg : void 0;
|
|
@@ -9669,8 +9805,8 @@ function git3(args, cwd) {
|
|
|
9669
9805
|
}).trim();
|
|
9670
9806
|
}
|
|
9671
9807
|
function deriveBranchName(issueNumber, title) {
|
|
9672
|
-
const
|
|
9673
|
-
return
|
|
9808
|
+
const slug2 = title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 50).replace(/-$/, "");
|
|
9809
|
+
return slug2 ? `${issueNumber}-${slug2}` : `${issueNumber}-task`;
|
|
9674
9810
|
}
|
|
9675
9811
|
function getCurrentBranch(cwd) {
|
|
9676
9812
|
return git3(["branch", "--show-current"], cwd);
|
|
@@ -10076,11 +10212,11 @@ var init_fixFlow = __esm({
|
|
|
10076
10212
|
// src/scripts/initFlow.ts
|
|
10077
10213
|
import { execFileSync as execFileSync15 } from "child_process";
|
|
10078
10214
|
import * as fs31 from "fs";
|
|
10079
|
-
import * as
|
|
10215
|
+
import * as path31 from "path";
|
|
10080
10216
|
function detectPackageManager(cwd) {
|
|
10081
|
-
if (fs31.existsSync(
|
|
10082
|
-
if (fs31.existsSync(
|
|
10083
|
-
if (fs31.existsSync(
|
|
10217
|
+
if (fs31.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
10218
|
+
if (fs31.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
|
|
10219
|
+
if (fs31.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
|
|
10084
10220
|
return "npm";
|
|
10085
10221
|
}
|
|
10086
10222
|
function qualityCommandsFor(pm) {
|
|
@@ -10152,7 +10288,7 @@ function performInit(cwd, force) {
|
|
|
10152
10288
|
const pm = detectPackageManager(cwd);
|
|
10153
10289
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
10154
10290
|
const defaultBranch2 = defaultBranchFromGit(cwd);
|
|
10155
|
-
const configPath =
|
|
10291
|
+
const configPath = path31.join(cwd, "kody.config.json");
|
|
10156
10292
|
if (fs31.existsSync(configPath) && !force) {
|
|
10157
10293
|
skipped.push("kody.config.json");
|
|
10158
10294
|
} else {
|
|
@@ -10161,8 +10297,8 @@ function performInit(cwd, force) {
|
|
|
10161
10297
|
`);
|
|
10162
10298
|
wrote.push("kody.config.json");
|
|
10163
10299
|
}
|
|
10164
|
-
const workflowDir =
|
|
10165
|
-
const workflowPath =
|
|
10300
|
+
const workflowDir = path31.join(cwd, ".github", "workflows");
|
|
10301
|
+
const workflowPath = path31.join(workflowDir, "kody.yml");
|
|
10166
10302
|
if (fs31.existsSync(workflowPath) && !force) {
|
|
10167
10303
|
skipped.push(".github/workflows/kody.yml");
|
|
10168
10304
|
} else {
|
|
@@ -10170,8 +10306,8 @@ function performInit(cwd, force) {
|
|
|
10170
10306
|
fs31.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
10171
10307
|
wrote.push(".github/workflows/kody.yml");
|
|
10172
10308
|
}
|
|
10173
|
-
const agentsDir =
|
|
10174
|
-
const agentPath =
|
|
10309
|
+
const agentsDir = path31.join(cwd, ".kody", "agents");
|
|
10310
|
+
const agentPath = path31.join(agentsDir, "kody.md");
|
|
10175
10311
|
if (fs31.existsSync(agentPath) && !force) {
|
|
10176
10312
|
skipped.push(".kody/agents/kody.md");
|
|
10177
10313
|
} else {
|
|
@@ -10187,7 +10323,7 @@ function performInit(cwd, force) {
|
|
|
10187
10323
|
continue;
|
|
10188
10324
|
}
|
|
10189
10325
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
10190
|
-
const target =
|
|
10326
|
+
const target = path31.join(workflowDir, `kody-${exe.name}.yml`);
|
|
10191
10327
|
if (fs31.existsSync(target) && !force) {
|
|
10192
10328
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
10193
10329
|
continue;
|
|
@@ -10385,7 +10521,7 @@ function stripDirective(body) {
|
|
|
10385
10521
|
}
|
|
10386
10522
|
return lines.slice(start).join("\n").trim();
|
|
10387
10523
|
}
|
|
10388
|
-
function parseAgentFile(raw,
|
|
10524
|
+
function parseAgentFile(raw, slug2) {
|
|
10389
10525
|
const stripped = stripLeadingFrontmatter(raw);
|
|
10390
10526
|
const trimmed = stripped.trim();
|
|
10391
10527
|
const firstLine2 = trimmed.split("\n", 1)[0] ?? "";
|
|
@@ -10394,14 +10530,14 @@ function parseAgentFile(raw, slug) {
|
|
|
10394
10530
|
const rest = trimmed.slice(firstLine2.length).replace(/^\n+/, "");
|
|
10395
10531
|
return { title: h1[1].trim(), body: rest };
|
|
10396
10532
|
}
|
|
10397
|
-
return { title: humanizeSlug2(
|
|
10533
|
+
return { title: humanizeSlug2(slug2), body: trimmed };
|
|
10398
10534
|
}
|
|
10399
10535
|
function stripLeadingFrontmatter(raw) {
|
|
10400
10536
|
const match = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/.exec(raw);
|
|
10401
10537
|
return match ? raw.slice(match[0].length) : raw;
|
|
10402
10538
|
}
|
|
10403
|
-
function humanizeSlug2(
|
|
10404
|
-
return
|
|
10539
|
+
function humanizeSlug2(slug2) {
|
|
10540
|
+
return slug2.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
|
|
10405
10541
|
}
|
|
10406
10542
|
var loadAgentAdhoc;
|
|
10407
10543
|
var init_loadAgentAdhoc = __esm({
|
|
@@ -10444,19 +10580,19 @@ var init_loadAgentResponsibilityState = __esm({
|
|
|
10444
10580
|
AGENT_RESPONSIBILITY_TOOL_PALETTE = new Set(AGENT_RESPONSIBILITY_MCP_TOOL_NAMES);
|
|
10445
10581
|
loadAgentResponsibilityState = async (ctx, profile, args) => {
|
|
10446
10582
|
const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
|
|
10447
|
-
const
|
|
10583
|
+
const slug2 = profile.name;
|
|
10448
10584
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
10449
10585
|
if (backend.hydrate) await backend.hydrate();
|
|
10450
|
-
const loaded = await backend.load(
|
|
10451
|
-
ctx.data.jobSlug =
|
|
10586
|
+
const loaded = await backend.load(slug2);
|
|
10587
|
+
ctx.data.jobSlug = slug2;
|
|
10452
10588
|
ctx.data.jobState = loaded;
|
|
10453
10589
|
ctx.data.jobStateJson = JSON.stringify(loaded.state, null, 2);
|
|
10454
|
-
ctx.data.agentResponsibilitySlug =
|
|
10590
|
+
ctx.data.agentResponsibilitySlug = slug2;
|
|
10455
10591
|
ctx.data.agentResponsibilityTitle = profile.describe;
|
|
10456
10592
|
ctx.data.agentActionSlug = profile.agentAction ?? profile.name;
|
|
10457
10593
|
ctx.data.agentSlug = profile.agent ?? "";
|
|
10458
10594
|
ctx.data.agentTitle = "";
|
|
10459
|
-
ctx.data.agentResponsibilitySchedule =
|
|
10595
|
+
ctx.data.agentResponsibilitySchedule = String(ctx.data.jobSchedule ?? "");
|
|
10460
10596
|
const mentions = (profile.mentions ?? []).map((l) => `@${l}`).join(" ");
|
|
10461
10597
|
ctx.data.mentions = mentions;
|
|
10462
10598
|
const declaredTools = profile.agentResponsibilityTools ?? [];
|
|
@@ -10464,7 +10600,7 @@ var init_loadAgentResponsibilityState = __esm({
|
|
|
10464
10600
|
const unknown = declaredTools.filter((name) => !AGENT_RESPONSIBILITY_TOOL_PALETTE.has(name));
|
|
10465
10601
|
if (unknown.length > 0) {
|
|
10466
10602
|
throw new Error(
|
|
10467
|
-
`loadAgentResponsibilityState: agentResponsibility '${
|
|
10603
|
+
`loadAgentResponsibilityState: agentResponsibility '${slug2}' declared agentResponsibilityTools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
|
|
10468
10604
|
);
|
|
10469
10605
|
}
|
|
10470
10606
|
ctx.data.agentResponsibilityTools = declaredTools;
|
|
@@ -10478,6 +10614,43 @@ var init_loadAgentResponsibilityState = __esm({
|
|
|
10478
10614
|
}
|
|
10479
10615
|
});
|
|
10480
10616
|
|
|
10617
|
+
// src/scripts/loadCompanyIntents.ts
|
|
10618
|
+
var loadCompanyIntents;
|
|
10619
|
+
var init_loadCompanyIntents = __esm({
|
|
10620
|
+
"src/scripts/loadCompanyIntents.ts"() {
|
|
10621
|
+
"use strict";
|
|
10622
|
+
init_companyIntent();
|
|
10623
|
+
loadCompanyIntents = async (ctx) => {
|
|
10624
|
+
const intents = listCompanyIntents(ctx.config, ctx.cwd);
|
|
10625
|
+
const active = intents.filter((record2) => record2.intent.status === "active");
|
|
10626
|
+
ctx.data.companyIntents = intents;
|
|
10627
|
+
ctx.data.companyActiveIntents = active;
|
|
10628
|
+
ctx.data.companyIntentsJson = JSON.stringify(
|
|
10629
|
+
active.map((record2) => record2.intent),
|
|
10630
|
+
null,
|
|
10631
|
+
2
|
|
10632
|
+
);
|
|
10633
|
+
if (active.length === 0) {
|
|
10634
|
+
ctx.output.reason = "no active company intents";
|
|
10635
|
+
}
|
|
10636
|
+
};
|
|
10637
|
+
}
|
|
10638
|
+
});
|
|
10639
|
+
|
|
10640
|
+
// src/scripts/loadCompanyPortfolio.ts
|
|
10641
|
+
var loadCompanyPortfolio;
|
|
10642
|
+
var init_loadCompanyPortfolio = __esm({
|
|
10643
|
+
"src/scripts/loadCompanyPortfolio.ts"() {
|
|
10644
|
+
"use strict";
|
|
10645
|
+
init_companyIntent();
|
|
10646
|
+
loadCompanyPortfolio = async (ctx) => {
|
|
10647
|
+
const portfolio = listCompanyPortfolio(ctx.config, ctx.cwd);
|
|
10648
|
+
ctx.data.companyPortfolio = portfolio;
|
|
10649
|
+
ctx.data.companyPortfolioJson = JSON.stringify(portfolio, null, 2);
|
|
10650
|
+
};
|
|
10651
|
+
}
|
|
10652
|
+
});
|
|
10653
|
+
|
|
10481
10654
|
// src/scripts/loadGoalState.ts
|
|
10482
10655
|
function retryDelaysMs() {
|
|
10483
10656
|
const raw = process.env.KODY_GOAL_STATE_RETRY_DELAYS_MS?.trim();
|
|
@@ -10620,8 +10793,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
10620
10793
|
|
|
10621
10794
|
// src/scripts/loadJobFromFile.ts
|
|
10622
10795
|
import * as fs33 from "fs";
|
|
10623
|
-
import * as
|
|
10624
|
-
function parseJobFile(raw,
|
|
10796
|
+
import * as path32 from "path";
|
|
10797
|
+
function parseJobFile(raw, slug2) {
|
|
10625
10798
|
let stripped = raw;
|
|
10626
10799
|
if (stripped.startsWith("---\n")) {
|
|
10627
10800
|
const end = stripped.indexOf("\n---\n", 4);
|
|
@@ -10636,10 +10809,10 @@ function parseJobFile(raw, slug) {
|
|
|
10636
10809
|
const rest = trimmed.slice(firstLine2.length).replace(/^\n+/, "");
|
|
10637
10810
|
return { title: h1[1].trim(), body: rest };
|
|
10638
10811
|
}
|
|
10639
|
-
return { title: humanizeSlug3(
|
|
10812
|
+
return { title: humanizeSlug3(slug2), body: trimmed };
|
|
10640
10813
|
}
|
|
10641
|
-
function humanizeSlug3(
|
|
10642
|
-
return
|
|
10814
|
+
function humanizeSlug3(slug2) {
|
|
10815
|
+
return slug2.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
|
|
10643
10816
|
}
|
|
10644
10817
|
var AGENT_RESPONSIBILITY_TOOL_PALETTE2, loadJobFromFile;
|
|
10645
10818
|
var init_loadJobFromFile = __esm({
|
|
@@ -10654,14 +10827,14 @@ var init_loadJobFromFile = __esm({
|
|
|
10654
10827
|
const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
|
|
10655
10828
|
const agentsDir = String(args?.agentsDir ?? ".kody/agents");
|
|
10656
10829
|
const slugArg = String(args?.slugArg ?? "job");
|
|
10657
|
-
const
|
|
10658
|
-
if (!
|
|
10830
|
+
const slug2 = String(ctx.args[slugArg] ?? "").trim();
|
|
10831
|
+
if (!slug2) {
|
|
10659
10832
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
10660
10833
|
}
|
|
10661
|
-
const agentResponsibility = resolveAgentResponsibilityFolder(
|
|
10834
|
+
const agentResponsibility = resolveAgentResponsibilityFolder(slug2, path32.join(ctx.cwd, jobsDir));
|
|
10662
10835
|
if (!agentResponsibility) {
|
|
10663
10836
|
throw new Error(
|
|
10664
|
-
`loadJobFromFile: agentResponsibility folder not found or incomplete: ${
|
|
10837
|
+
`loadJobFromFile: agentResponsibility folder not found or incomplete: ${path32.join(ctx.cwd, jobsDir, slug2)}`
|
|
10665
10838
|
);
|
|
10666
10839
|
}
|
|
10667
10840
|
const { title, body, config } = agentResponsibility;
|
|
@@ -10673,7 +10846,7 @@ var init_loadJobFromFile = __esm({
|
|
|
10673
10846
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
10674
10847
|
if (!fs33.existsSync(agentPath)) {
|
|
10675
10848
|
throw new Error(
|
|
10676
|
-
`loadJobFromFile: agentResponsibility '${
|
|
10849
|
+
`loadJobFromFile: agentResponsibility '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
10677
10850
|
);
|
|
10678
10851
|
}
|
|
10679
10852
|
const agentRaw = fs33.readFileSync(agentPath, "utf-8");
|
|
@@ -10682,28 +10855,28 @@ var init_loadJobFromFile = __esm({
|
|
|
10682
10855
|
agentIdentity = parsed.body;
|
|
10683
10856
|
}
|
|
10684
10857
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
10685
|
-
const loaded = await backend.load(
|
|
10686
|
-
ctx.data.jobSlug =
|
|
10858
|
+
const loaded = await backend.load(slug2);
|
|
10859
|
+
ctx.data.jobSlug = slug2;
|
|
10687
10860
|
ctx.data.jobTitle = title;
|
|
10688
|
-
ctx.data.jobIntent = body.replace(/\{\{\s*mentions\s*\}\}/g, mentions).replace(/\{\{\s*agentResponsibility\s*\}\}/g,
|
|
10861
|
+
ctx.data.jobIntent = body.replace(/\{\{\s*mentions\s*\}\}/g, mentions).replace(/\{\{\s*agentResponsibility\s*\}\}/g, slug2);
|
|
10689
10862
|
ctx.data.jobState = loaded;
|
|
10690
10863
|
ctx.data.jobStateJson = JSON.stringify(loaded.state, null, 2);
|
|
10691
10864
|
ctx.data.agentSlug = agentSlug;
|
|
10692
10865
|
ctx.data.agentTitle = agentTitle;
|
|
10693
10866
|
ctx.data.agentIdentity = agentIdentity;
|
|
10694
10867
|
ctx.data.mentions = mentions;
|
|
10695
|
-
ctx.data.agentResponsibilitySlug =
|
|
10868
|
+
ctx.data.agentResponsibilitySlug = slug2;
|
|
10696
10869
|
ctx.data.agentResponsibilityTitle = title;
|
|
10697
10870
|
ctx.data.agentSlug = agentSlug;
|
|
10698
10871
|
ctx.data.agentTitle = agentTitle;
|
|
10699
10872
|
ctx.data.agentActionSlug = profile.name;
|
|
10700
|
-
ctx.data.agentResponsibilitySchedule =
|
|
10873
|
+
ctx.data.agentResponsibilitySchedule = String(ctx.data.jobSchedule ?? "");
|
|
10701
10874
|
const declaredTools = config.tools ?? [];
|
|
10702
10875
|
if (declaredTools.length > 0) {
|
|
10703
10876
|
const unknown = declaredTools.filter((name) => !AGENT_RESPONSIBILITY_TOOL_PALETTE2.has(name));
|
|
10704
10877
|
if (unknown.length > 0) {
|
|
10705
10878
|
throw new Error(
|
|
10706
|
-
`loadJobFromFile: agentResponsibility '${
|
|
10879
|
+
`loadJobFromFile: agentResponsibility '${slug2}' declared tools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
|
|
10707
10880
|
);
|
|
10708
10881
|
}
|
|
10709
10882
|
const mcpToolNames = declaredTools.map((name) => `mcp__kody-agent-responsibility__${name}`);
|
|
@@ -10751,9 +10924,9 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
10751
10924
|
|
|
10752
10925
|
// src/scripts/kodyVariables.ts
|
|
10753
10926
|
import * as fs34 from "fs";
|
|
10754
|
-
import * as
|
|
10927
|
+
import * as path33 from "path";
|
|
10755
10928
|
function readKodyVariables(cwd) {
|
|
10756
|
-
const full =
|
|
10929
|
+
const full = path33.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
10757
10930
|
let raw;
|
|
10758
10931
|
try {
|
|
10759
10932
|
raw = fs34.readFileSync(full, "utf-8");
|
|
@@ -10782,7 +10955,7 @@ var init_kodyVariables = __esm({
|
|
|
10782
10955
|
|
|
10783
10956
|
// src/scripts/loadQaContext.ts
|
|
10784
10957
|
import * as fs35 from "fs";
|
|
10785
|
-
import * as
|
|
10958
|
+
import * as path34 from "path";
|
|
10786
10959
|
function parseSlugList(value) {
|
|
10787
10960
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
10788
10961
|
return inner.split(",").map(
|
|
@@ -10811,7 +10984,7 @@ function readProfileAgents(raw) {
|
|
|
10811
10984
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
10812
10985
|
}
|
|
10813
10986
|
function readProfile(cwd) {
|
|
10814
|
-
const dir =
|
|
10987
|
+
const dir = path34.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
10815
10988
|
if (!fs35.existsSync(dir)) return "";
|
|
10816
10989
|
let entries;
|
|
10817
10990
|
try {
|
|
@@ -10822,7 +10995,7 @@ function readProfile(cwd) {
|
|
|
10822
10995
|
const blocks = [];
|
|
10823
10996
|
for (const file of entries) {
|
|
10824
10997
|
try {
|
|
10825
|
-
const raw = fs35.readFileSync(
|
|
10998
|
+
const raw = fs35.readFileSync(path34.join(dir, file), "utf-8");
|
|
10826
10999
|
const { agent, body } = readProfileAgents(raw);
|
|
10827
11000
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
10828
11001
|
blocks.push(`## ${file}
|
|
@@ -10869,7 +11042,7 @@ var init_loadQaContext = __esm({
|
|
|
10869
11042
|
|
|
10870
11043
|
// src/taskContext.ts
|
|
10871
11044
|
import * as fs36 from "fs";
|
|
10872
|
-
import * as
|
|
11045
|
+
import * as path35 from "path";
|
|
10873
11046
|
function buildTaskContext(args) {
|
|
10874
11047
|
return {
|
|
10875
11048
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -10886,7 +11059,7 @@ function persistTaskContext(cwd, ctx) {
|
|
|
10886
11059
|
try {
|
|
10887
11060
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
10888
11061
|
fs36.mkdirSync(dir, { recursive: true });
|
|
10889
|
-
const file =
|
|
11062
|
+
const file = path35.join(dir, "task-context.json");
|
|
10890
11063
|
fs36.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
10891
11064
|
`);
|
|
10892
11065
|
return file;
|
|
@@ -11303,8 +11476,8 @@ function parseAgentFactoryBundle(raw) {
|
|
|
11303
11476
|
return { title, summary, files };
|
|
11304
11477
|
}
|
|
11305
11478
|
function buildAgentFactoryBranchName(issueNumber, title, now = Date.now()) {
|
|
11306
|
-
const
|
|
11307
|
-
const suffix =
|
|
11479
|
+
const slug2 = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48).replace(/-+$/g, "");
|
|
11480
|
+
const suffix = slug2 ? `-${slug2}` : "";
|
|
11308
11481
|
return `agent-factory/issue-${issueNumber}-${now.toString(36)}${suffix}`;
|
|
11309
11482
|
}
|
|
11310
11483
|
function normalizeBundleFiles(ctx, bundle) {
|
|
@@ -11537,21 +11710,21 @@ var init_openQaIssue = __esm({
|
|
|
11537
11710
|
ctx.data.action = failedAction3(reason);
|
|
11538
11711
|
return;
|
|
11539
11712
|
}
|
|
11540
|
-
const
|
|
11541
|
-
if (!
|
|
11713
|
+
const reportBody2 = agentResult.finalText.trim();
|
|
11714
|
+
if (!reportBody2) {
|
|
11542
11715
|
process.stderr.write("qa-engineer: agent produced no report body\n");
|
|
11543
11716
|
ctx.output.exitCode = 1;
|
|
11544
11717
|
ctx.output.reason = "empty report body";
|
|
11545
11718
|
ctx.data.action = failedAction3("empty report body");
|
|
11546
11719
|
return;
|
|
11547
11720
|
}
|
|
11548
|
-
const verdict = detectVerdict(
|
|
11721
|
+
const verdict = detectVerdict(reportBody2);
|
|
11549
11722
|
ctx.data.qaVerdict = verdict;
|
|
11550
|
-
ctx.data.qaReport =
|
|
11723
|
+
ctx.data.qaReport = reportBody2;
|
|
11551
11724
|
const existingIssue = ctx.args.issue;
|
|
11552
11725
|
if (typeof existingIssue === "number" && Number.isFinite(existingIssue) && existingIssue > 0) {
|
|
11553
11726
|
try {
|
|
11554
|
-
postIssueComment(existingIssue,
|
|
11727
|
+
postIssueComment(existingIssue, reportBody2, ctx.cwd);
|
|
11555
11728
|
} catch (err) {
|
|
11556
11729
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11557
11730
|
ctx.output.exitCode = 4;
|
|
@@ -11573,7 +11746,7 @@ QA_REPORT_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.gith
|
|
|
11573
11746
|
const hasLabel = ensureLabel2(ctx.cwd);
|
|
11574
11747
|
let created;
|
|
11575
11748
|
try {
|
|
11576
|
-
created = createQaIssue(title,
|
|
11749
|
+
created = createQaIssue(title, reportBody2, hasLabel, ctx.cwd);
|
|
11577
11750
|
} catch (err) {
|
|
11578
11751
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11579
11752
|
ctx.output.exitCode = 4;
|
|
@@ -11636,6 +11809,39 @@ var init_parseAgentResult = __esm({
|
|
|
11636
11809
|
}
|
|
11637
11810
|
});
|
|
11638
11811
|
|
|
11812
|
+
// src/scripts/parseCompanyManagerDecision.ts
|
|
11813
|
+
function makeAction3(type, payload) {
|
|
11814
|
+
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11815
|
+
}
|
|
11816
|
+
var parseCompanyManagerDecision;
|
|
11817
|
+
var init_parseCompanyManagerDecision = __esm({
|
|
11818
|
+
"src/scripts/parseCompanyManagerDecision.ts"() {
|
|
11819
|
+
"use strict";
|
|
11820
|
+
init_companyManagerDecision();
|
|
11821
|
+
parseCompanyManagerDecision = async (ctx, _profile, agentResult) => {
|
|
11822
|
+
if (!agentResult) {
|
|
11823
|
+
ctx.data.companyManagerDecision = { summary: "", actions: [] };
|
|
11824
|
+
ctx.data.action = makeAction3("COMPANY_MANAGER_NOT_RUN", { reason: "no agent result" });
|
|
11825
|
+
return;
|
|
11826
|
+
}
|
|
11827
|
+
try {
|
|
11828
|
+
const decision = parseCompanyManagerDecisionText(agentResult.finalText);
|
|
11829
|
+
ctx.data.companyManagerDecision = decision;
|
|
11830
|
+
ctx.data.action = makeAction3("COMPANY_MANAGER_DECIDED", {
|
|
11831
|
+
summary: decision.summary,
|
|
11832
|
+
actionCount: decision.actions.length
|
|
11833
|
+
});
|
|
11834
|
+
} catch (err) {
|
|
11835
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11836
|
+
ctx.data.companyManagerDecisionError = reason;
|
|
11837
|
+
ctx.data.action = makeAction3("COMPANY_MANAGER_FAILED", { reason });
|
|
11838
|
+
ctx.output.exitCode = 1;
|
|
11839
|
+
ctx.output.reason = reason;
|
|
11840
|
+
}
|
|
11841
|
+
};
|
|
11842
|
+
}
|
|
11843
|
+
});
|
|
11844
|
+
|
|
11639
11845
|
// src/scripts/stateEnvelope.ts
|
|
11640
11846
|
function isPartialEnvelope(x) {
|
|
11641
11847
|
if (x === null || typeof x !== "object") return false;
|
|
@@ -11896,6 +12102,119 @@ var init_persistFlowState = __esm({
|
|
|
11896
12102
|
}
|
|
11897
12103
|
});
|
|
11898
12104
|
|
|
12105
|
+
// src/scripts/planTaskJobs.ts
|
|
12106
|
+
function parseTaskJobSpecs(body) {
|
|
12107
|
+
const match = body.match(new RegExp(`<!--\\s*${TASK_JOBS_MARKER}\\s*([\\s\\S]*?)-->`));
|
|
12108
|
+
if (!match) return [];
|
|
12109
|
+
let parsed;
|
|
12110
|
+
try {
|
|
12111
|
+
parsed = JSON.parse(match[1].trim());
|
|
12112
|
+
} catch (err) {
|
|
12113
|
+
throw new Error(`task job plan is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
12114
|
+
}
|
|
12115
|
+
if (!Array.isArray(parsed)) throw new Error("task job plan must be a JSON array");
|
|
12116
|
+
return parsed.map((entry, index) => normalizeSpec(entry, index));
|
|
12117
|
+
}
|
|
12118
|
+
function taskJobSpecToJob(spec, issueNumber) {
|
|
12119
|
+
const cliArgs = spec.cliArgs ?? { issue: issueNumber };
|
|
12120
|
+
const target = typeof spec.target === "number" ? spec.target : targetFromCliArgs(cliArgs) ?? issueNumber;
|
|
12121
|
+
return {
|
|
12122
|
+
agentResponsibility: spec.agentResponsibility ?? spec.agentAction,
|
|
12123
|
+
agentAction: spec.agentAction,
|
|
12124
|
+
why: spec.reason,
|
|
12125
|
+
agent: spec.agent,
|
|
12126
|
+
schedule: spec.schedule,
|
|
12127
|
+
target,
|
|
12128
|
+
cliArgs,
|
|
12129
|
+
flavor: spec.flavor ?? "instant"
|
|
12130
|
+
};
|
|
12131
|
+
}
|
|
12132
|
+
function normalizeSpec(input, index) {
|
|
12133
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
12134
|
+
throw new Error(`task job plan entry ${index} must be an object`);
|
|
12135
|
+
}
|
|
12136
|
+
const raw = input;
|
|
12137
|
+
const agentAction = typeof raw.agentAction === "string" ? raw.agentAction.trim() : "";
|
|
12138
|
+
if (!/^[a-z][a-z0-9-]*$/.test(agentAction)) {
|
|
12139
|
+
throw new Error(`task job plan entry ${index} must have a valid agentAction`);
|
|
12140
|
+
}
|
|
12141
|
+
const cliArgs = raw.cliArgs;
|
|
12142
|
+
if (cliArgs !== void 0 && (!cliArgs || typeof cliArgs !== "object" || Array.isArray(cliArgs))) {
|
|
12143
|
+
throw new Error(`task job plan entry ${index} cliArgs must be an object`);
|
|
12144
|
+
}
|
|
12145
|
+
const flavor = raw.flavor;
|
|
12146
|
+
if (flavor !== void 0 && flavor !== "instant" && flavor !== "scheduled") {
|
|
12147
|
+
throw new Error(`task job plan entry ${index} flavor must be "instant" or "scheduled"`);
|
|
12148
|
+
}
|
|
12149
|
+
return {
|
|
12150
|
+
agentAction,
|
|
12151
|
+
...typeof raw.agentResponsibility === "string" && raw.agentResponsibility.trim() ? { agentResponsibility: raw.agentResponsibility.trim() } : {},
|
|
12152
|
+
...typeof raw.reason === "string" && raw.reason.trim() ? { reason: raw.reason.trim() } : {},
|
|
12153
|
+
...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
|
|
12154
|
+
...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
|
|
12155
|
+
...cliArgs ? { cliArgs } : {},
|
|
12156
|
+
...typeof raw.target === "number" && Number.isFinite(raw.target) ? { target: raw.target } : {},
|
|
12157
|
+
...flavor === "instant" || flavor === "scheduled" ? { flavor } : {},
|
|
12158
|
+
...typeof raw.schedule === "string" && raw.schedule.trim() ? { schedule: raw.schedule.trim() } : {}
|
|
12159
|
+
};
|
|
12160
|
+
}
|
|
12161
|
+
function jobToPlannedTaskJob(job) {
|
|
12162
|
+
return {
|
|
12163
|
+
id: stableJobKey(job),
|
|
12164
|
+
agentAction: job.agentAction ?? job.agentResponsibility ?? "unknown",
|
|
12165
|
+
agentResponsibility: job.agentResponsibility ?? job.action ?? job.agentAction ?? "unknown",
|
|
12166
|
+
...job.agent ? { agent: job.agent } : {},
|
|
12167
|
+
...job.flavor ? { flavor: job.flavor } : {},
|
|
12168
|
+
...job.schedule ? { schedule: job.schedule } : {},
|
|
12169
|
+
...typeof job.target === "number" ? { target: job.target } : {},
|
|
12170
|
+
...job.why ? { reason: job.why } : {}
|
|
12171
|
+
};
|
|
12172
|
+
}
|
|
12173
|
+
function assertUniqueJobIds(planned) {
|
|
12174
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12175
|
+
for (const job of planned) {
|
|
12176
|
+
if (seen.has(job.id)) throw new Error(`duplicate planned task job id: ${job.id}`);
|
|
12177
|
+
seen.add(job.id);
|
|
12178
|
+
}
|
|
12179
|
+
}
|
|
12180
|
+
var TASK_JOBS_MARKER, planTaskJobs;
|
|
12181
|
+
var init_planTaskJobs = __esm({
|
|
12182
|
+
"src/scripts/planTaskJobs.ts"() {
|
|
12183
|
+
"use strict";
|
|
12184
|
+
init_jobIdentity();
|
|
12185
|
+
init_state();
|
|
12186
|
+
TASK_JOBS_MARKER = "kody:task-jobs:v1";
|
|
12187
|
+
planTaskJobs = async (ctx) => {
|
|
12188
|
+
const issueNumber = ctx.args.issue;
|
|
12189
|
+
if (!issueNumber) {
|
|
12190
|
+
ctx.skipAgent = true;
|
|
12191
|
+
ctx.output.exitCode = 64;
|
|
12192
|
+
ctx.output.reason = "planTaskJobs requires --issue";
|
|
12193
|
+
return;
|
|
12194
|
+
}
|
|
12195
|
+
const issue = ctx.data.issue;
|
|
12196
|
+
const specs = parseTaskJobSpecs(issue?.body ?? "");
|
|
12197
|
+
if (specs.length === 0) {
|
|
12198
|
+
ctx.skipAgent = true;
|
|
12199
|
+
ctx.output.exitCode = 64;
|
|
12200
|
+
ctx.output.reason = `no ${TASK_JOBS_MARKER} block found on issue #${issueNumber}`;
|
|
12201
|
+
return;
|
|
12202
|
+
}
|
|
12203
|
+
const jobs = specs.map((spec) => taskJobSpecToJob(spec, issueNumber));
|
|
12204
|
+
const planned = jobs.map(jobToPlannedTaskJob);
|
|
12205
|
+
assertUniqueJobIds(planned);
|
|
12206
|
+
const prior = ctx.data.taskState ?? emptyState();
|
|
12207
|
+
const next = upsertTaskJobs(prior, planned, (/* @__PURE__ */ new Date()).toISOString());
|
|
12208
|
+
ctx.data.taskState = next;
|
|
12209
|
+
ctx.data.plannedTaskJobs = jobs;
|
|
12210
|
+
ctx.data.plannedTaskJobIds = planned.map((job) => job.id);
|
|
12211
|
+
const target = ctx.data.commentTargetType;
|
|
12212
|
+
const number = ctx.data.commentTargetNumber;
|
|
12213
|
+
if (target && number) writeTaskState(target, number, next, ctx.cwd, ctx.config);
|
|
12214
|
+
};
|
|
12215
|
+
}
|
|
12216
|
+
});
|
|
12217
|
+
|
|
11899
12218
|
// src/scripts/postAgentSummaryComment.ts
|
|
11900
12219
|
function postAgentSummaryComment(ctx, opts = {}) {
|
|
11901
12220
|
if (!ctx.data.agentDone) return;
|
|
@@ -12195,7 +12514,7 @@ function tryAuditComment(issueNumber, body, cwd) {
|
|
|
12195
12514
|
} catch {
|
|
12196
12515
|
}
|
|
12197
12516
|
}
|
|
12198
|
-
function
|
|
12517
|
+
function makeAction4(type, payload) {
|
|
12199
12518
|
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
12200
12519
|
}
|
|
12201
12520
|
function failedAction4(reason) {
|
|
@@ -12232,7 +12551,7 @@ var init_recordClassification = __esm({
|
|
|
12232
12551
|
ctx.output.reason = "classify: no decision";
|
|
12233
12552
|
return;
|
|
12234
12553
|
}
|
|
12235
|
-
ctx.data.action =
|
|
12554
|
+
ctx.data.action = makeAction4(`CLASSIFIED_AS_${classification.toUpperCase()}`, {
|
|
12236
12555
|
classification,
|
|
12237
12556
|
reason: reason ?? "",
|
|
12238
12557
|
source: ctx.data.classificationSource ?? "agent"
|
|
@@ -13075,12 +13394,12 @@ fi
|
|
|
13075
13394
|
|
|
13076
13395
|
// src/scripts/runPreviewBuild.ts
|
|
13077
13396
|
import { copyFile, writeFile } from "fs/promises";
|
|
13078
|
-
import * as
|
|
13397
|
+
import * as path36 from "path";
|
|
13079
13398
|
import { fileURLToPath } from "url";
|
|
13080
13399
|
function bundledDockerfilePath(mode) {
|
|
13081
|
-
const here =
|
|
13400
|
+
const here = path36.dirname(fileURLToPath(import.meta.url));
|
|
13082
13401
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
13083
|
-
return
|
|
13402
|
+
return path36.join(here, "preview-build-templates", file);
|
|
13084
13403
|
}
|
|
13085
13404
|
function required(name) {
|
|
13086
13405
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -13339,10 +13658,10 @@ var init_runPreviewBuild = __esm({
|
|
|
13339
13658
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
13340
13659
|
if (Object.keys(buildEnv).length > 0) {
|
|
13341
13660
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
13342
|
-
await writeFile(
|
|
13661
|
+
await writeFile(path36.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
13343
13662
|
`, "utf8");
|
|
13344
13663
|
}
|
|
13345
|
-
const consumerDockerfile =
|
|
13664
|
+
const consumerDockerfile = path36.join(ctx.cwd, "Dockerfile.preview");
|
|
13346
13665
|
const { stat } = await import("fs/promises");
|
|
13347
13666
|
let hasConsumerDockerfile = false;
|
|
13348
13667
|
try {
|
|
@@ -13527,7 +13846,7 @@ var init_tickShellRunner = __esm({
|
|
|
13527
13846
|
|
|
13528
13847
|
// src/scripts/runScheduledAgentActionTick.ts
|
|
13529
13848
|
import * as fs37 from "fs";
|
|
13530
|
-
import * as
|
|
13849
|
+
import * as path37 from "path";
|
|
13531
13850
|
var runScheduledAgentActionTick;
|
|
13532
13851
|
var init_runScheduledAgentActionTick = __esm({
|
|
13533
13852
|
"src/scripts/runScheduledAgentActionTick.ts"() {
|
|
@@ -13541,19 +13860,19 @@ var init_runScheduledAgentActionTick = __esm({
|
|
|
13541
13860
|
const slugArg = String(args?.slugArg ?? "agentResponsibility");
|
|
13542
13861
|
const fenceLabel = String(args?.fenceLabel ?? "kody-job-next-state");
|
|
13543
13862
|
const shell = String(args?.shell ?? "tick.sh");
|
|
13544
|
-
const
|
|
13545
|
-
if (!
|
|
13863
|
+
const slug2 = String(args?.slug ?? ctx.args[slugArg] ?? "").trim();
|
|
13864
|
+
if (!slug2) {
|
|
13546
13865
|
ctx.output.exitCode = 99;
|
|
13547
13866
|
ctx.output.reason = `runScheduledAgentActionTick: args.slug or ctx.args.${slugArg} must be non-empty agentResponsibility slug`;
|
|
13548
13867
|
return;
|
|
13549
13868
|
}
|
|
13550
|
-
const agentResponsibility = resolveAgentResponsibilityFolder(
|
|
13869
|
+
const agentResponsibility = resolveAgentResponsibilityFolder(slug2, path37.join(ctx.cwd, jobsDir));
|
|
13551
13870
|
if (!agentResponsibility) {
|
|
13552
13871
|
ctx.output.exitCode = 99;
|
|
13553
|
-
ctx.output.reason = `runScheduledAgentActionTick: agentResponsibility folder not found or incomplete: ${
|
|
13872
|
+
ctx.output.reason = `runScheduledAgentActionTick: agentResponsibility folder not found or incomplete: ${slug2} (searched ${jobsDir} and company store)`;
|
|
13554
13873
|
return;
|
|
13555
13874
|
}
|
|
13556
|
-
const shellPath =
|
|
13875
|
+
const shellPath = path37.join(profile.dir, shell);
|
|
13557
13876
|
if (!fs37.existsSync(shellPath)) {
|
|
13558
13877
|
ctx.output.exitCode = 99;
|
|
13559
13878
|
ctx.output.reason = `runScheduledAgentActionTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
@@ -13562,14 +13881,14 @@ var init_runScheduledAgentActionTick = __esm({
|
|
|
13562
13881
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
13563
13882
|
let loaded;
|
|
13564
13883
|
try {
|
|
13565
|
-
loaded = await backend.load(
|
|
13884
|
+
loaded = await backend.load(slug2);
|
|
13566
13885
|
} catch (err) {
|
|
13567
13886
|
ctx.output.exitCode = 99;
|
|
13568
13887
|
ctx.output.reason = `runScheduledAgentActionTick: state load failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
13569
13888
|
return;
|
|
13570
13889
|
}
|
|
13571
|
-
ctx.data.jobSlug =
|
|
13572
|
-
ctx.data.agentResponsibilitySlug =
|
|
13890
|
+
ctx.data.jobSlug = slug2;
|
|
13891
|
+
ctx.data.agentResponsibilitySlug = slug2;
|
|
13573
13892
|
ctx.data.agentActionSlug = profile.name;
|
|
13574
13893
|
ctx.data.jobState = loaded;
|
|
13575
13894
|
runTickShellAndParse({
|
|
@@ -13586,7 +13905,7 @@ var init_runScheduledAgentActionTick = __esm({
|
|
|
13586
13905
|
|
|
13587
13906
|
// src/scripts/runTickScript.ts
|
|
13588
13907
|
import * as fs38 from "fs";
|
|
13589
|
-
import * as
|
|
13908
|
+
import * as path38 from "path";
|
|
13590
13909
|
var runTickScript;
|
|
13591
13910
|
var init_runTickScript = __esm({
|
|
13592
13911
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -13599,25 +13918,25 @@ var init_runTickScript = __esm({
|
|
|
13599
13918
|
const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
|
|
13600
13919
|
const slugArg = String(args?.slugArg ?? "job");
|
|
13601
13920
|
const fenceLabel = String(args?.fenceLabel ?? "kody-job-next-state");
|
|
13602
|
-
const
|
|
13603
|
-
if (!
|
|
13921
|
+
const slug2 = String(ctx.args[slugArg] ?? "").trim();
|
|
13922
|
+
if (!slug2) {
|
|
13604
13923
|
ctx.output.exitCode = 99;
|
|
13605
13924
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
13606
13925
|
return;
|
|
13607
13926
|
}
|
|
13608
|
-
const agentResponsibility = readAgentResponsibilityFolder(
|
|
13927
|
+
const agentResponsibility = readAgentResponsibilityFolder(path38.join(ctx.cwd, jobsDir), slug2);
|
|
13609
13928
|
if (!agentResponsibility) {
|
|
13610
13929
|
ctx.output.exitCode = 99;
|
|
13611
|
-
ctx.output.reason = `runTickScript: agentResponsibility folder not found or incomplete: ${
|
|
13930
|
+
ctx.output.reason = `runTickScript: agentResponsibility folder not found or incomplete: ${path38.join(ctx.cwd, jobsDir, slug2)}`;
|
|
13612
13931
|
return;
|
|
13613
13932
|
}
|
|
13614
13933
|
const tickScript = agentResponsibility.config.tickScript;
|
|
13615
13934
|
if (!tickScript) {
|
|
13616
13935
|
ctx.output.exitCode = 99;
|
|
13617
|
-
ctx.output.reason = `runTickScript: agentResponsibility ${
|
|
13936
|
+
ctx.output.reason = `runTickScript: agentResponsibility ${slug2} has no \`tickScript\` in profile.json \u2014 route via agent-responsibility-tick instead`;
|
|
13618
13937
|
return;
|
|
13619
13938
|
}
|
|
13620
|
-
const scriptPath =
|
|
13939
|
+
const scriptPath = path38.isAbsolute(tickScript) ? tickScript : path38.join(ctx.cwd, tickScript);
|
|
13621
13940
|
if (!fs38.existsSync(scriptPath)) {
|
|
13622
13941
|
ctx.output.exitCode = 99;
|
|
13623
13942
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
@@ -13626,13 +13945,13 @@ var init_runTickScript = __esm({
|
|
|
13626
13945
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
13627
13946
|
let loaded;
|
|
13628
13947
|
try {
|
|
13629
|
-
loaded = await backend.load(
|
|
13948
|
+
loaded = await backend.load(slug2);
|
|
13630
13949
|
} catch (err) {
|
|
13631
13950
|
ctx.output.exitCode = 99;
|
|
13632
13951
|
ctx.output.reason = `runTickScript: state load failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
13633
13952
|
return;
|
|
13634
13953
|
}
|
|
13635
|
-
ctx.data.jobSlug =
|
|
13954
|
+
ctx.data.jobSlug = slug2;
|
|
13636
13955
|
ctx.data.jobState = loaded;
|
|
13637
13956
|
runTickShellAndParse({
|
|
13638
13957
|
ctx,
|
|
@@ -14577,6 +14896,86 @@ var init_writeJobStateFile = __esm({
|
|
|
14577
14896
|
}
|
|
14578
14897
|
});
|
|
14579
14898
|
|
|
14899
|
+
// src/scripts/writeResponsibilityReport.ts
|
|
14900
|
+
function writeReport(ctx, profile, agentResult) {
|
|
14901
|
+
const slug2 = responsibilitySlug(ctx);
|
|
14902
|
+
if (!slug2) {
|
|
14903
|
+
fail2(ctx, "writeResponsibilityReport: missing responsibility slug");
|
|
14904
|
+
return;
|
|
14905
|
+
}
|
|
14906
|
+
if (!REPORT_SLUG_RE.test(slug2)) {
|
|
14907
|
+
fail2(ctx, `writeResponsibilityReport: invalid responsibility slug "${slug2}"`);
|
|
14908
|
+
return;
|
|
14909
|
+
}
|
|
14910
|
+
const body = reportBody(ctx, agentResult, profile);
|
|
14911
|
+
if (!body.trim()) {
|
|
14912
|
+
fail2(ctx, `writeResponsibilityReport: ${slug2} produced no report output`);
|
|
14913
|
+
return;
|
|
14914
|
+
}
|
|
14915
|
+
const filePath = `reports/${slug2}.md`;
|
|
14916
|
+
const current = readStateText(ctx.config, ctx.cwd, filePath);
|
|
14917
|
+
if (current?.content === body) {
|
|
14918
|
+
ctx.data.responsibilityReport = { slug: slug2, path: current.path, changed: false };
|
|
14919
|
+
return;
|
|
14920
|
+
}
|
|
14921
|
+
upsertStateText(
|
|
14922
|
+
ctx.config,
|
|
14923
|
+
ctx.cwd,
|
|
14924
|
+
filePath,
|
|
14925
|
+
body,
|
|
14926
|
+
`chore(reports): refresh ${slug2}`
|
|
14927
|
+
);
|
|
14928
|
+
ctx.data.responsibilityReport = { slug: slug2, path: filePath, changed: true };
|
|
14929
|
+
}
|
|
14930
|
+
function responsibilitySlug(ctx) {
|
|
14931
|
+
const candidates = [
|
|
14932
|
+
ctx.data.jobAgentResponsibility,
|
|
14933
|
+
ctx.data.agentResponsibilitySlug,
|
|
14934
|
+
ctx.data.jobSlug
|
|
14935
|
+
];
|
|
14936
|
+
for (const candidate of candidates) {
|
|
14937
|
+
if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
|
|
14938
|
+
}
|
|
14939
|
+
return null;
|
|
14940
|
+
}
|
|
14941
|
+
function reportBody(ctx, agentResult, profile) {
|
|
14942
|
+
const prSummary = ctx.data.prSummary;
|
|
14943
|
+
if (typeof prSummary === "string" && prSummary.trim()) return ensureTrailingNewline(prSummary.trim());
|
|
14944
|
+
if (agentResult?.finalText.trim()) return ensureTrailingNewline(agentResult.finalText.trim());
|
|
14945
|
+
const reason = ctx.output.reason || ctx.data.agentFailureReason || agentResult?.error;
|
|
14946
|
+
if (typeof reason === "string" && reason.trim()) {
|
|
14947
|
+
return `# ${profile.name}
|
|
14948
|
+
|
|
14949
|
+
FAILED: ${reason.trim()}
|
|
14950
|
+
`;
|
|
14951
|
+
}
|
|
14952
|
+
return "";
|
|
14953
|
+
}
|
|
14954
|
+
function fail2(ctx, reason) {
|
|
14955
|
+
ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; ${reason}` : reason;
|
|
14956
|
+
if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
|
|
14957
|
+
}
|
|
14958
|
+
function ensureTrailingNewline(value) {
|
|
14959
|
+
return value.endsWith("\n") ? value : `${value}
|
|
14960
|
+
`;
|
|
14961
|
+
}
|
|
14962
|
+
var REPORT_SLUG_RE, writeResponsibilityReport;
|
|
14963
|
+
var init_writeResponsibilityReport = __esm({
|
|
14964
|
+
"src/scripts/writeResponsibilityReport.ts"() {
|
|
14965
|
+
"use strict";
|
|
14966
|
+
init_stateRepo();
|
|
14967
|
+
REPORT_SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
14968
|
+
writeResponsibilityReport = async (ctx, profile, agentResult) => {
|
|
14969
|
+
if (ctx.data.jobSaveReport !== true) return;
|
|
14970
|
+
try {
|
|
14971
|
+
writeReport(ctx, profile, agentResult);
|
|
14972
|
+
} catch (err) {
|
|
14973
|
+
fail2(ctx, `writeResponsibilityReport: ${err instanceof Error ? err.message : String(err)}`);
|
|
14974
|
+
}
|
|
14975
|
+
};
|
|
14976
|
+
}
|
|
14977
|
+
});
|
|
14978
|
+
|
|
14580
14979
|
// src/scripts/index.ts
|
|
14581
14980
|
var preflightScripts, postflightScripts, allScriptNames;
|
|
14582
14981
|
var init_scripts = __esm({
|
|
@@ -14586,7 +14985,9 @@ var init_scripts = __esm({
|
|
|
14586
14985
|
init_advanceFlow();
|
|
14587
14986
|
init_advanceManagedGoal();
|
|
14588
14987
|
init_appendCompanyActivity();
|
|
14988
|
+
init_appendCompanyIntentDecision();
|
|
14589
14989
|
init_applyAgentResponsibilityReports();
|
|
14990
|
+
init_applyCompanyManagerDecision();
|
|
14590
14991
|
init_buildSyntheticPlugin();
|
|
14591
14992
|
init_checkCoverageWithRetry();
|
|
14592
14993
|
init_classifyByLabel();
|
|
@@ -14611,6 +15012,8 @@ var init_scripts = __esm({
|
|
|
14611
15012
|
init_initFlow();
|
|
14612
15013
|
init_loadAgentAdhoc();
|
|
14613
15014
|
init_loadAgentResponsibilityState();
|
|
15015
|
+
init_loadCompanyIntents();
|
|
15016
|
+
init_loadCompanyPortfolio();
|
|
14614
15017
|
init_loadConventions();
|
|
14615
15018
|
init_loadCoverageRules();
|
|
14616
15019
|
init_loadGoalState();
|
|
@@ -14631,6 +15034,7 @@ var init_scripts = __esm({
|
|
|
14631
15034
|
init_openAgentFactoryStatePr();
|
|
14632
15035
|
init_openQaIssue();
|
|
14633
15036
|
init_parseAgentResult();
|
|
15037
|
+
init_parseCompanyManagerDecision();
|
|
14634
15038
|
init_parseIssueStateFromAgentResult();
|
|
14635
15039
|
init_parseJobStateFromAgentResult();
|
|
14636
15040
|
init_parseReproOutput();
|
|
@@ -14673,6 +15077,7 @@ var init_scripts = __esm({
|
|
|
14673
15077
|
init_writeAgentRunSummary();
|
|
14674
15078
|
init_writeIssueStateComment();
|
|
14675
15079
|
init_writeJobStateFile();
|
|
15080
|
+
init_writeResponsibilityReport();
|
|
14676
15081
|
preflightScripts = {
|
|
14677
15082
|
runFlow,
|
|
14678
15083
|
fixFlow,
|
|
@@ -14689,6 +15094,8 @@ var init_scripts = __esm({
|
|
|
14689
15094
|
loadIssueStateComment,
|
|
14690
15095
|
loadJobFromFile,
|
|
14691
15096
|
loadAgentResponsibilityState,
|
|
15097
|
+
loadCompanyIntents,
|
|
15098
|
+
loadCompanyPortfolio,
|
|
14692
15099
|
loadAgentAdhoc,
|
|
14693
15100
|
loadConventions,
|
|
14694
15101
|
loadCoverageRules,
|
|
@@ -14723,12 +15130,15 @@ var init_scripts = __esm({
|
|
|
14723
15130
|
};
|
|
14724
15131
|
postflightScripts = {
|
|
14725
15132
|
parseAgentResult: parseAgentResult2,
|
|
15133
|
+
parseCompanyManagerDecision,
|
|
14726
15134
|
parseIssueStateFromAgentResult,
|
|
14727
15135
|
parseJobStateFromAgentResult,
|
|
14728
15136
|
parseReproOutput,
|
|
14729
15137
|
writeIssueStateComment,
|
|
14730
15138
|
writeJobStateFile,
|
|
14731
15139
|
appendCompanyActivity,
|
|
15140
|
+
appendCompanyIntentDecision: appendCompanyIntentDecision2,
|
|
15141
|
+
applyCompanyManagerDecision,
|
|
14732
15142
|
requireFeedbackActions,
|
|
14733
15143
|
requirePlanDeviations,
|
|
14734
15144
|
verify,
|
|
@@ -14746,6 +15156,7 @@ var init_scripts = __esm({
|
|
|
14746
15156
|
postReviewResult,
|
|
14747
15157
|
persistArtifacts,
|
|
14748
15158
|
writeAgentRunSummary,
|
|
15159
|
+
writeResponsibilityReport,
|
|
14749
15160
|
saveTaskState,
|
|
14750
15161
|
mirrorStateToPr,
|
|
14751
15162
|
startFlow,
|
|
@@ -14842,7 +15253,7 @@ var init_tools = __esm({
|
|
|
14842
15253
|
// src/executor.ts
|
|
14843
15254
|
import { spawn as spawn7 } from "child_process";
|
|
14844
15255
|
import * as fs40 from "fs";
|
|
14845
|
-
import * as
|
|
15256
|
+
import * as path39 from "path";
|
|
14846
15257
|
function isMutatingPostflight(scriptName) {
|
|
14847
15258
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
14848
15259
|
}
|
|
@@ -15007,13 +15418,13 @@ async function runAgentAction(profileName, input) {
|
|
|
15007
15418
|
})
|
|
15008
15419
|
};
|
|
15009
15420
|
})() : null;
|
|
15010
|
-
const ndjsonDir =
|
|
15421
|
+
const ndjsonDir = path39.join(input.cwd, ".kody");
|
|
15011
15422
|
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
15423
|
const agentIdentityBlock = agentSlug ? frameAgentIdentity(agentSlug, loadAgentIdentity(input.cwd, agentSlug)) : null;
|
|
15013
15424
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
15014
15425
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
15015
15426
|
const invokeAgent = async (prompt) => {
|
|
15016
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
15427
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path39.isAbsolute(p) ? p : path39.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
15017
15428
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
15018
15429
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
15019
15430
|
const agents = loadSubagents(profile);
|
|
@@ -15248,6 +15659,7 @@ async function runAgentAction(profileName, input) {
|
|
|
15248
15659
|
outcome: postOutcome
|
|
15249
15660
|
});
|
|
15250
15661
|
}
|
|
15662
|
+
await writeResponsibilityReport(ctx, profile, agentResult);
|
|
15251
15663
|
return finishAndEnd({
|
|
15252
15664
|
exitCode: ctx.output.exitCode ?? 0,
|
|
15253
15665
|
prUrl: ctx.output.prUrl,
|
|
@@ -15376,7 +15788,8 @@ function handoffToJob(handoff) {
|
|
|
15376
15788
|
agentResponsibility: handoff.agentResponsibility,
|
|
15377
15789
|
agentAction: handoff.agentAction,
|
|
15378
15790
|
cliArgs: handoff.cliArgs,
|
|
15379
|
-
flavor: "instant"
|
|
15791
|
+
flavor: "instant",
|
|
15792
|
+
saveReport: handoff.saveReport === true
|
|
15380
15793
|
};
|
|
15381
15794
|
}
|
|
15382
15795
|
function clearStampedLifecycleLabels(profile, ctx) {
|
|
@@ -15395,13 +15808,13 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
15395
15808
|
function resolveProfilePath(profileName) {
|
|
15396
15809
|
const found = resolveAgentAction(profileName);
|
|
15397
15810
|
if (found) return found;
|
|
15398
|
-
const here =
|
|
15811
|
+
const here = path39.dirname(new URL(import.meta.url).pathname);
|
|
15399
15812
|
const candidates = [
|
|
15400
|
-
|
|
15813
|
+
path39.join(here, "agent-actions", profileName, "profile.json"),
|
|
15401
15814
|
// same-dir sibling (dev)
|
|
15402
|
-
|
|
15815
|
+
path39.join(here, "..", "agent-actions", profileName, "profile.json"),
|
|
15403
15816
|
// up one (prod: dist/bin → dist/agent-actions)
|
|
15404
|
-
|
|
15817
|
+
path39.join(here, "..", "src", "agent-actions", profileName, "profile.json")
|
|
15405
15818
|
// fallback
|
|
15406
15819
|
];
|
|
15407
15820
|
for (const c of candidates) {
|
|
@@ -15503,7 +15916,7 @@ function resolveShellTimeoutMs(entry) {
|
|
|
15503
15916
|
}
|
|
15504
15917
|
async function runShellEntry(entry, ctx, profile) {
|
|
15505
15918
|
const shellName = entry.shell;
|
|
15506
|
-
const shellPath =
|
|
15919
|
+
const shellPath = path39.join(profile.dir, shellName);
|
|
15507
15920
|
if (!fs40.existsSync(shellPath)) {
|
|
15508
15921
|
ctx.skipAgent = true;
|
|
15509
15922
|
ctx.output.exitCode = 99;
|
|
@@ -15636,6 +16049,7 @@ var init_executor = __esm({
|
|
|
15636
16049
|
init_profile();
|
|
15637
16050
|
init_registry();
|
|
15638
16051
|
init_scripts();
|
|
16052
|
+
init_writeResponsibilityReport();
|
|
15639
16053
|
init_subagents();
|
|
15640
16054
|
init_task_artifacts();
|
|
15641
16055
|
init_tools();
|
|
@@ -15663,7 +16077,7 @@ __export(job_exports, {
|
|
|
15663
16077
|
stableJobKey: () => stableJobKey,
|
|
15664
16078
|
validateJob: () => validateJob
|
|
15665
16079
|
});
|
|
15666
|
-
import * as
|
|
16080
|
+
import * as path40 from "path";
|
|
15667
16081
|
function newJobId(flavor) {
|
|
15668
16082
|
localJobSeq += 1;
|
|
15669
16083
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -15694,13 +16108,14 @@ function validateJob(input) {
|
|
|
15694
16108
|
target: typeof j.target === "number" ? j.target : void 0,
|
|
15695
16109
|
cliArgs: j.cliArgs ?? {},
|
|
15696
16110
|
flavor: j.flavor,
|
|
15697
|
-
force: j.force === true
|
|
16111
|
+
force: j.force === true,
|
|
16112
|
+
saveReport: j.saveReport === true
|
|
15698
16113
|
};
|
|
15699
16114
|
}
|
|
15700
16115
|
async function runJob(job, base) {
|
|
15701
16116
|
const valid = validateJob(job);
|
|
15702
16117
|
const action = valid.action ?? valid.agentResponsibility;
|
|
15703
|
-
const projectAgentResponsibilitiesRoot =
|
|
16118
|
+
const projectAgentResponsibilitiesRoot = path40.join(base.cwd, ".kody", "agent-responsibilities");
|
|
15704
16119
|
const resolvedAgentResponsibility = action ? resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot) : null;
|
|
15705
16120
|
const agentResponsibilityIdentity = valid.agentResponsibility ?? resolvedAgentResponsibility?.agentResponsibility;
|
|
15706
16121
|
const agentResponsibilityContext = loadAgentResponsibilityContext(agentResponsibilityIdentity, base.cwd);
|
|
@@ -15727,6 +16142,7 @@ async function runJob(job, base) {
|
|
|
15727
16142
|
if (executableIdentity !== void 0 && executableIdentity.length > 0)
|
|
15728
16143
|
preloadedData.jobAgentAction = executableIdentity;
|
|
15729
16144
|
if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
|
|
16145
|
+
if (valid.saveReport === true) preloadedData.jobSaveReport = true;
|
|
15730
16146
|
if (agentResponsibilityContext) {
|
|
15731
16147
|
preloadedData.agentResponsibilitySlug = agentResponsibilityContext.slug;
|
|
15732
16148
|
preloadedData.agentResponsibilityTitle = agentResponsibilityContext.title;
|
|
@@ -15737,9 +16153,6 @@ async function runJob(job, base) {
|
|
|
15737
16153
|
if (agentResponsibilityContext.config.agent && preloadedData.jobAgent === void 0) {
|
|
15738
16154
|
preloadedData.jobAgent = agentResponsibilityContext.config.agent;
|
|
15739
16155
|
}
|
|
15740
|
-
if (agentResponsibilityContext.config.every && preloadedData.jobSchedule === void 0) {
|
|
15741
|
-
preloadedData.jobSchedule = agentResponsibilityContext.config.every;
|
|
15742
|
-
}
|
|
15743
16156
|
if (agentResponsibilityContext.config.mentions && agentResponsibilityContext.config.mentions.length > 0) {
|
|
15744
16157
|
preloadedData.mentions = agentResponsibilityContext.config.mentions.map((login) => `@${login}`).join(" ");
|
|
15745
16158
|
}
|
|
@@ -15760,9 +16173,9 @@ async function runJob(job, base) {
|
|
|
15760
16173
|
const run = base.chain === false ? runAgentAction : runAgentActionChain;
|
|
15761
16174
|
return run(profileName, input);
|
|
15762
16175
|
}
|
|
15763
|
-
function loadAgentResponsibilityContext(
|
|
15764
|
-
if (!
|
|
15765
|
-
return resolveAgentResponsibilityFolder(
|
|
16176
|
+
function loadAgentResponsibilityContext(slug2, cwd) {
|
|
16177
|
+
if (!slug2) return null;
|
|
16178
|
+
return resolveAgentResponsibilityFolder(slug2, path40.join(cwd, ".kody", "agent-responsibilities"));
|
|
15766
16179
|
}
|
|
15767
16180
|
function mintInstantJob(dispatch2, opts) {
|
|
15768
16181
|
return {
|
|
@@ -15784,7 +16197,8 @@ function mintScheduledJob(input) {
|
|
|
15784
16197
|
schedule: input.schedule,
|
|
15785
16198
|
agent: input.agent,
|
|
15786
16199
|
cliArgs: input.cliArgs ?? {},
|
|
15787
|
-
flavor: "scheduled"
|
|
16200
|
+
flavor: "scheduled",
|
|
16201
|
+
saveReport: input.saveReport === true
|
|
15788
16202
|
};
|
|
15789
16203
|
}
|
|
15790
16204
|
var DEFAULT_INSTANT_AGENT, localJobSeq, InvalidJobError;
|
|
@@ -15915,7 +16329,7 @@ function translateOpenAISseToBrain(opts) {
|
|
|
15915
16329
|
// src/servers/brain-serve.ts
|
|
15916
16330
|
import * as fs43 from "fs";
|
|
15917
16331
|
import { createServer } from "http";
|
|
15918
|
-
import * as
|
|
16332
|
+
import * as path43 from "path";
|
|
15919
16333
|
|
|
15920
16334
|
// src/chat/loop.ts
|
|
15921
16335
|
init_agent();
|
|
@@ -16458,7 +16872,7 @@ init_config();
|
|
|
16458
16872
|
// src/kody-cli.ts
|
|
16459
16873
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
16460
16874
|
import * as fs41 from "fs";
|
|
16461
|
-
import * as
|
|
16875
|
+
import * as path41 from "path";
|
|
16462
16876
|
|
|
16463
16877
|
// src/app-auth.ts
|
|
16464
16878
|
import { createSign } from "crypto";
|
|
@@ -17054,9 +17468,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
17054
17468
|
return void 0;
|
|
17055
17469
|
}
|
|
17056
17470
|
function detectPackageManager2(cwd) {
|
|
17057
|
-
if (fs41.existsSync(
|
|
17058
|
-
if (fs41.existsSync(
|
|
17059
|
-
if (fs41.existsSync(
|
|
17471
|
+
if (fs41.existsSync(path41.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
17472
|
+
if (fs41.existsSync(path41.join(cwd, "yarn.lock"))) return "yarn";
|
|
17473
|
+
if (fs41.existsSync(path41.join(cwd, "bun.lockb"))) return "bun";
|
|
17060
17474
|
return "npm";
|
|
17061
17475
|
}
|
|
17062
17476
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
@@ -17143,7 +17557,7 @@ function configureGitIdentity(cwd) {
|
|
|
17143
17557
|
}
|
|
17144
17558
|
function postFailureTail(issueNumber, cwd, reason) {
|
|
17145
17559
|
if (!issueNumber) return;
|
|
17146
|
-
const logPath =
|
|
17560
|
+
const logPath = path41.join(cwd, ".kody", "last-run.jsonl");
|
|
17147
17561
|
let tail = "";
|
|
17148
17562
|
try {
|
|
17149
17563
|
if (fs41.existsSync(logPath)) {
|
|
@@ -17172,7 +17586,7 @@ async function runCi(argv) {
|
|
|
17172
17586
|
return 0;
|
|
17173
17587
|
}
|
|
17174
17588
|
const args = parseCiArgs(argv);
|
|
17175
|
-
const cwd = args.cwd ?
|
|
17589
|
+
const cwd = args.cwd ? path41.resolve(args.cwd) : process.cwd();
|
|
17176
17590
|
let earlyConfig;
|
|
17177
17591
|
let earlyConfigError;
|
|
17178
17592
|
try {
|
|
@@ -17514,10 +17928,10 @@ init_repoWorkspace();
|
|
|
17514
17928
|
|
|
17515
17929
|
// src/scripts/brainTurnLog.ts
|
|
17516
17930
|
import * as fs42 from "fs";
|
|
17517
|
-
import * as
|
|
17931
|
+
import * as path42 from "path";
|
|
17518
17932
|
var live = /* @__PURE__ */ new Map();
|
|
17519
17933
|
function eventsPath2(dir, chatId) {
|
|
17520
|
-
return
|
|
17934
|
+
return path42.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
|
|
17521
17935
|
}
|
|
17522
17936
|
function lastPersistedSeq(dir, chatId) {
|
|
17523
17937
|
const p = eventsPath2(dir, chatId);
|
|
@@ -17560,7 +17974,7 @@ function beginTurn(dir, chatId) {
|
|
|
17560
17974
|
};
|
|
17561
17975
|
live.set(chatId, state);
|
|
17562
17976
|
const p = eventsPath2(dir, chatId);
|
|
17563
|
-
fs42.mkdirSync(
|
|
17977
|
+
fs42.mkdirSync(path42.dirname(p), { recursive: true });
|
|
17564
17978
|
return (event) => {
|
|
17565
17979
|
state.seq += 1;
|
|
17566
17980
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
@@ -17835,7 +18249,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
17835
18249
|
const repo = strField(body, "repo");
|
|
17836
18250
|
const repoToken = strField(body, "repoToken");
|
|
17837
18251
|
const sessionFile = sessionFilePath(opts.cwd, chatId);
|
|
17838
|
-
fs43.mkdirSync(
|
|
18252
|
+
fs43.mkdirSync(path43.dirname(sessionFile), { recursive: true });
|
|
17839
18253
|
appendTurn(sessionFile, {
|
|
17840
18254
|
role: "user",
|
|
17841
18255
|
content: message,
|
|
@@ -17882,7 +18296,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
17882
18296
|
function buildServer(opts) {
|
|
17883
18297
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
17884
18298
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
17885
|
-
const reposRoot = opts.reposRoot ??
|
|
18299
|
+
const reposRoot = opts.reposRoot ?? path43.join(path43.dirname(path43.resolve(opts.cwd)), "repos");
|
|
17886
18300
|
return createServer(async (req, res) => {
|
|
17887
18301
|
if (!req.method || !req.url) {
|
|
17888
18302
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -18478,13 +18892,13 @@ async function loadConfigSafe() {
|
|
|
18478
18892
|
// src/chat-cli.ts
|
|
18479
18893
|
import { execFileSync as execFileSync28 } from "child_process";
|
|
18480
18894
|
import * as fs45 from "fs";
|
|
18481
|
-
import * as
|
|
18895
|
+
import * as path45 from "path";
|
|
18482
18896
|
|
|
18483
18897
|
// src/chat/modes/interactive.ts
|
|
18484
18898
|
init_issue();
|
|
18485
18899
|
import { execFileSync as execFileSync27 } from "child_process";
|
|
18486
18900
|
import * as fs44 from "fs";
|
|
18487
|
-
import * as
|
|
18901
|
+
import * as path44 from "path";
|
|
18488
18902
|
|
|
18489
18903
|
// src/chat/inbox.ts
|
|
18490
18904
|
import { execFileSync as execFileSync26 } from "child_process";
|
|
@@ -18644,9 +19058,9 @@ function findNextUserTurn(turns, fromIdx) {
|
|
|
18644
19058
|
return -1;
|
|
18645
19059
|
}
|
|
18646
19060
|
function commitTurn(cwd, sessionId, _verbose) {
|
|
18647
|
-
const sessionRel =
|
|
18648
|
-
const eventsRel =
|
|
18649
|
-
const rels = [sessionRel, eventsRel].filter((p) => fs44.existsSync(
|
|
19061
|
+
const sessionRel = path44.relative(cwd, sessionFilePath(cwd, sessionId));
|
|
19062
|
+
const eventsRel = path44.relative(cwd, eventsFilePath(cwd, sessionId));
|
|
19063
|
+
const rels = [sessionRel, eventsRel].filter((p) => fs44.existsSync(path44.join(cwd, p)));
|
|
18650
19064
|
if (rels.length === 0) return;
|
|
18651
19065
|
const repository = process.env.GITHUB_REPOSITORY;
|
|
18652
19066
|
if (!repository) {
|
|
@@ -18658,8 +19072,8 @@ function commitTurn(cwd, sessionId, _verbose) {
|
|
|
18658
19072
|
}
|
|
18659
19073
|
const branch = defaultBranch(cwd) ?? "main";
|
|
18660
19074
|
for (const rel of rels) {
|
|
18661
|
-
const repoPath = rel.split(
|
|
18662
|
-
const localText = fs44.readFileSync(
|
|
19075
|
+
const repoPath = rel.split(path44.sep).join("/");
|
|
19076
|
+
const localText = fs44.readFileSync(path44.join(cwd, rel), "utf-8");
|
|
18663
19077
|
putJsonlViaContents(repository, branch, repoPath, localText, sessionId, cwd);
|
|
18664
19078
|
}
|
|
18665
19079
|
}
|
|
@@ -18804,12 +19218,12 @@ function parseChatArgs(argv, env = process.env) {
|
|
|
18804
19218
|
return result;
|
|
18805
19219
|
}
|
|
18806
19220
|
function commitChatFiles(cwd, sessionId, verbose) {
|
|
18807
|
-
const sessionFile =
|
|
18808
|
-
const eventsFile =
|
|
19221
|
+
const sessionFile = path45.relative(cwd, sessionFilePath(cwd, sessionId));
|
|
19222
|
+
const eventsFile = path45.relative(cwd, eventsFilePath(cwd, sessionId));
|
|
18809
19223
|
const safeSession = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
18810
|
-
const tasksDir =
|
|
19224
|
+
const tasksDir = path45.join(".kody", "tasks", safeSession);
|
|
18811
19225
|
const candidatePaths = [sessionFile, eventsFile, tasksDir];
|
|
18812
|
-
const paths = candidatePaths.filter((p) => fs45.existsSync(
|
|
19226
|
+
const paths = candidatePaths.filter((p) => fs45.existsSync(path45.join(cwd, p)));
|
|
18813
19227
|
if (paths.length === 0) return;
|
|
18814
19228
|
const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
|
|
18815
19229
|
try {
|
|
@@ -18853,7 +19267,7 @@ async function runChat(argv) {
|
|
|
18853
19267
|
${CHAT_HELP}`);
|
|
18854
19268
|
return 64;
|
|
18855
19269
|
}
|
|
18856
|
-
const cwd = args.cwd ?
|
|
19270
|
+
const cwd = args.cwd ? path45.resolve(args.cwd) : process.cwd();
|
|
18857
19271
|
const sessionId = args.sessionId;
|
|
18858
19272
|
const unpackedSecrets = unpackAllSecrets();
|
|
18859
19273
|
if (unpackedSecrets > 0) {
|
|
@@ -19064,8 +19478,8 @@ var FlyClient = class {
|
|
|
19064
19478
|
get fetch() {
|
|
19065
19479
|
return this.opts.fetchImpl ?? fetch;
|
|
19066
19480
|
}
|
|
19067
|
-
async call(
|
|
19068
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
19481
|
+
async call(path46, init = {}) {
|
|
19482
|
+
const res = await this.fetch(`${FLY_API_BASE}${path46}`, {
|
|
19069
19483
|
method: init.method ?? "GET",
|
|
19070
19484
|
headers: {
|
|
19071
19485
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -19076,7 +19490,7 @@ var FlyClient = class {
|
|
|
19076
19490
|
if (res.status === 404 && init.allow404) return null;
|
|
19077
19491
|
if (!res.ok) {
|
|
19078
19492
|
const text = await res.text().catch(() => "");
|
|
19079
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
19493
|
+
throw new Error(`Fly API ${res.status} on ${path46}: ${text.slice(0, 200) || res.statusText}`);
|
|
19080
19494
|
}
|
|
19081
19495
|
if (res.status === 204) return null;
|
|
19082
19496
|
const raw = await res.text();
|