@kody-ade/kody-engine 0.4.64 → 0.4.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/kody.js +817 -530
- package/dist/executables/bug/profile.json +1 -0
- package/dist/executables/chore/profile.json +1 -0
- package/dist/executables/feature/profile.json +1 -0
- package/dist/executables/fix/profile.json +11 -27
- package/dist/executables/fix-ci/profile.json +12 -53
- package/dist/executables/goal-scheduler/scheduler.sh +0 -0
- package/dist/executables/release-deploy/deploy.sh +0 -0
- package/dist/executables/release-prepare/prepare.sh +0 -0
- package/dist/executables/release-publish/publish.sh +0 -0
- package/dist/executables/resolve/apply-prefer.sh +0 -0
- package/dist/executables/revert/revert.sh +0 -0
- package/dist/executables/run/profile.json +14 -28
- package/dist/executables/types.ts +32 -0
- package/package.json +14 -15
package/dist/bin/kody.js
CHANGED
|
@@ -312,10 +312,559 @@ var init_verifyMcp = __esm({
|
|
|
312
312
|
}
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
+
// src/issue.ts
|
|
316
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
317
|
+
function ghToken() {
|
|
318
|
+
return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
|
|
319
|
+
}
|
|
320
|
+
function gh(args, options) {
|
|
321
|
+
const token = ghToken();
|
|
322
|
+
const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
|
|
323
|
+
return execFileSync3("gh", args, {
|
|
324
|
+
encoding: "utf-8",
|
|
325
|
+
timeout: API_TIMEOUT_MS,
|
|
326
|
+
cwd: options?.cwd,
|
|
327
|
+
env,
|
|
328
|
+
input: options?.input,
|
|
329
|
+
stdio: options?.input ? ["pipe", "pipe", "pipe"] : ["inherit", "pipe", "pipe"]
|
|
330
|
+
}).trim();
|
|
331
|
+
}
|
|
332
|
+
function getIssue(issueNumber, cwd) {
|
|
333
|
+
const output = gh(["issue", "view", String(issueNumber), "--json", "number,title,body,comments,labels"], { cwd });
|
|
334
|
+
const parsed = JSON.parse(output);
|
|
335
|
+
if (typeof parsed?.title !== "string") {
|
|
336
|
+
throw new Error(`Issue #${issueNumber}: unexpected response shape`);
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
number: parsed.number ?? issueNumber,
|
|
340
|
+
title: parsed.title,
|
|
341
|
+
body: parsed.body ?? "",
|
|
342
|
+
comments: (parsed.comments ?? []).map((c) => ({
|
|
343
|
+
body: c.body ?? "",
|
|
344
|
+
author: c.author?.login ?? "unknown",
|
|
345
|
+
createdAt: c.createdAt ?? ""
|
|
346
|
+
})),
|
|
347
|
+
labels: Array.isArray(parsed.labels) ? parsed.labels.map((l) => l.name ?? "").filter((n) => n.length > 0) : []
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function stripKodyMentions(body) {
|
|
351
|
+
return body.replace(/(@)(kody)/gi, "$1\u200B$2");
|
|
352
|
+
}
|
|
353
|
+
function postIssueComment(issueNumber, body, cwd) {
|
|
354
|
+
try {
|
|
355
|
+
gh(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
356
|
+
} catch (err) {
|
|
357
|
+
process.stderr.write(
|
|
358
|
+
`[kody] failed to post comment on #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
359
|
+
`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function truncate2(s, maxBytes) {
|
|
364
|
+
if (s.length <= maxBytes) return s;
|
|
365
|
+
return `${s.slice(0, maxBytes)}\u2026 (+${s.length - maxBytes} chars)`;
|
|
366
|
+
}
|
|
367
|
+
function parsePrNumber(url) {
|
|
368
|
+
const m = url.match(/\/pull\/(\d+)(?:[/?#]|$)/);
|
|
369
|
+
if (!m) return null;
|
|
370
|
+
const n = parseInt(m[1], 10);
|
|
371
|
+
return Number.isFinite(n) ? n : null;
|
|
372
|
+
}
|
|
373
|
+
function getPr(prNumber, cwd) {
|
|
374
|
+
const output = gh(["pr", "view", String(prNumber), "--json", "number,title,body,headRefName,baseRefName,state"], {
|
|
375
|
+
cwd
|
|
376
|
+
});
|
|
377
|
+
const parsed = JSON.parse(output);
|
|
378
|
+
if (typeof parsed?.title !== "string") {
|
|
379
|
+
throw new Error(`PR #${prNumber}: unexpected response shape`);
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
number: parsed.number ?? prNumber,
|
|
383
|
+
title: parsed.title,
|
|
384
|
+
body: parsed.body ?? "",
|
|
385
|
+
headRefName: String(parsed.headRefName ?? ""),
|
|
386
|
+
baseRefName: String(parsed.baseRefName ?? ""),
|
|
387
|
+
state: String(parsed.state ?? "")
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function getPrDiff(prNumber, cwd) {
|
|
391
|
+
try {
|
|
392
|
+
return gh(["pr", "diff", String(prNumber)], { cwd });
|
|
393
|
+
} catch (err) {
|
|
394
|
+
process.stderr.write(
|
|
395
|
+
`[kody] failed to fetch diff for PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
396
|
+
`
|
|
397
|
+
);
|
|
398
|
+
return "";
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function getPrReviews(prNumber, cwd) {
|
|
402
|
+
try {
|
|
403
|
+
const output = gh(["pr", "view", String(prNumber), "--json", "reviews"], { cwd });
|
|
404
|
+
const parsed = JSON.parse(output);
|
|
405
|
+
if (!Array.isArray(parsed?.reviews)) return [];
|
|
406
|
+
return parsed.reviews.map(
|
|
407
|
+
(r) => ({
|
|
408
|
+
body: r.body ?? "",
|
|
409
|
+
state: r.state ?? "",
|
|
410
|
+
author: r.author?.login ?? "unknown",
|
|
411
|
+
submittedAt: r.submittedAt ?? ""
|
|
412
|
+
})
|
|
413
|
+
);
|
|
414
|
+
} catch {
|
|
415
|
+
return [];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
function getPrComments(prNumber, cwd) {
|
|
419
|
+
try {
|
|
420
|
+
const output = gh(["pr", "view", String(prNumber), "--json", "comments"], { cwd });
|
|
421
|
+
const parsed = JSON.parse(output);
|
|
422
|
+
if (!Array.isArray(parsed?.comments)) return [];
|
|
423
|
+
return parsed.comments.map((c) => ({
|
|
424
|
+
body: c.body ?? "",
|
|
425
|
+
author: c.author?.login ?? "unknown",
|
|
426
|
+
createdAt: c.createdAt ?? ""
|
|
427
|
+
})).filter((c) => c.body.trim().length > 0);
|
|
428
|
+
} catch {
|
|
429
|
+
return [];
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function isReviewShaped(body) {
|
|
433
|
+
return VERDICT_HEADING.test(body);
|
|
434
|
+
}
|
|
435
|
+
function getPrLatestReviewBody(prNumber, cwd) {
|
|
436
|
+
const reviews = getPrReviews(prNumber, cwd).filter((r) => r.body.trim().length > 0).map((r) => ({ body: r.body, at: r.submittedAt }));
|
|
437
|
+
const comments = getPrComments(prNumber, cwd).filter((c) => isReviewShaped(c.body)).map((c) => ({ body: c.body, at: c.createdAt }));
|
|
438
|
+
const all = [...reviews, ...comments].sort((a, b) => (b.at || "").localeCompare(a.at || ""));
|
|
439
|
+
if (all.length > 0) return all[0].body;
|
|
440
|
+
const pr = getPr(prNumber, cwd);
|
|
441
|
+
return pr.body;
|
|
442
|
+
}
|
|
443
|
+
function postPrReviewComment(prNumber, body, cwd) {
|
|
444
|
+
try {
|
|
445
|
+
gh(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
446
|
+
} catch (err) {
|
|
447
|
+
process.stderr.write(
|
|
448
|
+
`[kody] failed to post review comment on PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
449
|
+
`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
var API_TIMEOUT_MS, VERDICT_HEADING;
|
|
454
|
+
var init_issue = __esm({
|
|
455
|
+
"src/issue.ts"() {
|
|
456
|
+
"use strict";
|
|
457
|
+
API_TIMEOUT_MS = 3e4;
|
|
458
|
+
VERDICT_HEADING = /(^|\n)\s*#{1,6}\s*Verdict\s*:/i;
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// src/prompt.ts
|
|
463
|
+
import * as fs13 from "fs";
|
|
464
|
+
import * as path12 from "path";
|
|
465
|
+
function loadProjectConventions(projectDir) {
|
|
466
|
+
const out = [];
|
|
467
|
+
for (const rel of CONVENTION_FILES) {
|
|
468
|
+
const abs = path12.join(projectDir, rel);
|
|
469
|
+
if (!fs13.existsSync(abs)) continue;
|
|
470
|
+
let content;
|
|
471
|
+
try {
|
|
472
|
+
content = fs13.readFileSync(abs, "utf-8");
|
|
473
|
+
} catch {
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
const truncated = content.length > CONVENTIONS_PER_FILE_MAX_BYTES;
|
|
477
|
+
if (truncated) content = `${content.slice(0, CONVENTIONS_PER_FILE_MAX_BYTES)}
|
|
478
|
+
|
|
479
|
+
\u2026 (truncated)`;
|
|
480
|
+
out.push({ path: rel, content, truncated });
|
|
481
|
+
}
|
|
482
|
+
return out;
|
|
483
|
+
}
|
|
484
|
+
function parseAgentResult(finalText) {
|
|
485
|
+
const text = (finalText || "").trim();
|
|
486
|
+
if (!text)
|
|
487
|
+
return {
|
|
488
|
+
done: false,
|
|
489
|
+
commitMessage: "",
|
|
490
|
+
prSummary: "",
|
|
491
|
+
feedbackActions: "",
|
|
492
|
+
planDeviations: "",
|
|
493
|
+
priorArt: "",
|
|
494
|
+
failureReason: "agent produced no final message",
|
|
495
|
+
markerMissing: false
|
|
496
|
+
};
|
|
497
|
+
const MARKDOWN_PREFIX = "[\\s>*_#`~\\-]*";
|
|
498
|
+
const FAILED_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}FAILED${MARKDOWN_PREFIX}\\s*:\\s*(.+?)\\s*$`, "is");
|
|
499
|
+
const DONE_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}DONE\\b`, "i");
|
|
500
|
+
const failedMatch = text.match(FAILED_RE);
|
|
501
|
+
if (failedMatch) {
|
|
502
|
+
return {
|
|
503
|
+
done: false,
|
|
504
|
+
commitMessage: "",
|
|
505
|
+
prSummary: "",
|
|
506
|
+
feedbackActions: "",
|
|
507
|
+
planDeviations: "",
|
|
508
|
+
priorArt: "",
|
|
509
|
+
failureReason: stripMarkdownEmphasis(failedMatch[1]),
|
|
510
|
+
markerMissing: false
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
const hasDoneMarker = DONE_RE.test(text);
|
|
514
|
+
const hasCommitMsg = /^[\s>*_#`~-]*COMMIT_MSG\s*:/im.test(text);
|
|
515
|
+
const hasPrSummary = /^[\s>*_#`~-]*PR_SUMMARY\s*:/im.test(text);
|
|
516
|
+
const markerMissing = !hasDoneMarker && !hasCommitMsg && !hasPrSummary;
|
|
517
|
+
const commitMatch = text.match(/^[\s>*_#`~-]*COMMIT_MSG[\s>*_#`~-]*\s*:\s*(.+)$/im);
|
|
518
|
+
const commitMessage = commitMatch ? stripMarkdownEmphasis(commitMatch[1]) : "";
|
|
519
|
+
const feedbackActions = extractBlock(
|
|
520
|
+
text,
|
|
521
|
+
/(?:^|\n)[ \t]*FEEDBACK_ACTIONS\s*:[ \t]*\n/i,
|
|
522
|
+
/(?:^|\n)[ \t]*(?:PLAN_DEVIATIONS|COMMIT_MSG|PR_SUMMARY|PRIOR_ART)\s*:/i
|
|
523
|
+
);
|
|
524
|
+
let planDeviations = extractBlock(
|
|
525
|
+
text,
|
|
526
|
+
/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*\n/i,
|
|
527
|
+
/(?:^|\n)[ \t]*(?:COMMIT_MSG|PR_SUMMARY|FEEDBACK_ACTIONS|PRIOR_ART)\s*:/i
|
|
528
|
+
);
|
|
529
|
+
if (!planDeviations) {
|
|
530
|
+
const inline = text.match(/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
531
|
+
if (inline) planDeviations = inline[1].trim();
|
|
532
|
+
}
|
|
533
|
+
let priorArt = "";
|
|
534
|
+
const priorArtInline = text.match(/(?:^|\n)[ \t]*PRIOR_ART\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
535
|
+
if (priorArtInline) priorArt = priorArtInline[1].trim();
|
|
536
|
+
const summaryStart = text.search(/(^|\n)[ \t]*PR_SUMMARY\s*:[ \t]*\n/i);
|
|
537
|
+
let prSummary = "";
|
|
538
|
+
if (summaryStart !== -1) {
|
|
539
|
+
const afterMarker = text.slice(summaryStart).replace(/^[\s\S]*?PR_SUMMARY\s*:[ \t]*\n/i, "");
|
|
540
|
+
prSummary = afterMarker.replace(/\n\s*```\s*$/g, "").replace(/```\s*$/g, "").trim();
|
|
541
|
+
}
|
|
542
|
+
return {
|
|
543
|
+
done: true,
|
|
544
|
+
commitMessage,
|
|
545
|
+
prSummary,
|
|
546
|
+
feedbackActions,
|
|
547
|
+
planDeviations,
|
|
548
|
+
priorArt,
|
|
549
|
+
failureReason: "",
|
|
550
|
+
markerMissing
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
function stripMarkdownEmphasis(s) {
|
|
554
|
+
return s.trim().replace(/^[*_`~]+|[*_`~]+$/g, "").trim();
|
|
555
|
+
}
|
|
556
|
+
function extractBlock(text, startMarker, endMarker) {
|
|
557
|
+
const startIdx = text.search(startMarker);
|
|
558
|
+
if (startIdx === -1) return "";
|
|
559
|
+
const afterStart = text.slice(startIdx).replace(startMarker, "");
|
|
560
|
+
const endIdx = afterStart.search(endMarker);
|
|
561
|
+
const body = endIdx === -1 ? afterStart : afterStart.slice(0, endIdx);
|
|
562
|
+
return body.replace(/\n\s*```\s*$/g, "").trim();
|
|
563
|
+
}
|
|
564
|
+
var CONVENTIONS_PER_FILE_MAX_BYTES, CONVENTION_FILES;
|
|
565
|
+
var init_prompt = __esm({
|
|
566
|
+
"src/prompt.ts"() {
|
|
567
|
+
"use strict";
|
|
568
|
+
CONVENTIONS_PER_FILE_MAX_BYTES = 3e4;
|
|
569
|
+
CONVENTION_FILES = ["CLAUDE.md", "AGENTS.md"];
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// src/scripts/loadConventions.ts
|
|
574
|
+
var loadConventions_exports = {};
|
|
575
|
+
__export(loadConventions_exports, {
|
|
576
|
+
loadConventions: () => loadConventions
|
|
577
|
+
});
|
|
578
|
+
var loadConventions;
|
|
579
|
+
var init_loadConventions = __esm({
|
|
580
|
+
"src/scripts/loadConventions.ts"() {
|
|
581
|
+
"use strict";
|
|
582
|
+
init_prompt();
|
|
583
|
+
loadConventions = async (ctx) => {
|
|
584
|
+
if (Array.isArray(ctx.data.conventions)) return;
|
|
585
|
+
const conventions = loadProjectConventions(ctx.cwd);
|
|
586
|
+
ctx.data.conventions = conventions;
|
|
587
|
+
if (conventions.length > 0) {
|
|
588
|
+
process.stderr.write(`[kody] loaded conventions: ${conventions.map((c) => c.path).join(", ")}
|
|
589
|
+
`);
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
// src/scripts/loadCoverageRules.ts
|
|
596
|
+
var loadCoverageRules_exports = {};
|
|
597
|
+
__export(loadCoverageRules_exports, {
|
|
598
|
+
loadCoverageRules: () => loadCoverageRules
|
|
599
|
+
});
|
|
600
|
+
var loadCoverageRules;
|
|
601
|
+
var init_loadCoverageRules = __esm({
|
|
602
|
+
"src/scripts/loadCoverageRules.ts"() {
|
|
603
|
+
"use strict";
|
|
604
|
+
loadCoverageRules = async (ctx) => {
|
|
605
|
+
if (Array.isArray(ctx.data.coverageRules)) return;
|
|
606
|
+
ctx.data.coverageRules = ctx.config.testRequirements ?? [];
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// src/scripts/loadMemoryContext.ts
|
|
612
|
+
var loadMemoryContext_exports = {};
|
|
613
|
+
__export(loadMemoryContext_exports, {
|
|
614
|
+
loadMemoryContext: () => loadMemoryContext
|
|
615
|
+
});
|
|
616
|
+
import * as fs27 from "fs";
|
|
617
|
+
import * as path26 from "path";
|
|
618
|
+
function collectPages(memoryAbs) {
|
|
619
|
+
const out = [];
|
|
620
|
+
walkMd(memoryAbs, (file) => {
|
|
621
|
+
let stat;
|
|
622
|
+
try {
|
|
623
|
+
stat = fs27.statSync(file);
|
|
624
|
+
} catch {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
let raw;
|
|
628
|
+
try {
|
|
629
|
+
raw = fs27.readFileSync(file, "utf-8");
|
|
630
|
+
} catch {
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
634
|
+
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path26.basename(file, ".md");
|
|
635
|
+
const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
|
|
636
|
+
out.push({
|
|
637
|
+
relPath: path26.relative(memoryAbs, file),
|
|
638
|
+
title,
|
|
639
|
+
updated,
|
|
640
|
+
content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX : raw,
|
|
641
|
+
mtime: stat.mtimeMs
|
|
642
|
+
});
|
|
643
|
+
});
|
|
644
|
+
return out;
|
|
645
|
+
}
|
|
646
|
+
function extractQueryTerms(ctx) {
|
|
647
|
+
const terms = [];
|
|
648
|
+
const issue = ctx.data.issue;
|
|
649
|
+
const pr = ctx.data.pr;
|
|
650
|
+
if (issue?.title) terms.push(...tokenize(issue.title));
|
|
651
|
+
if (pr?.title) terms.push(...tokenize(pr.title));
|
|
652
|
+
return Array.from(new Set(terms)).slice(0, 20);
|
|
653
|
+
}
|
|
654
|
+
function tokenize(s) {
|
|
655
|
+
return s.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((t) => t.length >= 3);
|
|
656
|
+
}
|
|
657
|
+
function scorePages(pages, terms) {
|
|
658
|
+
return pages.map((p) => {
|
|
659
|
+
const haystack = `${p.title} ${p.content}`.toLowerCase();
|
|
660
|
+
let score = 0;
|
|
661
|
+
for (const t of terms) {
|
|
662
|
+
if (haystack.includes(t)) score++;
|
|
663
|
+
}
|
|
664
|
+
return { p, score };
|
|
665
|
+
}).sort((a, b) => {
|
|
666
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
667
|
+
return b.p.mtime - a.p.mtime;
|
|
668
|
+
}).map((x) => x.p);
|
|
669
|
+
}
|
|
670
|
+
function sortByRecency(pages) {
|
|
671
|
+
return [...pages].sort((a, b) => {
|
|
672
|
+
if (a.updated && b.updated && a.updated !== b.updated) {
|
|
673
|
+
return b.updated.localeCompare(a.updated);
|
|
674
|
+
}
|
|
675
|
+
return b.mtime - a.mtime;
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
function formatBlock(pages) {
|
|
679
|
+
if (pages.length === 0) return "";
|
|
680
|
+
const lines = [
|
|
681
|
+
"# Project memory (`.kody/memory/`)",
|
|
682
|
+
"",
|
|
683
|
+
"Pages from prior memorize ticks. Treat as advisory context \u2014 confirm against the codebase before acting.",
|
|
684
|
+
""
|
|
685
|
+
];
|
|
686
|
+
let total = 0;
|
|
687
|
+
for (const p of pages) {
|
|
688
|
+
const block = [`## ${p.title} \u2014 \`${p.relPath}\``, "", p.content].join("\n");
|
|
689
|
+
if (total + block.length > TOTAL_MAX_BYTES) {
|
|
690
|
+
lines.push("_\u2026 (further pages truncated to fit budget)_");
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
lines.push(block);
|
|
694
|
+
lines.push("");
|
|
695
|
+
total += block.length;
|
|
696
|
+
}
|
|
697
|
+
return lines.join("\n");
|
|
698
|
+
}
|
|
699
|
+
function walkMd(root, visit) {
|
|
700
|
+
const stack = [root];
|
|
701
|
+
while (stack.length > 0) {
|
|
702
|
+
const dir = stack.pop();
|
|
703
|
+
let names;
|
|
704
|
+
try {
|
|
705
|
+
names = fs27.readdirSync(dir);
|
|
706
|
+
} catch {
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
for (const name of names) {
|
|
710
|
+
if (name.startsWith(".")) continue;
|
|
711
|
+
const full = path26.join(dir, name);
|
|
712
|
+
let stat;
|
|
713
|
+
try {
|
|
714
|
+
stat = fs27.statSync(full);
|
|
715
|
+
} catch {
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
if (stat.isDirectory()) {
|
|
719
|
+
stack.push(full);
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
if (stat.isFile() && full.endsWith(".md")) visit(full);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
var MEMORY_DIR_RELATIVE, MAX_PAGES, PER_PAGE_MAX_BYTES, TOTAL_MAX_BYTES, TRUNCATED_SUFFIX, loadMemoryContext;
|
|
727
|
+
var init_loadMemoryContext = __esm({
|
|
728
|
+
"src/scripts/loadMemoryContext.ts"() {
|
|
729
|
+
"use strict";
|
|
730
|
+
MEMORY_DIR_RELATIVE = ".kody/memory";
|
|
731
|
+
MAX_PAGES = 8;
|
|
732
|
+
PER_PAGE_MAX_BYTES = 4e3;
|
|
733
|
+
TOTAL_MAX_BYTES = 24e3;
|
|
734
|
+
TRUNCATED_SUFFIX = "\n\n\u2026 (truncated)";
|
|
735
|
+
loadMemoryContext = async (ctx) => {
|
|
736
|
+
if (typeof ctx.data.memoryContext === "string") return;
|
|
737
|
+
const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
738
|
+
if (!fs27.existsSync(memoryAbs)) {
|
|
739
|
+
ctx.data.memoryContext = "";
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
let pages = [];
|
|
743
|
+
try {
|
|
744
|
+
pages = collectPages(memoryAbs);
|
|
745
|
+
} catch {
|
|
746
|
+
ctx.data.memoryContext = "";
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
if (pages.length === 0) {
|
|
750
|
+
ctx.data.memoryContext = "";
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
const queryTerms = extractQueryTerms(ctx);
|
|
754
|
+
const ranked = queryTerms.length > 0 ? scorePages(pages, queryTerms) : sortByRecency(pages);
|
|
755
|
+
const top = ranked.slice(0, MAX_PAGES);
|
|
756
|
+
ctx.data.memoryContext = formatBlock(top);
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
// src/scripts/loadPriorArt.ts
|
|
762
|
+
var loadPriorArt_exports = {};
|
|
763
|
+
__export(loadPriorArt_exports, {
|
|
764
|
+
loadPriorArt: () => loadPriorArt
|
|
765
|
+
});
|
|
766
|
+
function parsePrNumbers(raw) {
|
|
767
|
+
if (!raw) return [];
|
|
768
|
+
const trimmed = raw.trim();
|
|
769
|
+
if (!trimmed) return [];
|
|
770
|
+
try {
|
|
771
|
+
const parsed = JSON.parse(trimmed);
|
|
772
|
+
if (!Array.isArray(parsed)) return [];
|
|
773
|
+
return parsed.filter((n) => typeof n === "number" && Number.isInteger(n) && n > 0);
|
|
774
|
+
} catch {
|
|
775
|
+
return [];
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function fetchPrBlock(prNumber, cwd) {
|
|
779
|
+
try {
|
|
780
|
+
const metaRaw = gh(["pr", "view", String(prNumber), "--json", "title,state,url,mergedAt,closedAt"], { cwd });
|
|
781
|
+
const meta = JSON.parse(metaRaw);
|
|
782
|
+
const diff = truncate3(safeGh(["pr", "diff", String(prNumber)], cwd), PER_PR_DIFF_MAX_BYTES);
|
|
783
|
+
const commentsRaw = safeGh(["pr", "view", String(prNumber), "--json", "comments,reviews"], cwd);
|
|
784
|
+
const commentsBlock = formatReviewComments(commentsRaw);
|
|
785
|
+
const lines = [
|
|
786
|
+
`## Prior art: PR #${prNumber} \u2014 ${meta.title ?? "(no title)"} [${meta.state ?? "unknown"}]`,
|
|
787
|
+
meta.url ? meta.url : "",
|
|
788
|
+
"",
|
|
789
|
+
"### Diff",
|
|
790
|
+
"```diff",
|
|
791
|
+
diff || "(empty)",
|
|
792
|
+
"```"
|
|
793
|
+
];
|
|
794
|
+
if (commentsBlock) {
|
|
795
|
+
lines.push("");
|
|
796
|
+
lines.push("### Review comments");
|
|
797
|
+
lines.push(commentsBlock);
|
|
798
|
+
}
|
|
799
|
+
return lines.filter((l) => l !== "").join("\n");
|
|
800
|
+
} catch (err) {
|
|
801
|
+
return `## Prior art: PR #${prNumber}
|
|
802
|
+
_Could not fetch \u2014 ${err instanceof Error ? err.message : String(err)}_`;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
function safeGh(args, cwd) {
|
|
806
|
+
try {
|
|
807
|
+
return gh(args, { cwd });
|
|
808
|
+
} catch {
|
|
809
|
+
return "";
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
function truncate3(s, max) {
|
|
813
|
+
return s.length <= max ? s : s.slice(0, max) + TRUNCATED_SUFFIX2;
|
|
814
|
+
}
|
|
815
|
+
function formatReviewComments(raw) {
|
|
816
|
+
if (!raw) return "";
|
|
817
|
+
try {
|
|
818
|
+
const parsed = JSON.parse(raw);
|
|
819
|
+
const out = [];
|
|
820
|
+
for (const c of parsed.comments ?? []) {
|
|
821
|
+
if (!c.body) continue;
|
|
822
|
+
out.push(`- **${c.author?.login ?? "unknown"}**: ${c.body.replace(/\n/g, " ").slice(0, 500)}`);
|
|
823
|
+
}
|
|
824
|
+
for (const r of parsed.reviews ?? []) {
|
|
825
|
+
if (!r.body && !r.state) continue;
|
|
826
|
+
const state = r.state ? ` (${r.state})` : "";
|
|
827
|
+
const body = r.body ? `: ${r.body.replace(/\n/g, " ").slice(0, 500)}` : "";
|
|
828
|
+
out.push(`- **${r.author?.login ?? "unknown"}**${state}${body}`);
|
|
829
|
+
}
|
|
830
|
+
return out.join("\n");
|
|
831
|
+
} catch {
|
|
832
|
+
return "";
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
var PER_PR_DIFF_MAX_BYTES, TOTAL_MAX_BYTES2, TRUNCATED_SUFFIX2, loadPriorArt;
|
|
836
|
+
var init_loadPriorArt = __esm({
|
|
837
|
+
"src/scripts/loadPriorArt.ts"() {
|
|
838
|
+
"use strict";
|
|
839
|
+
init_issue();
|
|
840
|
+
PER_PR_DIFF_MAX_BYTES = 8e3;
|
|
841
|
+
TOTAL_MAX_BYTES2 = 3e4;
|
|
842
|
+
TRUNCATED_SUFFIX2 = "\n\n\u2026 (truncated)";
|
|
843
|
+
loadPriorArt = async (ctx, _profile, args) => {
|
|
844
|
+
if (typeof ctx.data.priorArt === "string") return;
|
|
845
|
+
const artifactName = typeof args?.artifactName === "string" ? args.artifactName : "priorArt";
|
|
846
|
+
const state = ctx.data.taskState;
|
|
847
|
+
const artifact = state?.artifacts?.[artifactName];
|
|
848
|
+
const prNumbers = parsePrNumbers(artifact?.content);
|
|
849
|
+
if (prNumbers.length === 0) {
|
|
850
|
+
ctx.data.priorArt = "";
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
const blocks = [];
|
|
854
|
+
for (const n of prNumbers) {
|
|
855
|
+
const block = fetchPrBlock(n, ctx.cwd);
|
|
856
|
+
if (block) blocks.push(block);
|
|
857
|
+
}
|
|
858
|
+
const joined = blocks.join("\n\n---\n\n");
|
|
859
|
+
ctx.data.priorArt = joined.length > TOTAL_MAX_BYTES2 ? joined.slice(0, TOTAL_MAX_BYTES2) + TRUNCATED_SUFFIX2 : joined;
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
|
|
315
864
|
// package.json
|
|
316
865
|
var package_default = {
|
|
317
866
|
name: "@kody-ade/kody-engine",
|
|
318
|
-
version: "0.4.
|
|
867
|
+
version: "0.4.66",
|
|
319
868
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
320
869
|
license: "MIT",
|
|
321
870
|
type: "module",
|
|
@@ -1754,177 +2303,177 @@ function parseCommentArgs(rest, inputs) {
|
|
|
1754
2303
|
const boolHit = inputs.find((s) => s.type === "bool" && s.flag === `--${t}` && args[s.name] === void 0);
|
|
1755
2304
|
if (boolHit) {
|
|
1756
2305
|
args[boolHit.name] = true;
|
|
1757
|
-
continue;
|
|
1758
|
-
}
|
|
1759
|
-
unmatched.push(t);
|
|
1760
|
-
}
|
|
1761
|
-
return { args, leftover: unmatched.join(" ") };
|
|
1762
|
-
}
|
|
1763
|
-
function findInputByFlag(inputs, key) {
|
|
1764
|
-
return inputs.find((s) => s.name === key || s.flag === `--${key}`);
|
|
1765
|
-
}
|
|
1766
|
-
function coerceBare(spec, value) {
|
|
1767
|
-
if (spec.type === "int") {
|
|
1768
|
-
const n = parseInt(value, 10);
|
|
1769
|
-
return Number.isNaN(n) ? value : n;
|
|
1770
|
-
}
|
|
1771
|
-
if (spec.type === "bool") {
|
|
1772
|
-
const v = value.toLowerCase();
|
|
1773
|
-
return v === "true" || v === "1" || v === "yes";
|
|
1774
|
-
}
|
|
1775
|
-
return value;
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
// src/issue.ts
|
|
1779
|
-
import { execFileSync as execFileSync3 } from "child_process";
|
|
1780
|
-
var API_TIMEOUT_MS = 3e4;
|
|
1781
|
-
function ghToken() {
|
|
1782
|
-
return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
|
|
1783
|
-
}
|
|
1784
|
-
function gh(args, options) {
|
|
1785
|
-
const token = ghToken();
|
|
1786
|
-
const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
|
|
1787
|
-
return execFileSync3("gh", args, {
|
|
1788
|
-
encoding: "utf-8",
|
|
1789
|
-
timeout: API_TIMEOUT_MS,
|
|
1790
|
-
cwd: options?.cwd,
|
|
1791
|
-
env,
|
|
1792
|
-
input: options?.input,
|
|
1793
|
-
stdio: options?.input ? ["pipe", "pipe", "pipe"] : ["inherit", "pipe", "pipe"]
|
|
1794
|
-
}).trim();
|
|
1795
|
-
}
|
|
1796
|
-
function getIssue(issueNumber, cwd) {
|
|
1797
|
-
const output = gh(["issue", "view", String(issueNumber), "--json", "number,title,body,comments,labels"], { cwd });
|
|
1798
|
-
const parsed = JSON.parse(output);
|
|
1799
|
-
if (typeof parsed?.title !== "string") {
|
|
1800
|
-
throw new Error(`Issue #${issueNumber}: unexpected response shape`);
|
|
1801
|
-
}
|
|
1802
|
-
return {
|
|
1803
|
-
number: parsed.number ?? issueNumber,
|
|
1804
|
-
title: parsed.title,
|
|
1805
|
-
body: parsed.body ?? "",
|
|
1806
|
-
comments: (parsed.comments ?? []).map((c) => ({
|
|
1807
|
-
body: c.body ?? "",
|
|
1808
|
-
author: c.author?.login ?? "unknown",
|
|
1809
|
-
createdAt: c.createdAt ?? ""
|
|
1810
|
-
})),
|
|
1811
|
-
labels: Array.isArray(parsed.labels) ? parsed.labels.map((l) => l.name ?? "").filter((n) => n.length > 0) : []
|
|
1812
|
-
};
|
|
1813
|
-
}
|
|
1814
|
-
function stripKodyMentions(body) {
|
|
1815
|
-
return body.replace(/(@)(kody)/gi, "$1\u200B$2");
|
|
1816
|
-
}
|
|
1817
|
-
function postIssueComment(issueNumber, body, cwd) {
|
|
1818
|
-
try {
|
|
1819
|
-
gh(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
1820
|
-
} catch (err) {
|
|
1821
|
-
process.stderr.write(
|
|
1822
|
-
`[kody] failed to post comment on #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
1823
|
-
`
|
|
1824
|
-
);
|
|
2306
|
+
continue;
|
|
2307
|
+
}
|
|
2308
|
+
unmatched.push(t);
|
|
1825
2309
|
}
|
|
2310
|
+
return { args, leftover: unmatched.join(" ") };
|
|
1826
2311
|
}
|
|
1827
|
-
function
|
|
1828
|
-
|
|
1829
|
-
return `${s.slice(0, maxBytes)}\u2026 (+${s.length - maxBytes} chars)`;
|
|
2312
|
+
function findInputByFlag(inputs, key) {
|
|
2313
|
+
return inputs.find((s) => s.name === key || s.flag === `--${key}`);
|
|
1830
2314
|
}
|
|
1831
|
-
function
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
2315
|
+
function coerceBare(spec, value) {
|
|
2316
|
+
if (spec.type === "int") {
|
|
2317
|
+
const n = parseInt(value, 10);
|
|
2318
|
+
return Number.isNaN(n) ? value : n;
|
|
2319
|
+
}
|
|
2320
|
+
if (spec.type === "bool") {
|
|
2321
|
+
const v = value.toLowerCase();
|
|
2322
|
+
return v === "true" || v === "1" || v === "yes";
|
|
2323
|
+
}
|
|
2324
|
+
return value;
|
|
1836
2325
|
}
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
2326
|
+
|
|
2327
|
+
// src/kody-cli.ts
|
|
2328
|
+
init_issue();
|
|
2329
|
+
|
|
2330
|
+
// src/executor.ts
|
|
2331
|
+
import { execFileSync as execFileSync29, spawn as spawn5 } from "child_process";
|
|
2332
|
+
import * as fs31 from "fs";
|
|
2333
|
+
import * as path29 from "path";
|
|
2334
|
+
init_events();
|
|
2335
|
+
|
|
2336
|
+
// src/lifecycleLabels.ts
|
|
2337
|
+
init_issue();
|
|
2338
|
+
|
|
2339
|
+
// src/profile.ts
|
|
2340
|
+
import * as fs9 from "fs";
|
|
2341
|
+
import * as path8 from "path";
|
|
2342
|
+
|
|
2343
|
+
// src/profile-error.ts
|
|
2344
|
+
var ProfileError = class extends Error {
|
|
2345
|
+
constructor(profilePath, message) {
|
|
2346
|
+
super(`Invalid profile at ${profilePath}:
|
|
2347
|
+
${message}`);
|
|
2348
|
+
this.profilePath = profilePath;
|
|
2349
|
+
this.name = "ProfileError";
|
|
1844
2350
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
2351
|
+
profilePath;
|
|
2352
|
+
};
|
|
2353
|
+
|
|
2354
|
+
// src/lifecycles/prBranch.ts
|
|
2355
|
+
var VALID_CONTEXTS = /* @__PURE__ */ new Set(["task", "ci-fix", "minimal"]);
|
|
2356
|
+
var CONTEXT_BUNDLES = {
|
|
2357
|
+
task: ["loadTaskState", "loadConventions", "loadPriorArt", "loadMemoryContext", "loadCoverageRules"],
|
|
2358
|
+
"ci-fix": ["loadTaskState", "loadConventions", "loadCoverageRules"],
|
|
2359
|
+
minimal: []
|
|
2360
|
+
};
|
|
2361
|
+
function prBranchLifecycle(profile, profilePath) {
|
|
2362
|
+
const cfg = validateConfig(profile.lifecycleConfig, profilePath);
|
|
2363
|
+
const before = [];
|
|
2364
|
+
if (cfg.sync) before.push({ script: "syncFlow" });
|
|
2365
|
+
before.push({
|
|
2366
|
+
script: "setLifecycleLabel",
|
|
2367
|
+
with: {
|
|
2368
|
+
label: cfg.label.name,
|
|
2369
|
+
color: cfg.label.color,
|
|
2370
|
+
description: cfg.label.description
|
|
2371
|
+
}
|
|
2372
|
+
});
|
|
2373
|
+
const contextBundle = buildContextBundle(cfg.context, cfg.contextExtras);
|
|
2374
|
+
const afterPreflight = cfg.context === "minimal" && cfg.contextExtras.length === 0 ? [{ script: "composePrompt" }] : [...contextBundle, { script: "composePrompt" }];
|
|
2375
|
+
profile.scripts.preflight = [...before, ...profile.scripts.preflight, ...afterPreflight];
|
|
2376
|
+
const beforePostflight = [{ script: "parseAgentResult" }];
|
|
2377
|
+
const verifyChain = cfg.verify ? [{ script: "verify" }, { script: "checkCoverageWithRetry" }, { script: "abortUnfinishedGitOps" }] : [];
|
|
2378
|
+
const tail = [
|
|
2379
|
+
...verifyChain,
|
|
2380
|
+
{ script: "commitAndPush" },
|
|
2381
|
+
{ script: "ensurePr" },
|
|
2382
|
+
{ script: "postIssueComment" },
|
|
2383
|
+
{ script: "writeRunSummary" },
|
|
2384
|
+
{ script: "saveTaskState" }
|
|
2385
|
+
];
|
|
2386
|
+
if (cfg.mirrorState) tail.push({ script: "mirrorStateToPr" });
|
|
2387
|
+
if (cfg.advance) tail.push({ script: "advanceFlow" });
|
|
2388
|
+
profile.scripts.postflight = [...beforePostflight, ...profile.scripts.postflight, ...tail];
|
|
1853
2389
|
}
|
|
1854
|
-
function
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
)
|
|
1862
|
-
|
|
2390
|
+
function buildContextBundle(context, extras) {
|
|
2391
|
+
const base = CONTEXT_BUNDLES[context] ?? [];
|
|
2392
|
+
if (base.length === 0 && extras.length === 0) return [];
|
|
2393
|
+
const out = [];
|
|
2394
|
+
let extrasInserted = false;
|
|
2395
|
+
for (const name of base) {
|
|
2396
|
+
out.push({ script: name });
|
|
2397
|
+
if (name === "loadTaskState" && extras.length > 0) {
|
|
2398
|
+
for (const e of extras) out.push({ script: e });
|
|
2399
|
+
extrasInserted = true;
|
|
2400
|
+
}
|
|
1863
2401
|
}
|
|
2402
|
+
if (!extrasInserted && extras.length > 0) {
|
|
2403
|
+
out.unshift(...extras.map((e) => ({ script: e })));
|
|
2404
|
+
}
|
|
2405
|
+
return out;
|
|
1864
2406
|
}
|
|
1865
|
-
function
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
})
|
|
2407
|
+
function validateConfig(raw, profilePath) {
|
|
2408
|
+
if (!raw) {
|
|
2409
|
+
throw new ProfileError(profilePath, `lifecycle "pr-branch" requires "lifecycleConfig" with a "label" object`);
|
|
2410
|
+
}
|
|
2411
|
+
const label = raw.label;
|
|
2412
|
+
if (!label || typeof label !== "object" || Array.isArray(label)) {
|
|
2413
|
+
throw new ProfileError(profilePath, `lifecycle "pr-branch": lifecycleConfig.label must be an object`);
|
|
2414
|
+
}
|
|
2415
|
+
const lbl = label;
|
|
2416
|
+
for (const k of ["name", "color", "description"]) {
|
|
2417
|
+
if (typeof lbl[k] !== "string" || lbl[k].length === 0) {
|
|
2418
|
+
throw new ProfileError(profilePath, `lifecycle "pr-branch": lifecycleConfig.label.${k} must be a non-empty string`);
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
const context = raw.context === void 0 ? "task" : raw.context;
|
|
2422
|
+
if (typeof context !== "string" || !VALID_CONTEXTS.has(context)) {
|
|
2423
|
+
throw new ProfileError(
|
|
2424
|
+
profilePath,
|
|
2425
|
+
`lifecycle "pr-branch": lifecycleConfig.context must be one of: ${[...VALID_CONTEXTS].join(" | ")}`
|
|
1877
2426
|
);
|
|
1878
|
-
} catch {
|
|
1879
|
-
return [];
|
|
1880
2427
|
}
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
createdAt: c.createdAt ?? ""
|
|
1891
|
-
})).filter((c) => c.body.trim().length > 0);
|
|
1892
|
-
} catch {
|
|
1893
|
-
return [];
|
|
2428
|
+
let contextExtras = [];
|
|
2429
|
+
if (raw.contextExtras !== void 0) {
|
|
2430
|
+
if (!Array.isArray(raw.contextExtras) || raw.contextExtras.some((s) => typeof s !== "string" || !s)) {
|
|
2431
|
+
throw new ProfileError(
|
|
2432
|
+
profilePath,
|
|
2433
|
+
`lifecycle "pr-branch": lifecycleConfig.contextExtras must be an array of non-empty strings`
|
|
2434
|
+
);
|
|
2435
|
+
}
|
|
2436
|
+
contextExtras = raw.contextExtras;
|
|
1894
2437
|
}
|
|
2438
|
+
return {
|
|
2439
|
+
label: {
|
|
2440
|
+
name: lbl.name,
|
|
2441
|
+
color: lbl.color,
|
|
2442
|
+
description: lbl.description
|
|
2443
|
+
},
|
|
2444
|
+
context,
|
|
2445
|
+
contextExtras,
|
|
2446
|
+
sync: parseBool(raw, profilePath, "sync", true),
|
|
2447
|
+
verify: parseBool(raw, profilePath, "verify", true),
|
|
2448
|
+
advance: parseBool(raw, profilePath, "advance", true),
|
|
2449
|
+
mirrorState: parseBool(raw, profilePath, "mirrorState", false)
|
|
2450
|
+
};
|
|
1895
2451
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
const comments = getPrComments(prNumber, cwd).filter((c) => isReviewShaped(c.body)).map((c) => ({ body: c.body, at: c.createdAt }));
|
|
1903
|
-
const all = [...reviews, ...comments].sort((a, b) => (b.at || "").localeCompare(a.at || ""));
|
|
1904
|
-
if (all.length > 0) return all[0].body;
|
|
1905
|
-
const pr = getPr(prNumber, cwd);
|
|
1906
|
-
return pr.body;
|
|
2452
|
+
function parseBool(raw, profilePath, key, def) {
|
|
2453
|
+
if (raw[key] === void 0) return def;
|
|
2454
|
+
if (typeof raw[key] !== "boolean") {
|
|
2455
|
+
throw new ProfileError(profilePath, `lifecycle "pr-branch": lifecycleConfig.${key} must be a boolean`);
|
|
2456
|
+
}
|
|
2457
|
+
return raw[key];
|
|
1907
2458
|
}
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
2459
|
+
|
|
2460
|
+
// src/lifecycles/index.ts
|
|
2461
|
+
var REGISTRY = {
|
|
2462
|
+
"pr-branch": prBranchLifecycle
|
|
2463
|
+
};
|
|
2464
|
+
function applyLifecycle(profile, profilePath) {
|
|
2465
|
+
if (!profile.lifecycle) return;
|
|
2466
|
+
const expander = REGISTRY[profile.lifecycle];
|
|
2467
|
+
if (!expander) {
|
|
2468
|
+
throw new ProfileError(
|
|
2469
|
+
profilePath,
|
|
2470
|
+
`unknown "lifecycle": "${profile.lifecycle}". Registered: ${Object.keys(REGISTRY).sort().join(", ")}`
|
|
1915
2471
|
);
|
|
1916
2472
|
}
|
|
2473
|
+
expander(profile, profilePath);
|
|
1917
2474
|
}
|
|
1918
2475
|
|
|
1919
|
-
// src/executor.ts
|
|
1920
|
-
import { execFileSync as execFileSync29, spawn as spawn5 } from "child_process";
|
|
1921
|
-
import * as fs31 from "fs";
|
|
1922
|
-
import * as path29 from "path";
|
|
1923
|
-
init_events();
|
|
1924
|
-
|
|
1925
2476
|
// src/profile.ts
|
|
1926
|
-
import * as fs9 from "fs";
|
|
1927
|
-
import * as path8 from "path";
|
|
1928
2477
|
var VALID_INPUT_TYPES = /* @__PURE__ */ new Set(["int", "string", "bool", "enum"]);
|
|
1929
2478
|
var VALID_PERMISSION_MODES = /* @__PURE__ */ new Set(["default", "acceptEdits", "plan", "bypassPermissions"]);
|
|
1930
2479
|
var VALID_ROLES = /* @__PURE__ */ new Set(["primitive", "orchestrator", "container", "watch", "utility"]);
|
|
@@ -1940,6 +2489,8 @@ var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1940
2489
|
"inputs",
|
|
1941
2490
|
"claudeCode",
|
|
1942
2491
|
"cliTools",
|
|
2492
|
+
"lifecycle",
|
|
2493
|
+
"lifecycleConfig",
|
|
1943
2494
|
"scripts",
|
|
1944
2495
|
"outputContract",
|
|
1945
2496
|
"inputArtifacts",
|
|
@@ -1949,17 +2500,9 @@ var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1949
2500
|
"output",
|
|
1950
2501
|
// legacy JSON name for outputArtifacts source
|
|
1951
2502
|
"children",
|
|
1952
|
-
"resetBetweenChildren"
|
|
2503
|
+
"resetBetweenChildren",
|
|
2504
|
+
"preloadContext"
|
|
1953
2505
|
]);
|
|
1954
|
-
var ProfileError = class extends Error {
|
|
1955
|
-
constructor(profilePath, message) {
|
|
1956
|
-
super(`Invalid profile at ${profilePath}:
|
|
1957
|
-
${message}`);
|
|
1958
|
-
this.profilePath = profilePath;
|
|
1959
|
-
this.name = "ProfileError";
|
|
1960
|
-
}
|
|
1961
|
-
profilePath;
|
|
1962
|
-
};
|
|
1963
2506
|
function loadProfile(profilePath) {
|
|
1964
2507
|
if (!fs9.existsSync(profilePath)) {
|
|
1965
2508
|
throw new ProfileError(profilePath, "file not found");
|
|
@@ -1997,6 +2540,23 @@ function loadProfile(profilePath) {
|
|
|
1997
2540
|
phase = r.phase;
|
|
1998
2541
|
}
|
|
1999
2542
|
const children = parseContainerChildren(profilePath, role, r.children);
|
|
2543
|
+
let lifecycle;
|
|
2544
|
+
if (r.lifecycle !== void 0) {
|
|
2545
|
+
if (typeof r.lifecycle !== "string" || r.lifecycle.length === 0) {
|
|
2546
|
+
throw new ProfileError(profilePath, `"lifecycle" must be a non-empty string`);
|
|
2547
|
+
}
|
|
2548
|
+
lifecycle = r.lifecycle;
|
|
2549
|
+
}
|
|
2550
|
+
let lifecycleConfig;
|
|
2551
|
+
if (r.lifecycleConfig !== void 0) {
|
|
2552
|
+
if (!r.lifecycleConfig || typeof r.lifecycleConfig !== "object" || Array.isArray(r.lifecycleConfig)) {
|
|
2553
|
+
throw new ProfileError(profilePath, `"lifecycleConfig" must be an object`);
|
|
2554
|
+
}
|
|
2555
|
+
lifecycleConfig = r.lifecycleConfig;
|
|
2556
|
+
}
|
|
2557
|
+
if (lifecycleConfig && !lifecycle) {
|
|
2558
|
+
throw new ProfileError(profilePath, `"lifecycleConfig" is only meaningful when "lifecycle" is set`);
|
|
2559
|
+
}
|
|
2000
2560
|
const profile = {
|
|
2001
2561
|
name: requireString(profilePath, r, "name"),
|
|
2002
2562
|
describe: typeof r.describe === "string" ? r.describe : "",
|
|
@@ -2007,6 +2567,8 @@ function loadProfile(profilePath) {
|
|
|
2007
2567
|
inputs: parseInputs(profilePath, r.inputs),
|
|
2008
2568
|
claudeCode: parseClaudeCode(profilePath, r.claudeCode),
|
|
2009
2569
|
cliTools: parseCliTools(profilePath, r.cliTools),
|
|
2570
|
+
lifecycle,
|
|
2571
|
+
lifecycleConfig,
|
|
2010
2572
|
scripts: parseScripts(profilePath, r.scripts),
|
|
2011
2573
|
outputContract: r.outputContract,
|
|
2012
2574
|
inputArtifacts: parseInputArtifacts(profilePath, r.input),
|
|
@@ -2016,8 +2578,14 @@ function loadProfile(profilePath) {
|
|
|
2016
2578
|
// container child sees a clean tracked tree (see executor.ts).
|
|
2017
2579
|
// Containers opt out by setting `"resetBetweenChildren": false`.
|
|
2018
2580
|
resetBetweenChildren: typeof r.resetBetweenChildren === "boolean" ? r.resetBetweenChildren : true,
|
|
2581
|
+
// Phase 5 in-process handoff opt-in. Default false; containers
|
|
2582
|
+
// flip to true after end-to-end verification.
|
|
2583
|
+
preloadContext: r.preloadContext === true,
|
|
2019
2584
|
dir: path8.dirname(profilePath)
|
|
2020
2585
|
};
|
|
2586
|
+
if (lifecycle) {
|
|
2587
|
+
applyLifecycle(profile, profilePath);
|
|
2588
|
+
}
|
|
2021
2589
|
return profile;
|
|
2022
2590
|
}
|
|
2023
2591
|
function validateScriptReferences(profile, registeredScripts) {
|
|
@@ -3077,129 +3645,25 @@ function checkCoverage(addedFiles, requirements) {
|
|
|
3077
3645
|
const expected = renderSiblingPath(file, req.requireSibling);
|
|
3078
3646
|
if (!addedSet.has(expected)) {
|
|
3079
3647
|
misses.push({ file, expectedTest: expected });
|
|
3080
|
-
}
|
|
3081
|
-
break;
|
|
3082
|
-
}
|
|
3083
|
-
}
|
|
3084
|
-
return misses;
|
|
3085
|
-
}
|
|
3086
|
-
function formatMissesForFeedback(misses) {
|
|
3087
|
-
if (misses.length === 0) return "";
|
|
3088
|
-
const lines = ["The following files were added without a sibling test file:"];
|
|
3089
|
-
for (const m of misses) lines.push(`- \`${m.file}\` \u2192 expected \`${m.expectedTest}\``);
|
|
3090
|
-
lines.push("");
|
|
3091
|
-
lines.push(
|
|
3092
|
-
"Add the missing test files. Each should cover the new file's public API with at least a happy path and one failure path. Then re-emit DONE / COMMIT_MSG / PR_SUMMARY."
|
|
3093
|
-
);
|
|
3094
|
-
return lines.join("\n");
|
|
3095
|
-
}
|
|
3096
|
-
|
|
3097
|
-
// src/prompt.ts
|
|
3098
|
-
import * as fs13 from "fs";
|
|
3099
|
-
import * as path12 from "path";
|
|
3100
|
-
var CONVENTIONS_PER_FILE_MAX_BYTES = 3e4;
|
|
3101
|
-
var CONVENTION_FILES = ["CLAUDE.md", "AGENTS.md"];
|
|
3102
|
-
function loadProjectConventions(projectDir) {
|
|
3103
|
-
const out = [];
|
|
3104
|
-
for (const rel of CONVENTION_FILES) {
|
|
3105
|
-
const abs = path12.join(projectDir, rel);
|
|
3106
|
-
if (!fs13.existsSync(abs)) continue;
|
|
3107
|
-
let content;
|
|
3108
|
-
try {
|
|
3109
|
-
content = fs13.readFileSync(abs, "utf-8");
|
|
3110
|
-
} catch {
|
|
3111
|
-
continue;
|
|
3112
|
-
}
|
|
3113
|
-
const truncated = content.length > CONVENTIONS_PER_FILE_MAX_BYTES;
|
|
3114
|
-
if (truncated) content = `${content.slice(0, CONVENTIONS_PER_FILE_MAX_BYTES)}
|
|
3115
|
-
|
|
3116
|
-
\u2026 (truncated)`;
|
|
3117
|
-
out.push({ path: rel, content, truncated });
|
|
3118
|
-
}
|
|
3119
|
-
return out;
|
|
3120
|
-
}
|
|
3121
|
-
function parseAgentResult(finalText) {
|
|
3122
|
-
const text = (finalText || "").trim();
|
|
3123
|
-
if (!text)
|
|
3124
|
-
return {
|
|
3125
|
-
done: false,
|
|
3126
|
-
commitMessage: "",
|
|
3127
|
-
prSummary: "",
|
|
3128
|
-
feedbackActions: "",
|
|
3129
|
-
planDeviations: "",
|
|
3130
|
-
priorArt: "",
|
|
3131
|
-
failureReason: "agent produced no final message",
|
|
3132
|
-
markerMissing: false
|
|
3133
|
-
};
|
|
3134
|
-
const MARKDOWN_PREFIX = "[\\s>*_#`~\\-]*";
|
|
3135
|
-
const FAILED_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}FAILED${MARKDOWN_PREFIX}\\s*:\\s*(.+?)\\s*$`, "is");
|
|
3136
|
-
const DONE_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}DONE\\b`, "i");
|
|
3137
|
-
const failedMatch = text.match(FAILED_RE);
|
|
3138
|
-
if (failedMatch) {
|
|
3139
|
-
return {
|
|
3140
|
-
done: false,
|
|
3141
|
-
commitMessage: "",
|
|
3142
|
-
prSummary: "",
|
|
3143
|
-
feedbackActions: "",
|
|
3144
|
-
planDeviations: "",
|
|
3145
|
-
priorArt: "",
|
|
3146
|
-
failureReason: stripMarkdownEmphasis(failedMatch[1]),
|
|
3147
|
-
markerMissing: false
|
|
3148
|
-
};
|
|
3149
|
-
}
|
|
3150
|
-
const hasDoneMarker = DONE_RE.test(text);
|
|
3151
|
-
const hasCommitMsg = /^[\s>*_#`~-]*COMMIT_MSG\s*:/im.test(text);
|
|
3152
|
-
const hasPrSummary = /^[\s>*_#`~-]*PR_SUMMARY\s*:/im.test(text);
|
|
3153
|
-
const markerMissing = !hasDoneMarker && !hasCommitMsg && !hasPrSummary;
|
|
3154
|
-
const commitMatch = text.match(/^[\s>*_#`~-]*COMMIT_MSG[\s>*_#`~-]*\s*:\s*(.+)$/im);
|
|
3155
|
-
const commitMessage = commitMatch ? stripMarkdownEmphasis(commitMatch[1]) : "";
|
|
3156
|
-
const feedbackActions = extractBlock(
|
|
3157
|
-
text,
|
|
3158
|
-
/(?:^|\n)[ \t]*FEEDBACK_ACTIONS\s*:[ \t]*\n/i,
|
|
3159
|
-
/(?:^|\n)[ \t]*(?:PLAN_DEVIATIONS|COMMIT_MSG|PR_SUMMARY|PRIOR_ART)\s*:/i
|
|
3160
|
-
);
|
|
3161
|
-
let planDeviations = extractBlock(
|
|
3162
|
-
text,
|
|
3163
|
-
/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*\n/i,
|
|
3164
|
-
/(?:^|\n)[ \t]*(?:COMMIT_MSG|PR_SUMMARY|FEEDBACK_ACTIONS|PRIOR_ART)\s*:/i
|
|
3165
|
-
);
|
|
3166
|
-
if (!planDeviations) {
|
|
3167
|
-
const inline = text.match(/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
3168
|
-
if (inline) planDeviations = inline[1].trim();
|
|
3169
|
-
}
|
|
3170
|
-
let priorArt = "";
|
|
3171
|
-
const priorArtInline = text.match(/(?:^|\n)[ \t]*PRIOR_ART\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
3172
|
-
if (priorArtInline) priorArt = priorArtInline[1].trim();
|
|
3173
|
-
const summaryStart = text.search(/(^|\n)[ \t]*PR_SUMMARY\s*:[ \t]*\n/i);
|
|
3174
|
-
let prSummary = "";
|
|
3175
|
-
if (summaryStart !== -1) {
|
|
3176
|
-
const afterMarker = text.slice(summaryStart).replace(/^[\s\S]*?PR_SUMMARY\s*:[ \t]*\n/i, "");
|
|
3177
|
-
prSummary = afterMarker.replace(/\n\s*```\s*$/g, "").replace(/```\s*$/g, "").trim();
|
|
3648
|
+
}
|
|
3649
|
+
break;
|
|
3650
|
+
}
|
|
3178
3651
|
}
|
|
3179
|
-
return
|
|
3180
|
-
done: true,
|
|
3181
|
-
commitMessage,
|
|
3182
|
-
prSummary,
|
|
3183
|
-
feedbackActions,
|
|
3184
|
-
planDeviations,
|
|
3185
|
-
priorArt,
|
|
3186
|
-
failureReason: "",
|
|
3187
|
-
markerMissing
|
|
3188
|
-
};
|
|
3189
|
-
}
|
|
3190
|
-
function stripMarkdownEmphasis(s) {
|
|
3191
|
-
return s.trim().replace(/^[*_`~]+|[*_`~]+$/g, "").trim();
|
|
3652
|
+
return misses;
|
|
3192
3653
|
}
|
|
3193
|
-
function
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
const
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3654
|
+
function formatMissesForFeedback(misses) {
|
|
3655
|
+
if (misses.length === 0) return "";
|
|
3656
|
+
const lines = ["The following files were added without a sibling test file:"];
|
|
3657
|
+
for (const m of misses) lines.push(`- \`${m.file}\` \u2192 expected \`${m.expectedTest}\``);
|
|
3658
|
+
lines.push("");
|
|
3659
|
+
lines.push(
|
|
3660
|
+
"Add the missing test files. Each should cover the new file's public API with at least a happy path and one failure path. Then re-emit DONE / COMMIT_MSG / PR_SUMMARY."
|
|
3661
|
+
);
|
|
3662
|
+
return lines.join("\n");
|
|
3200
3663
|
}
|
|
3201
3664
|
|
|
3202
3665
|
// src/scripts/checkCoverageWithRetry.ts
|
|
3666
|
+
init_prompt();
|
|
3203
3667
|
var checkCoverageWithRetry = async (ctx) => {
|
|
3204
3668
|
const reqs = ctx.data.coverageRules ?? [];
|
|
3205
3669
|
if (reqs.length === 0) {
|
|
@@ -3508,11 +3972,13 @@ function formatToolsUsage(profile) {
|
|
|
3508
3972
|
}
|
|
3509
3973
|
|
|
3510
3974
|
// src/scripts/createQaGoal.ts
|
|
3975
|
+
init_issue();
|
|
3511
3976
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
3512
3977
|
import * as fs16 from "fs";
|
|
3513
3978
|
import * as path16 from "path";
|
|
3514
3979
|
|
|
3515
3980
|
// src/scripts/postReviewResult.ts
|
|
3981
|
+
init_issue();
|
|
3516
3982
|
function detectVerdict(body) {
|
|
3517
3983
|
const m = body.match(/##\s*Verdict\s*:\s*(PASS|CONCERNS|FAIL)\b/i);
|
|
3518
3984
|
if (!m) return "UNKNOWN";
|
|
@@ -4051,6 +4517,9 @@ QA_GOAL_TARGETED=(no manifest issue) (id: ${goalId}, verdict: ${verdict})
|
|
|
4051
4517
|
ctx.output.exitCode = verdict === "FAIL" ? 1 : 0;
|
|
4052
4518
|
};
|
|
4053
4519
|
|
|
4520
|
+
// src/goal/operations.ts
|
|
4521
|
+
init_issue();
|
|
4522
|
+
|
|
4054
4523
|
// src/goal/labels.ts
|
|
4055
4524
|
function goalLabel(goalId) {
|
|
4056
4525
|
return `goal:${goalId}`;
|
|
@@ -4955,7 +5424,11 @@ function stripQuotes(value) {
|
|
|
4955
5424
|
return value;
|
|
4956
5425
|
}
|
|
4957
5426
|
|
|
5427
|
+
// src/scripts/jobState/contentsApiBackend.ts
|
|
5428
|
+
init_issue();
|
|
5429
|
+
|
|
4958
5430
|
// src/scripts/issueStateComment.ts
|
|
5431
|
+
init_issue();
|
|
4959
5432
|
function isStateEnvelope(x) {
|
|
4960
5433
|
if (x === null || typeof x !== "object") return false;
|
|
4961
5434
|
const o = x;
|
|
@@ -5419,6 +5892,7 @@ function listJobSlugs(absDir) {
|
|
|
5419
5892
|
}
|
|
5420
5893
|
|
|
5421
5894
|
// src/scripts/dispatchJobTicks.ts
|
|
5895
|
+
init_issue();
|
|
5422
5896
|
var dispatchJobTicks = async (ctx, _profile, args) => {
|
|
5423
5897
|
ctx.skipAgent = true;
|
|
5424
5898
|
const label = String(args?.label ?? "");
|
|
@@ -5506,6 +5980,7 @@ var dispatchNextTask = async (ctx) => {
|
|
|
5506
5980
|
};
|
|
5507
5981
|
|
|
5508
5982
|
// src/pr.ts
|
|
5983
|
+
init_issue();
|
|
5509
5984
|
function prMergeStatus(prNumber, cwd) {
|
|
5510
5985
|
try {
|
|
5511
5986
|
const out = gh(
|
|
@@ -5852,6 +6327,7 @@ var finalizeGoal = async (ctx) => {
|
|
|
5852
6327
|
};
|
|
5853
6328
|
|
|
5854
6329
|
// src/scripts/finishFlow.ts
|
|
6330
|
+
init_issue();
|
|
5855
6331
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
5856
6332
|
var TERMINAL_PHASE = {
|
|
5857
6333
|
"review-passed": { phase: "shipped", status: "succeeded" },
|
|
@@ -6140,6 +6616,9 @@ function sleepMs(ms) {
|
|
|
6140
6616
|
}
|
|
6141
6617
|
}
|
|
6142
6618
|
|
|
6619
|
+
// src/scripts/fixCiFlow.ts
|
|
6620
|
+
init_issue();
|
|
6621
|
+
|
|
6143
6622
|
// src/workflow.ts
|
|
6144
6623
|
import { execFileSync as execFileSync17 } from "child_process";
|
|
6145
6624
|
var GH_TIMEOUT_MS = 3e4;
|
|
@@ -6293,6 +6772,7 @@ function tryPostPr(prNumber, body, cwd) {
|
|
|
6293
6772
|
}
|
|
6294
6773
|
|
|
6295
6774
|
// src/scripts/fixFlow.ts
|
|
6775
|
+
init_issue();
|
|
6296
6776
|
var fixFlow = async (ctx) => {
|
|
6297
6777
|
const prNumber = ctx.args.pr;
|
|
6298
6778
|
const pr = getPr(prNumber, ctx.cwd);
|
|
@@ -6659,22 +7139,9 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
6659
7139
|
ctx.output.exitCode = 0;
|
|
6660
7140
|
};
|
|
6661
7141
|
|
|
6662
|
-
// src/scripts/
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
const conventions = loadProjectConventions(ctx.cwd);
|
|
6666
|
-
ctx.data.conventions = conventions;
|
|
6667
|
-
if (conventions.length > 0) {
|
|
6668
|
-
process.stderr.write(`[kody] loaded conventions: ${conventions.map((c) => c.path).join(", ")}
|
|
6669
|
-
`);
|
|
6670
|
-
}
|
|
6671
|
-
};
|
|
6672
|
-
|
|
6673
|
-
// src/scripts/loadCoverageRules.ts
|
|
6674
|
-
var loadCoverageRules = async (ctx) => {
|
|
6675
|
-
if (Array.isArray(ctx.data.coverageRules)) return;
|
|
6676
|
-
ctx.data.coverageRules = ctx.config.testRequirements ?? [];
|
|
6677
|
-
};
|
|
7142
|
+
// src/scripts/index.ts
|
|
7143
|
+
init_loadConventions();
|
|
7144
|
+
init_loadCoverageRules();
|
|
6678
7145
|
|
|
6679
7146
|
// src/goal/state.ts
|
|
6680
7147
|
import * as fs25 from "fs";
|
|
@@ -6791,6 +7258,7 @@ var loadGoalState = async (ctx) => {
|
|
|
6791
7258
|
};
|
|
6792
7259
|
|
|
6793
7260
|
// src/scripts/loadIssueContext.ts
|
|
7261
|
+
init_issue();
|
|
6794
7262
|
var DEFAULT_COMMENT_LIMIT = 12;
|
|
6795
7263
|
var DEFAULT_COMMENT_MAX_BYTES = 16e3;
|
|
6796
7264
|
var loadIssueContext = async (ctx) => {
|
|
@@ -6820,6 +7288,7 @@ var loadIssueContext = async (ctx) => {
|
|
|
6820
7288
|
};
|
|
6821
7289
|
|
|
6822
7290
|
// src/scripts/loadIssueStateComment.ts
|
|
7291
|
+
init_issue();
|
|
6823
7292
|
var loadIssueStateComment = async (ctx, _profile, args) => {
|
|
6824
7293
|
const marker = String(args?.marker ?? "");
|
|
6825
7294
|
if (!marker) {
|
|
@@ -6890,237 +7359,9 @@ function humanizeSlug(slug) {
|
|
|
6890
7359
|
return slug.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
|
|
6891
7360
|
}
|
|
6892
7361
|
|
|
6893
|
-
// src/scripts/
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
var MEMORY_DIR_RELATIVE = ".kody/memory";
|
|
6897
|
-
var MAX_PAGES = 8;
|
|
6898
|
-
var PER_PAGE_MAX_BYTES = 4e3;
|
|
6899
|
-
var TOTAL_MAX_BYTES = 24e3;
|
|
6900
|
-
var TRUNCATED_SUFFIX = "\n\n\u2026 (truncated)";
|
|
6901
|
-
var loadMemoryContext = async (ctx) => {
|
|
6902
|
-
if (typeof ctx.data.memoryContext === "string") return;
|
|
6903
|
-
const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
6904
|
-
if (!fs27.existsSync(memoryAbs)) {
|
|
6905
|
-
ctx.data.memoryContext = "";
|
|
6906
|
-
return;
|
|
6907
|
-
}
|
|
6908
|
-
let pages = [];
|
|
6909
|
-
try {
|
|
6910
|
-
pages = collectPages(memoryAbs);
|
|
6911
|
-
} catch {
|
|
6912
|
-
ctx.data.memoryContext = "";
|
|
6913
|
-
return;
|
|
6914
|
-
}
|
|
6915
|
-
if (pages.length === 0) {
|
|
6916
|
-
ctx.data.memoryContext = "";
|
|
6917
|
-
return;
|
|
6918
|
-
}
|
|
6919
|
-
const queryTerms = extractQueryTerms(ctx);
|
|
6920
|
-
const ranked = queryTerms.length > 0 ? scorePages(pages, queryTerms) : sortByRecency(pages);
|
|
6921
|
-
const top = ranked.slice(0, MAX_PAGES);
|
|
6922
|
-
ctx.data.memoryContext = formatBlock(top);
|
|
6923
|
-
};
|
|
6924
|
-
function collectPages(memoryAbs) {
|
|
6925
|
-
const out = [];
|
|
6926
|
-
walkMd(memoryAbs, (file) => {
|
|
6927
|
-
let stat;
|
|
6928
|
-
try {
|
|
6929
|
-
stat = fs27.statSync(file);
|
|
6930
|
-
} catch {
|
|
6931
|
-
return;
|
|
6932
|
-
}
|
|
6933
|
-
let raw;
|
|
6934
|
-
try {
|
|
6935
|
-
raw = fs27.readFileSync(file, "utf-8");
|
|
6936
|
-
} catch {
|
|
6937
|
-
return;
|
|
6938
|
-
}
|
|
6939
|
-
const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
6940
|
-
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path26.basename(file, ".md");
|
|
6941
|
-
const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
|
|
6942
|
-
out.push({
|
|
6943
|
-
relPath: path26.relative(memoryAbs, file),
|
|
6944
|
-
title,
|
|
6945
|
-
updated,
|
|
6946
|
-
content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX : raw,
|
|
6947
|
-
mtime: stat.mtimeMs
|
|
6948
|
-
});
|
|
6949
|
-
});
|
|
6950
|
-
return out;
|
|
6951
|
-
}
|
|
6952
|
-
function extractQueryTerms(ctx) {
|
|
6953
|
-
const terms = [];
|
|
6954
|
-
const issue = ctx.data.issue;
|
|
6955
|
-
const pr = ctx.data.pr;
|
|
6956
|
-
if (issue?.title) terms.push(...tokenize(issue.title));
|
|
6957
|
-
if (pr?.title) terms.push(...tokenize(pr.title));
|
|
6958
|
-
return Array.from(new Set(terms)).slice(0, 20);
|
|
6959
|
-
}
|
|
6960
|
-
function tokenize(s) {
|
|
6961
|
-
return s.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((t) => t.length >= 3);
|
|
6962
|
-
}
|
|
6963
|
-
function scorePages(pages, terms) {
|
|
6964
|
-
return pages.map((p) => {
|
|
6965
|
-
const haystack = `${p.title} ${p.content}`.toLowerCase();
|
|
6966
|
-
let score = 0;
|
|
6967
|
-
for (const t of terms) {
|
|
6968
|
-
if (haystack.includes(t)) score++;
|
|
6969
|
-
}
|
|
6970
|
-
return { p, score };
|
|
6971
|
-
}).sort((a, b) => {
|
|
6972
|
-
if (b.score !== a.score) return b.score - a.score;
|
|
6973
|
-
return b.p.mtime - a.p.mtime;
|
|
6974
|
-
}).map((x) => x.p);
|
|
6975
|
-
}
|
|
6976
|
-
function sortByRecency(pages) {
|
|
6977
|
-
return [...pages].sort((a, b) => {
|
|
6978
|
-
if (a.updated && b.updated && a.updated !== b.updated) {
|
|
6979
|
-
return b.updated.localeCompare(a.updated);
|
|
6980
|
-
}
|
|
6981
|
-
return b.mtime - a.mtime;
|
|
6982
|
-
});
|
|
6983
|
-
}
|
|
6984
|
-
function formatBlock(pages) {
|
|
6985
|
-
if (pages.length === 0) return "";
|
|
6986
|
-
const lines = [
|
|
6987
|
-
"# Project memory (`.kody/memory/`)",
|
|
6988
|
-
"",
|
|
6989
|
-
"Pages from prior memorize ticks. Treat as advisory context \u2014 confirm against the codebase before acting.",
|
|
6990
|
-
""
|
|
6991
|
-
];
|
|
6992
|
-
let total = 0;
|
|
6993
|
-
for (const p of pages) {
|
|
6994
|
-
const block = [`## ${p.title} \u2014 \`${p.relPath}\``, "", p.content].join("\n");
|
|
6995
|
-
if (total + block.length > TOTAL_MAX_BYTES) {
|
|
6996
|
-
lines.push("_\u2026 (further pages truncated to fit budget)_");
|
|
6997
|
-
break;
|
|
6998
|
-
}
|
|
6999
|
-
lines.push(block);
|
|
7000
|
-
lines.push("");
|
|
7001
|
-
total += block.length;
|
|
7002
|
-
}
|
|
7003
|
-
return lines.join("\n");
|
|
7004
|
-
}
|
|
7005
|
-
function walkMd(root, visit) {
|
|
7006
|
-
const stack = [root];
|
|
7007
|
-
while (stack.length > 0) {
|
|
7008
|
-
const dir = stack.pop();
|
|
7009
|
-
let names;
|
|
7010
|
-
try {
|
|
7011
|
-
names = fs27.readdirSync(dir);
|
|
7012
|
-
} catch {
|
|
7013
|
-
continue;
|
|
7014
|
-
}
|
|
7015
|
-
for (const name of names) {
|
|
7016
|
-
if (name.startsWith(".")) continue;
|
|
7017
|
-
const full = path26.join(dir, name);
|
|
7018
|
-
let stat;
|
|
7019
|
-
try {
|
|
7020
|
-
stat = fs27.statSync(full);
|
|
7021
|
-
} catch {
|
|
7022
|
-
continue;
|
|
7023
|
-
}
|
|
7024
|
-
if (stat.isDirectory()) {
|
|
7025
|
-
stack.push(full);
|
|
7026
|
-
continue;
|
|
7027
|
-
}
|
|
7028
|
-
if (stat.isFile() && full.endsWith(".md")) visit(full);
|
|
7029
|
-
}
|
|
7030
|
-
}
|
|
7031
|
-
}
|
|
7032
|
-
|
|
7033
|
-
// src/scripts/loadPriorArt.ts
|
|
7034
|
-
var PER_PR_DIFF_MAX_BYTES = 8e3;
|
|
7035
|
-
var TOTAL_MAX_BYTES2 = 3e4;
|
|
7036
|
-
var TRUNCATED_SUFFIX2 = "\n\n\u2026 (truncated)";
|
|
7037
|
-
var loadPriorArt = async (ctx, _profile, args) => {
|
|
7038
|
-
if (typeof ctx.data.priorArt === "string") return;
|
|
7039
|
-
const artifactName = typeof args?.artifactName === "string" ? args.artifactName : "priorArt";
|
|
7040
|
-
const state = ctx.data.taskState;
|
|
7041
|
-
const artifact = state?.artifacts?.[artifactName];
|
|
7042
|
-
const prNumbers = parsePrNumbers(artifact?.content);
|
|
7043
|
-
if (prNumbers.length === 0) {
|
|
7044
|
-
ctx.data.priorArt = "";
|
|
7045
|
-
return;
|
|
7046
|
-
}
|
|
7047
|
-
const blocks = [];
|
|
7048
|
-
for (const n of prNumbers) {
|
|
7049
|
-
const block = fetchPrBlock(n, ctx.cwd);
|
|
7050
|
-
if (block) blocks.push(block);
|
|
7051
|
-
}
|
|
7052
|
-
const joined = blocks.join("\n\n---\n\n");
|
|
7053
|
-
ctx.data.priorArt = joined.length > TOTAL_MAX_BYTES2 ? joined.slice(0, TOTAL_MAX_BYTES2) + TRUNCATED_SUFFIX2 : joined;
|
|
7054
|
-
};
|
|
7055
|
-
function parsePrNumbers(raw) {
|
|
7056
|
-
if (!raw) return [];
|
|
7057
|
-
const trimmed = raw.trim();
|
|
7058
|
-
if (!trimmed) return [];
|
|
7059
|
-
try {
|
|
7060
|
-
const parsed = JSON.parse(trimmed);
|
|
7061
|
-
if (!Array.isArray(parsed)) return [];
|
|
7062
|
-
return parsed.filter((n) => typeof n === "number" && Number.isInteger(n) && n > 0);
|
|
7063
|
-
} catch {
|
|
7064
|
-
return [];
|
|
7065
|
-
}
|
|
7066
|
-
}
|
|
7067
|
-
function fetchPrBlock(prNumber, cwd) {
|
|
7068
|
-
try {
|
|
7069
|
-
const metaRaw = gh(["pr", "view", String(prNumber), "--json", "title,state,url,mergedAt,closedAt"], { cwd });
|
|
7070
|
-
const meta = JSON.parse(metaRaw);
|
|
7071
|
-
const diff = truncate3(safeGh(["pr", "diff", String(prNumber)], cwd), PER_PR_DIFF_MAX_BYTES);
|
|
7072
|
-
const commentsRaw = safeGh(["pr", "view", String(prNumber), "--json", "comments,reviews"], cwd);
|
|
7073
|
-
const commentsBlock = formatReviewComments(commentsRaw);
|
|
7074
|
-
const lines = [
|
|
7075
|
-
`## Prior art: PR #${prNumber} \u2014 ${meta.title ?? "(no title)"} [${meta.state ?? "unknown"}]`,
|
|
7076
|
-
meta.url ? meta.url : "",
|
|
7077
|
-
"",
|
|
7078
|
-
"### Diff",
|
|
7079
|
-
"```diff",
|
|
7080
|
-
diff || "(empty)",
|
|
7081
|
-
"```"
|
|
7082
|
-
];
|
|
7083
|
-
if (commentsBlock) {
|
|
7084
|
-
lines.push("");
|
|
7085
|
-
lines.push("### Review comments");
|
|
7086
|
-
lines.push(commentsBlock);
|
|
7087
|
-
}
|
|
7088
|
-
return lines.filter((l) => l !== "").join("\n");
|
|
7089
|
-
} catch (err) {
|
|
7090
|
-
return `## Prior art: PR #${prNumber}
|
|
7091
|
-
_Could not fetch \u2014 ${err instanceof Error ? err.message : String(err)}_`;
|
|
7092
|
-
}
|
|
7093
|
-
}
|
|
7094
|
-
function safeGh(args, cwd) {
|
|
7095
|
-
try {
|
|
7096
|
-
return gh(args, { cwd });
|
|
7097
|
-
} catch {
|
|
7098
|
-
return "";
|
|
7099
|
-
}
|
|
7100
|
-
}
|
|
7101
|
-
function truncate3(s, max) {
|
|
7102
|
-
return s.length <= max ? s : s.slice(0, max) + TRUNCATED_SUFFIX2;
|
|
7103
|
-
}
|
|
7104
|
-
function formatReviewComments(raw) {
|
|
7105
|
-
if (!raw) return "";
|
|
7106
|
-
try {
|
|
7107
|
-
const parsed = JSON.parse(raw);
|
|
7108
|
-
const out = [];
|
|
7109
|
-
for (const c of parsed.comments ?? []) {
|
|
7110
|
-
if (!c.body) continue;
|
|
7111
|
-
out.push(`- **${c.author?.login ?? "unknown"}**: ${c.body.replace(/\n/g, " ").slice(0, 500)}`);
|
|
7112
|
-
}
|
|
7113
|
-
for (const r of parsed.reviews ?? []) {
|
|
7114
|
-
if (!r.body && !r.state) continue;
|
|
7115
|
-
const state = r.state ? ` (${r.state})` : "";
|
|
7116
|
-
const body = r.body ? `: ${r.body.replace(/\n/g, " ").slice(0, 500)}` : "";
|
|
7117
|
-
out.push(`- **${r.author?.login ?? "unknown"}**${state}${body}`);
|
|
7118
|
-
}
|
|
7119
|
-
return out.join("\n");
|
|
7120
|
-
} catch {
|
|
7121
|
-
return "";
|
|
7122
|
-
}
|
|
7123
|
-
}
|
|
7362
|
+
// src/scripts/index.ts
|
|
7363
|
+
init_loadMemoryContext();
|
|
7364
|
+
init_loadPriorArt();
|
|
7124
7365
|
|
|
7125
7366
|
// src/scripts/loadTaskContext.ts
|
|
7126
7367
|
init_events();
|
|
@@ -7291,6 +7532,7 @@ function parsePrNumber3(prUrl) {
|
|
|
7291
7532
|
}
|
|
7292
7533
|
|
|
7293
7534
|
// src/scripts/notifyTerminal.ts
|
|
7535
|
+
init_issue();
|
|
7294
7536
|
var notifyTerminal = async (ctx, _profile, _agentResult, args) => {
|
|
7295
7537
|
const issueNumber = ctx.args.issue;
|
|
7296
7538
|
if (!issueNumber || issueNumber <= 0) return;
|
|
@@ -7322,6 +7564,7 @@ function composeBody({ label, exit, prUrl, reason, dryRun }) {
|
|
|
7322
7564
|
}
|
|
7323
7565
|
|
|
7324
7566
|
// src/scripts/openQaIssue.ts
|
|
7567
|
+
init_issue();
|
|
7325
7568
|
var QA_LABEL = "kody:qa-report";
|
|
7326
7569
|
function qaAction2(verdict, payload) {
|
|
7327
7570
|
const type = verdict === "PASS" ? "QA_PASS" : verdict === "CONCERNS" ? "QA_CONCERNS" : verdict === "FAIL" ? "QA_FAIL" : "QA_COMPLETED";
|
|
@@ -7423,6 +7666,7 @@ QA_REPORT_POSTED=${created.url} (verdict: ${verdict})
|
|
|
7423
7666
|
};
|
|
7424
7667
|
|
|
7425
7668
|
// src/scripts/parseAgentResult.ts
|
|
7669
|
+
init_prompt();
|
|
7426
7670
|
var parseAgentResult2 = async (ctx, profile, agentResult) => {
|
|
7427
7671
|
if (!agentResult) {
|
|
7428
7672
|
ctx.data.agentDone = false;
|
|
@@ -7665,6 +7909,9 @@ var persistFlowState = async (ctx) => {
|
|
|
7665
7909
|
}
|
|
7666
7910
|
};
|
|
7667
7911
|
|
|
7912
|
+
// src/scripts/postIssueComment.ts
|
|
7913
|
+
init_issue();
|
|
7914
|
+
|
|
7668
7915
|
// src/scripts/prOutcome.ts
|
|
7669
7916
|
function readPrOutcome(data) {
|
|
7670
7917
|
const raw = data.prResult;
|
|
@@ -7800,6 +8047,7 @@ function postWith(type, n, body, cwd) {
|
|
|
7800
8047
|
}
|
|
7801
8048
|
|
|
7802
8049
|
// src/scripts/postPlanComment.ts
|
|
8050
|
+
init_issue();
|
|
7803
8051
|
var postPlanComment = async (ctx) => {
|
|
7804
8052
|
if (!ctx.data.agentDone) return;
|
|
7805
8053
|
const targetType = ctx.data.commentTargetType;
|
|
@@ -7830,6 +8078,7 @@ Comment \`kody run\` (prefixed with \`@\`) to execute this plan.`;
|
|
|
7830
8078
|
}
|
|
7831
8079
|
|
|
7832
8080
|
// src/scripts/postResearchComment.ts
|
|
8081
|
+
init_issue();
|
|
7833
8082
|
var postResearchComment = async (ctx) => {
|
|
7834
8083
|
if (!ctx.data.agentDone) return;
|
|
7835
8084
|
const targetType = ctx.data.commentTargetType;
|
|
@@ -8011,6 +8260,7 @@ var resolveArtifacts = async (ctx, profile) => {
|
|
|
8011
8260
|
|
|
8012
8261
|
// src/scripts/resolveFlow.ts
|
|
8013
8262
|
import { execFileSync as execFileSync21 } from "child_process";
|
|
8263
|
+
init_issue();
|
|
8014
8264
|
var CONFLICT_DIFF_MAX_BYTES = 4e4;
|
|
8015
8265
|
var resolveFlow = async (ctx) => {
|
|
8016
8266
|
const prNumber = ctx.args.pr;
|
|
@@ -8159,6 +8409,7 @@ function pushEmptyCommit(branch, cwd) {
|
|
|
8159
8409
|
}
|
|
8160
8410
|
|
|
8161
8411
|
// src/deployments.ts
|
|
8412
|
+
init_issue();
|
|
8162
8413
|
function findPreviewDeploymentUrl(prNumber, cwd) {
|
|
8163
8414
|
const sha = getPrHeadSha(prNumber, cwd);
|
|
8164
8415
|
if (!sha) return null;
|
|
@@ -8311,6 +8562,7 @@ var resolveQaUrl = async (ctx) => {
|
|
|
8311
8562
|
|
|
8312
8563
|
// src/scripts/revertFlow.ts
|
|
8313
8564
|
import { execFileSync as execFileSync23 } from "child_process";
|
|
8565
|
+
init_issue();
|
|
8314
8566
|
var SHA_RE = /^[0-9a-f]{4,40}$/i;
|
|
8315
8567
|
var revertFlow = async (ctx) => {
|
|
8316
8568
|
const prNumber = ctx.args.pr;
|
|
@@ -8423,6 +8675,7 @@ function tryPostPr4(prNumber, body, cwd) {
|
|
|
8423
8675
|
}
|
|
8424
8676
|
|
|
8425
8677
|
// src/scripts/reviewFlow.ts
|
|
8678
|
+
init_issue();
|
|
8426
8679
|
var reviewFlow = async (ctx) => {
|
|
8427
8680
|
const prNumber = ctx.args.pr;
|
|
8428
8681
|
const pr = getPr(prNumber, ctx.cwd);
|
|
@@ -8450,6 +8703,7 @@ function tryPostPr5(prNumber, body, cwd) {
|
|
|
8450
8703
|
}
|
|
8451
8704
|
|
|
8452
8705
|
// src/scripts/runFlow.ts
|
|
8706
|
+
init_issue();
|
|
8453
8707
|
var runFlow = async (ctx) => {
|
|
8454
8708
|
const issueNumber = ctx.args.issue;
|
|
8455
8709
|
const issue = getIssue(issueNumber, ctx.cwd);
|
|
@@ -8736,6 +8990,7 @@ var stageMergeConflicts = async (ctx) => {
|
|
|
8736
8990
|
};
|
|
8737
8991
|
|
|
8738
8992
|
// src/scripts/startFlow.ts
|
|
8993
|
+
init_issue();
|
|
8739
8994
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
8740
8995
|
var API_TIMEOUT_MS9 = 3e4;
|
|
8741
8996
|
var startFlow = async (ctx, profile, _agentResult, args) => {
|
|
@@ -8785,6 +9040,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
|
|
|
8785
9040
|
|
|
8786
9041
|
// src/scripts/syncFlow.ts
|
|
8787
9042
|
import { execFileSync as execFileSync26 } from "child_process";
|
|
9043
|
+
init_issue();
|
|
8788
9044
|
var syncFlow = async (ctx, _profile, args) => {
|
|
8789
9045
|
const announceOnSuccess = Boolean(args?.announceOnSuccess);
|
|
8790
9046
|
const prNumber = ctx.args.pr;
|
|
@@ -9028,6 +9284,7 @@ function downgrade2(ctx, reason) {
|
|
|
9028
9284
|
}
|
|
9029
9285
|
|
|
9030
9286
|
// src/scripts/waitForCi.ts
|
|
9287
|
+
init_issue();
|
|
9031
9288
|
import { execFileSync as execFileSync27 } from "child_process";
|
|
9032
9289
|
var API_TIMEOUT_MS10 = 3e4;
|
|
9033
9290
|
var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
@@ -10040,6 +10297,32 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
10040
10297
|
const runChild = input.__runChild ?? ((name, opts) => runExecutable(name, opts));
|
|
10041
10298
|
const reader = input.__readTaskState ?? readTaskState;
|
|
10042
10299
|
const issueNumber = ctx.args.issue;
|
|
10300
|
+
let preloadedSnapshot;
|
|
10301
|
+
if (profile.preloadContext) {
|
|
10302
|
+
try {
|
|
10303
|
+
const { loadConventions: loadConventions2 } = await Promise.resolve().then(() => (init_loadConventions(), loadConventions_exports));
|
|
10304
|
+
const { loadPriorArt: loadPriorArt2 } = await Promise.resolve().then(() => (init_loadPriorArt(), loadPriorArt_exports));
|
|
10305
|
+
const { loadMemoryContext: loadMemoryContext2 } = await Promise.resolve().then(() => (init_loadMemoryContext(), loadMemoryContext_exports));
|
|
10306
|
+
const { loadCoverageRules: loadCoverageRules2 } = await Promise.resolve().then(() => (init_loadCoverageRules(), loadCoverageRules_exports));
|
|
10307
|
+
await loadConventions2(ctx, profile);
|
|
10308
|
+
await loadPriorArt2(ctx, profile);
|
|
10309
|
+
await loadMemoryContext2(ctx, profile);
|
|
10310
|
+
await loadCoverageRules2(ctx, profile);
|
|
10311
|
+
preloadedSnapshot = {};
|
|
10312
|
+
for (const k of ["issue", "conventions", "priorArt", "memoryContext", "coverageRules", "taskContext"]) {
|
|
10313
|
+
if (ctx.data[k] !== void 0) preloadedSnapshot[k] = ctx.data[k];
|
|
10314
|
+
}
|
|
10315
|
+
process.stderr.write(
|
|
10316
|
+
`[kody container] preloadContext: snapshot keys=${Object.keys(preloadedSnapshot).join(",")}
|
|
10317
|
+
`
|
|
10318
|
+
);
|
|
10319
|
+
} catch (err) {
|
|
10320
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10321
|
+
process.stderr.write(`[kody container] preloadContext failed (falling back to per-child loads): ${msg}
|
|
10322
|
+
`);
|
|
10323
|
+
preloadedSnapshot = void 0;
|
|
10324
|
+
}
|
|
10325
|
+
}
|
|
10043
10326
|
let currentIdx = 0;
|
|
10044
10327
|
let iteration = 0;
|
|
10045
10328
|
let knownPrUrl;
|
|
@@ -10121,7 +10404,10 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
10121
10404
|
config: input.config,
|
|
10122
10405
|
skipConfig: input.skipConfig,
|
|
10123
10406
|
verbose: input.verbose,
|
|
10124
|
-
quiet: input.quiet
|
|
10407
|
+
quiet: input.quiet,
|
|
10408
|
+
// Phase 5 in-process handoff — undefined when preloadContext
|
|
10409
|
+
// is off, so children fall back to their own loaders.
|
|
10410
|
+
preloadedData: preloadedSnapshot
|
|
10125
10411
|
});
|
|
10126
10412
|
emitEvent(input.cwd, {
|
|
10127
10413
|
executable: profile.name,
|
|
@@ -10287,6 +10573,7 @@ function flattenConfig(obj, prefix = "") {
|
|
|
10287
10573
|
}
|
|
10288
10574
|
|
|
10289
10575
|
// src/kody-cli.ts
|
|
10576
|
+
init_issue();
|
|
10290
10577
|
var CI_HELP = `kody ci \u2014 minimal-YAML autonomous engineer (CI preflight + run)
|
|
10291
10578
|
|
|
10292
10579
|
Usage:
|