@karajan-family/code 4.55.0 → 4.57.0

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.
@@ -0,0 +1,67 @@
1
+ /**
2
+ * KJC-TSK-1075 (#2227): review someone else's PR. kj's reviewer, the target
3
+ * repo's rules (.karajan) and the provider the agent picks run over
4
+ * base...head; no own-work gate applies (card, tests, policy, session RAG) and
5
+ * no verdict is stored, so this mode never unlocks a commit (ADR 0015). The
6
+ * own-work gate, reviewGateCommand, stays untouched.
7
+ */
8
+ import { runCommand } from "../utils/process.js";
9
+ import { resolveRole } from "../config/role-resolver.js";
10
+ import { runOneShotReview } from "./one-shot-review.js";
11
+ import { prRequirementChecks } from "./pr-requirements.js";
12
+ import { prSecurityChecks } from "./pr-security.js";
13
+ import { sonarCheck } from "./pr-sonar.js";
14
+
15
+ const gitDiffOf = async (projectDir, range) => {
16
+ const res = await runCommand("git", ["diff", range], { cwd: projectDir });
17
+ if (res.exitCode !== 0) throw new Error(`git diff ${range} failed: ${(res.stderr || "").trim()}`);
18
+ return res.stdout;
19
+ };
20
+
21
+ const finding = (i) => ({
22
+ file: i.file ?? null, line: i.line ?? null, severity: i.severity ?? null,
23
+ description: i.description ?? "", suggested_fix: i.suggested_fix ?? null,
24
+ });
25
+
26
+ /** The review as data: verdict, findings, suggestions and the PR-requirement checks. */
27
+ export async function thirdPartyReview({ range, config, projectDir, logger, task = null, gitDiff = gitDiffOf, run = runOneShotReview, requirements = prRequirementChecks, security = prSecurityChecks, sonar = sonarCheck }) {
28
+ const diff = await gitDiff(projectDir, range);
29
+ // KJC-TSK-1076/1077: the PR's requirements and its security, with no tokens; they never stop the review.
30
+ const checks = [...await requirements({ range, projectDir, config }), ...await security({ diff, projectDir, config }), await sonar({ diff, config, projectDir })];
31
+ const record = await run({
32
+ diff, task, config, logger, projectDir,
33
+ reviewerOverride: resolveRole(config, "reviewer").provider || null,
34
+ persist: false,
35
+ });
36
+ return {
37
+ mode: "third-party",
38
+ range,
39
+ reviewer: record.reviewer,
40
+ verdict: { approved: record.verdict === "approved", summary: record.summary ?? "" },
41
+ findings: (record.issues ?? []).map(finding),
42
+ suggestions: record.suggestions ?? [],
43
+ checks,
44
+ };
45
+ }
46
+
47
+ /**
48
+ * The CLI side: stdout carries exactly one JSON document, logs go to stderr.
49
+ * Exit 0 whatever the PR's verdict (the agent decides what to post); non-zero
50
+ * only when kj itself fails.
51
+ */
52
+ export async function thirdPartyReviewCommand({ flags, config, out = process.stdout, err = process.stderr, review = thirdPartyReview }) {
53
+ const print = (doc) => out.write(`${JSON.stringify(doc)}\n`);
54
+ if (!flags.range) {
55
+ print({ error: "--third-party reviews a range: pass --range <base>...<head>" });
56
+ return 1;
57
+ }
58
+ const log = (msg) => err.write(`${msg}\n`);
59
+ const logger = { info: log, warn: log, error: log, debug: () => {} };
60
+ try {
61
+ print(await review({ range: flags.range, config, projectDir: config.projectDir || process.cwd(), logger, task: flags.task ?? null }));
62
+ return 0;
63
+ } catch (e) {
64
+ print({ error: e.message });
65
+ return 1;
66
+ }
67
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * KJC-TSK-1086: the Steward's block (STW-C, KJC-TSK-0791) at commit too. Only
3
+ * where the project adopted it (method_gates.steward: block), only the hard
4
+ * invariants (vulnerable dependencies, a persistently red main), and never on
5
+ * an invariant whose verdict is unknown. Having declared block, a missing or
6
+ * unreadable report blocks too: the sweep has to run.
7
+ */
8
+ import { readFileSync } from "node:fs";
9
+ import { join } from "node:path";
10
+
11
+ const HARD = new Set(["vulnerable-deps", "main-ci"]);
12
+
13
+ /** @returns {{ sweptAt: string, hard: object[], reason: string } | null} */
14
+ export function stewardBlocking({ projectDir, config }) {
15
+ if (config?.method_gates?.steward !== "block") return null;
16
+ const file = join(projectDir, ".karajan", "steward", "report.json");
17
+ let rep;
18
+ try {
19
+ rep = JSON.parse(readFileSync(file, "utf8"));
20
+ } catch (err) {
21
+ // block was adopted explicitly: a missing or unreadable report is never a silent pass.
22
+ return { sweptAt: null, hard: [], reason: `steward cannot read ${file} (${err.message}) — rerun kj steward sweep; while it is unreadable the block stands` };
23
+ }
24
+ if (!Array.isArray(rep?.invariants)) {
25
+ return { sweptAt: rep?.sweptAt ?? null, hard: [], reason: `steward report ${file} has no invariants list — rerun kj steward sweep; while it is malformed the block stands` };
26
+ }
27
+ const hard = rep.invariants.filter((r) => r?.verdict === "broken" && HARD.has(r.id));
28
+ if (hard.length === 0) return null;
29
+ const lines = hard.map((r) => `${r.id}: ${r.evidence || ""} -> ${r.remedy || r.renew || "kj steward sweep"}`);
30
+ return { sweptAt: rep.sweptAt, hard, reason: `steward (sweep ${rep.sweptAt}) blocks: ${lines.join("; ")} — if the work goes on, your user sets method_gates.steward to inform` };
31
+ }
package/src/utils/git.js CHANGED
@@ -307,8 +307,10 @@ export async function hasRemote(cwd = null) {
307
307
  return res.exitCode === 0;
308
308
  }
309
309
 
310
+ // KJC-TSK-1093: no -u, which writes the upstream into .git/config, read-only inside
311
+ // the host sandbox. Nothing in kj reads a feature branch's upstream.
310
312
  export async function pushBranch(branch, cwd = null) {
311
- await runGit(["push", "-u", "origin", branch], cwd ? { cwd } : {});
313
+ await runGit(["push", "origin", branch], cwd ? { cwd } : {});
312
314
  }
313
315
 
314
316
  export async function createPullRequest({ baseBranch, branch, title, body, cwd = null }) {