@kody-ade/kody-engine 0.4.171 → 0.4.173
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
CHANGED
|
@@ -531,7 +531,22 @@ function getIssue(issueNumber, cwd) {
|
|
|
531
531
|
function stripKodyMentions(body) {
|
|
532
532
|
return body.replace(/(@)(kody)/gi, "$1\u200B$2");
|
|
533
533
|
}
|
|
534
|
+
function detectBotDispatchShape(body) {
|
|
535
|
+
const trimmed = body.replace(/^\s+/, "");
|
|
536
|
+
const m = trimmed.match(/^@kody\s+([a-z][a-z0-9-]*)\b/i);
|
|
537
|
+
return m ? m[1].toLowerCase() : null;
|
|
538
|
+
}
|
|
539
|
+
function isRunningAsBot() {
|
|
540
|
+
if (process.env.GITHUB_ACTIONS !== "true") return false;
|
|
541
|
+
const actor = (process.env.GITHUB_ACTOR ?? "").toLowerCase();
|
|
542
|
+
if (actor.endsWith("[bot]") || actor === "kody-bot" || actor === "kodyade") return true;
|
|
543
|
+
return !!process.env.KODY_APP_ID;
|
|
544
|
+
}
|
|
534
545
|
function postIssueComment(issueNumber, body, cwd) {
|
|
546
|
+
if (isRunningAsBot()) {
|
|
547
|
+
const slug = detectBotDispatchShape(body);
|
|
548
|
+
if (slug) throw new BotDispatchCommentError(slug);
|
|
549
|
+
}
|
|
535
550
|
try {
|
|
536
551
|
gh(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
537
552
|
} catch (err) {
|
|
@@ -629,6 +644,10 @@ function getPrLatestReviewBody(prNumber, cwd) {
|
|
|
629
644
|
return pr.body;
|
|
630
645
|
}
|
|
631
646
|
function postPrReviewComment(prNumber, body, cwd) {
|
|
647
|
+
if (isRunningAsBot()) {
|
|
648
|
+
const slug = detectBotDispatchShape(body);
|
|
649
|
+
if (slug) throw new BotDispatchCommentError(slug);
|
|
650
|
+
}
|
|
632
651
|
try {
|
|
633
652
|
gh(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
634
653
|
} catch (err) {
|
|
@@ -638,11 +657,19 @@ function postPrReviewComment(prNumber, body, cwd) {
|
|
|
638
657
|
);
|
|
639
658
|
}
|
|
640
659
|
}
|
|
641
|
-
var API_TIMEOUT_MS, DEFAULT_COMMENT_LIMIT, DEFAULT_COMMENT_MAX_BYTES, VERDICT_HEADING;
|
|
660
|
+
var API_TIMEOUT_MS, BotDispatchCommentError, DEFAULT_COMMENT_LIMIT, DEFAULT_COMMENT_MAX_BYTES, VERDICT_HEADING;
|
|
642
661
|
var init_issue = __esm({
|
|
643
662
|
"src/issue.ts"() {
|
|
644
663
|
"use strict";
|
|
645
664
|
API_TIMEOUT_MS = 3e4;
|
|
665
|
+
BotDispatchCommentError = class extends Error {
|
|
666
|
+
constructor(slug) {
|
|
667
|
+
super(
|
|
668
|
+
`bot self-dispatch via @kody comments is banned. Refusing to post "@kody ${slug} \u2026" \u2014 use runExecutableChain (same-run) or dispatchExecutable (cross-run) instead. See docs/duty-dispatch.md for the contract.`
|
|
669
|
+
);
|
|
670
|
+
this.name = "BotDispatchCommentError";
|
|
671
|
+
}
|
|
672
|
+
};
|
|
646
673
|
DEFAULT_COMMENT_LIMIT = 12;
|
|
647
674
|
DEFAULT_COMMENT_MAX_BYTES = 16e3;
|
|
648
675
|
VERDICT_HEADING = /(^|\n)\s*#{1,6}\s*Verdict\s*:/i;
|
|
@@ -1061,7 +1088,7 @@ var init_loadPriorArt = __esm({
|
|
|
1061
1088
|
// package.json
|
|
1062
1089
|
var package_default = {
|
|
1063
1090
|
name: "@kody-ade/kody-engine",
|
|
1064
|
-
version: "0.4.
|
|
1091
|
+
version: "0.4.173",
|
|
1065
1092
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
1066
1093
|
license: "MIT",
|
|
1067
1094
|
type: "module",
|
|
@@ -6430,6 +6457,35 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
|
|
|
6430
6457
|
});
|
|
6431
6458
|
}
|
|
6432
6459
|
|
|
6460
|
+
// src/scripts/deriveQaScopeFromIssue.ts
|
|
6461
|
+
init_issue();
|
|
6462
|
+
var TITLE_PATTERN = /^QA(?:\s+\w+)?:\s*(.+?)(?:\s*\(#\d+\))?\s*$/i;
|
|
6463
|
+
var deriveQaScopeFromIssue = async (ctx) => {
|
|
6464
|
+
if (typeof ctx.args.scope === "string" && ctx.args.scope.trim().length > 0) {
|
|
6465
|
+
return;
|
|
6466
|
+
}
|
|
6467
|
+
const issueNumber = Number(ctx.args.issue ?? 0);
|
|
6468
|
+
if (!Number.isFinite(issueNumber) || issueNumber <= 0) return;
|
|
6469
|
+
let title = "";
|
|
6470
|
+
try {
|
|
6471
|
+
const issue = getIssue(issueNumber, ctx.cwd);
|
|
6472
|
+
title = (issue.title ?? "").trim();
|
|
6473
|
+
} catch (err) {
|
|
6474
|
+
process.stderr.write(
|
|
6475
|
+
`[kody] deriveQaScopeFromIssue: could not read #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
6476
|
+
`
|
|
6477
|
+
);
|
|
6478
|
+
return;
|
|
6479
|
+
}
|
|
6480
|
+
if (!title) return;
|
|
6481
|
+
const m = title.match(TITLE_PATTERN);
|
|
6482
|
+
const scope = (m?.[1] ?? title).trim();
|
|
6483
|
+
if (!scope) return;
|
|
6484
|
+
ctx.args.scope = scope;
|
|
6485
|
+
process.stdout.write(`\u2192 qa-engineer: derived scope from tracking issue #${issueNumber} title: "${scope}"
|
|
6486
|
+
`);
|
|
6487
|
+
};
|
|
6488
|
+
|
|
6433
6489
|
// src/scripts/diagMcp.ts
|
|
6434
6490
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
6435
6491
|
import * as fs25 from "fs";
|
|
@@ -9058,7 +9114,7 @@ var loadJobFromFile = async (ctx, _profile, args) => {
|
|
|
9058
9114
|
const loaded = await backend.load(slug);
|
|
9059
9115
|
ctx.data.jobSlug = slug;
|
|
9060
9116
|
ctx.data.jobTitle = title;
|
|
9061
|
-
ctx.data.jobIntent = body;
|
|
9117
|
+
ctx.data.jobIntent = body.replace(/\{\{\s*mentions\s*\}\}/g, mentions);
|
|
9062
9118
|
ctx.data.jobState = loaded;
|
|
9063
9119
|
ctx.data.jobStateJson = JSON.stringify(loaded.state, null, 2);
|
|
9064
9120
|
ctx.data.workerSlug = workerSlug;
|
|
@@ -13101,6 +13157,7 @@ var preflightScripts = {
|
|
|
13101
13157
|
buildSyntheticPlugin,
|
|
13102
13158
|
resolveArtifacts,
|
|
13103
13159
|
discoverQaContext,
|
|
13160
|
+
deriveQaScopeFromIssue,
|
|
13104
13161
|
resolvePreviewUrl,
|
|
13105
13162
|
resolveQaUrl,
|
|
13106
13163
|
promoteQaGoal,
|
|
@@ -10,6 +10,8 @@ The job below assigns you, worker **`{{workerSlug}}`**, as its executor. This pe
|
|
|
10
10
|
|
|
11
11
|
Slug **`{{jobSlug}}`** — *{{jobTitle}}*, assigned to worker **`{{workerSlug}}`**. The job body below is authoritative for *what* to do, *when* (cadence), allowed commands, and state schema. It is human-edited — re-read it every tick. Execute it **as** the persona above.
|
|
12
12
|
|
|
13
|
+
**Addressing the operator.** When the job body tells you to @-mention the operator (e.g. the first line of an inbox recommendation), the exact handle(s) to use are: {{mentions}}. Copy that string **verbatim** — never invent, abbreviate, guess, or retype a GitHub username. A wrong handle silently fails to route to the operator's inbox, so the recommendation is lost. If the line above is blank, the duty declared no operator; post without a mention.
|
|
14
|
+
|
|
13
15
|
### Job body
|
|
14
16
|
|
|
15
17
|
{{jobIntent}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.173",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|