tianshu-harness 3.23.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.
- package/LICENSE +189 -0
- package/README.en.md +1066 -0
- package/README.ja.md +1214 -0
- package/README.ko.md +1216 -0
- package/README.md +309 -0
- package/completions/rivet.bash +118 -0
- package/completions/rivet.fish +110 -0
- package/completions/rivet.ps1 +230 -0
- package/completions/rivet.zsh +187 -0
- package/dist/account-OAEKORZE.js +47 -0
- package/dist/account-login-V6FOLHJR.js +65 -0
- package/dist/account-status-KHNPPAFL.js +23 -0
- package/dist/agent/worker-process/child.js +407 -0
- package/dist/browser-cli-FLNY5ZHI.js +19 -0
- package/dist/browser-readiness-LWVGSBD5.js +12 -0
- package/dist/build-backends-5KXKR2S4.js +13 -0
- package/dist/build-options-66Y4ZE7C.js +9 -0
- package/dist/bundled-skills/brainstorming/SKILL.md +139 -0
- package/dist/bundled-skills/visual-acceptance/SKILL.md +64 -0
- package/dist/chain-7MAMFXZ3.js +10 -0
- package/dist/checkpoint-MND4DUIX.js +33 -0
- package/dist/chunk-2E6CK2RC.js +392 -0
- package/dist/chunk-2EBWGAXD.js +51 -0
- package/dist/chunk-2HDP7RMR.js +119 -0
- package/dist/chunk-2HKD2UFM.js +1000 -0
- package/dist/chunk-2VYRLULP.js +51 -0
- package/dist/chunk-2XN7PM4N.js +125 -0
- package/dist/chunk-35H7GVNR.js +66 -0
- package/dist/chunk-3C3R7JXY.js +77 -0
- package/dist/chunk-3VGD2FXB.js +118 -0
- package/dist/chunk-424AP7FM.js +534 -0
- package/dist/chunk-4J5TZGOE.js +3707 -0
- package/dist/chunk-4QJ3Y5JM.js +898 -0
- package/dist/chunk-4U2ET7ZY.js +1326 -0
- package/dist/chunk-4XPFLICE.js +876 -0
- package/dist/chunk-5B2OCU5P.js +31707 -0
- package/dist/chunk-5GGOGLSN.js +73 -0
- package/dist/chunk-5JRZPLI6.js +251 -0
- package/dist/chunk-5TQ3JYBU.js +397 -0
- package/dist/chunk-66JPZSGX.js +55 -0
- package/dist/chunk-6HSVXHCZ.js +764 -0
- package/dist/chunk-6S5FPUS7.js +21 -0
- package/dist/chunk-722LQO64.js +131 -0
- package/dist/chunk-73NJ7IT7.js +354 -0
- package/dist/chunk-7FW3I7WC.js +95 -0
- package/dist/chunk-7KUCBNLB.js +173 -0
- package/dist/chunk-7RDOV3DF.js +201 -0
- package/dist/chunk-A5MNH4ER.js +79 -0
- package/dist/chunk-ADIVZ2D5.js +15 -0
- package/dist/chunk-AE3P3F6W.js +366 -0
- package/dist/chunk-AERM3VGP.js +280 -0
- package/dist/chunk-AEWHC4WM.js +246 -0
- package/dist/chunk-AOVQ7VIF.js +169 -0
- package/dist/chunk-AOYHP3WI.js +12411 -0
- package/dist/chunk-B3YEBABJ.js +7160 -0
- package/dist/chunk-BCQXEZPJ.js +154 -0
- package/dist/chunk-BKTQAYO2.js +418 -0
- package/dist/chunk-BSECIPAQ.js +80 -0
- package/dist/chunk-BUIMGNDD.js +52 -0
- package/dist/chunk-BXHV3GSB.js +10320 -0
- package/dist/chunk-C6ZVZCPP.js +139 -0
- package/dist/chunk-CEZNQVWM.js +82 -0
- package/dist/chunk-CGFZGR7G.js +1492 -0
- package/dist/chunk-CGOADM2X.js +337 -0
- package/dist/chunk-CI4R6P2B.js +24 -0
- package/dist/chunk-D2TCGRSX.js +73 -0
- package/dist/chunk-D4PTYFOG.js +154 -0
- package/dist/chunk-D54ZWG4T.js +717 -0
- package/dist/chunk-DEBI37QB.js +145 -0
- package/dist/chunk-DWROHPXP.js +1051 -0
- package/dist/chunk-DZ6UOJ5D.js +92 -0
- package/dist/chunk-EBJTVRQN.js +81 -0
- package/dist/chunk-EGEI2RQA.js +1167 -0
- package/dist/chunk-EHHUASO5.js +1305 -0
- package/dist/chunk-EPKTIOED.js +41 -0
- package/dist/chunk-ER5JW2QZ.js +5681 -0
- package/dist/chunk-ETHFACAB.js +315 -0
- package/dist/chunk-EXUE5W2F.js +112 -0
- package/dist/chunk-EXXICUIW.js +73 -0
- package/dist/chunk-FFQSZJOO.js +169 -0
- package/dist/chunk-FHFKPGDO.js +85 -0
- package/dist/chunk-FW3QKMFX.js +158 -0
- package/dist/chunk-GD4ZNZ7W.js +30 -0
- package/dist/chunk-GHVMWF2I.js +581 -0
- package/dist/chunk-GMKAXSYQ.js +297 -0
- package/dist/chunk-HBVF6BWO.js +325 -0
- package/dist/chunk-HV4YGVMS.js +379 -0
- package/dist/chunk-ILBCKAV6.js +89 -0
- package/dist/chunk-J4U4AW46.js +440 -0
- package/dist/chunk-J6ESSM47.js +1791 -0
- package/dist/chunk-JBZHIC6T.js +2309 -0
- package/dist/chunk-JCFWOULR.js +245 -0
- package/dist/chunk-JRF5L6OD.js +131 -0
- package/dist/chunk-JSS75KCG.js +2014 -0
- package/dist/chunk-JSXWIWWJ.js +225 -0
- package/dist/chunk-JYV7I2QH.js +98 -0
- package/dist/chunk-KIOXTQQL.js +1596 -0
- package/dist/chunk-KWVTXT5B.js +89 -0
- package/dist/chunk-KX22RD6R.js +33 -0
- package/dist/chunk-LA6IPTGH.js +709 -0
- package/dist/chunk-LH5VCGLB.js +1796 -0
- package/dist/chunk-LQQ6XJ2Y.js +269 -0
- package/dist/chunk-MJQ55WZZ.js +65 -0
- package/dist/chunk-ML3UKMH3.js +40 -0
- package/dist/chunk-MOZPLHSU.js +5526 -0
- package/dist/chunk-NGEWJ4DF.js +89 -0
- package/dist/chunk-NH6VIOAR.js +211 -0
- package/dist/chunk-O5VZQKCB.js +26106 -0
- package/dist/chunk-OHSV42QB.js +748 -0
- package/dist/chunk-OO3TAHO5.js +4070 -0
- package/dist/chunk-OTNHSAGN.js +38282 -0
- package/dist/chunk-OUWAC7AQ.js +442 -0
- package/dist/chunk-OXMIV4WE.js +270 -0
- package/dist/chunk-P5KJURUR.js +229 -0
- package/dist/chunk-P6GJOVO6.js +307 -0
- package/dist/chunk-QARAGUXX.js +23 -0
- package/dist/chunk-R43HJCDX.js +2711 -0
- package/dist/chunk-RAXBAWRN.js +210 -0
- package/dist/chunk-RK3JHWPT.js +39 -0
- package/dist/chunk-RWA23GMM.js +24 -0
- package/dist/chunk-S4K4L6IM.js +179 -0
- package/dist/chunk-SAXK6LVF.js +124 -0
- package/dist/chunk-SEPGEJNK.js +1607 -0
- package/dist/chunk-SUJERP5I.js +285 -0
- package/dist/chunk-T3ED6BY2.js +913 -0
- package/dist/chunk-THKDVSEC.js +90 -0
- package/dist/chunk-TI4GSEL5.js +52 -0
- package/dist/chunk-TPI73L57.js +164 -0
- package/dist/chunk-TVHW77C7.js +338 -0
- package/dist/chunk-TWNHOSDT.js +1073 -0
- package/dist/chunk-UFMN76QD.js +347 -0
- package/dist/chunk-UHGLFRZE.js +205 -0
- package/dist/chunk-UTZYPKBF.js +15231 -0
- package/dist/chunk-UXNLELW6.js +25 -0
- package/dist/chunk-UXXS53EA.js +166 -0
- package/dist/chunk-V5DHFGI7.js +171 -0
- package/dist/chunk-V5YIPMHV.js +2353 -0
- package/dist/chunk-WMUWEO2C.js +754 -0
- package/dist/chunk-WOE3D7JM.js +945 -0
- package/dist/chunk-X2IK5LVR.js +2592 -0
- package/dist/chunk-XU2YXCDL.js +459 -0
- package/dist/chunk-YJG5HIX5.js +203 -0
- package/dist/chunk-Z3QE7TZM.js +72 -0
- package/dist/chunk-Z5Z3JHJY.js +64 -0
- package/dist/chunk-ZDIFBJFT.js +168 -0
- package/dist/chunk-ZGGCEXDC.js +176 -0
- package/dist/chunk-ZMZCZNKU.js +263 -0
- package/dist/chunk-ZNC5T65N.js +17 -0
- package/dist/chunk-ZO3I3A7O.js +308 -0
- package/dist/chunk-ZQKXBUB7.js +217 -0
- package/dist/chunk-ZTRINFM2.js +78 -0
- package/dist/chunk-ZU7JZCVP.js +193 -0
- package/dist/chunk-ZZAWNALS.js +350 -0
- package/dist/cli/entry.js +54 -0
- package/dist/connector-L5QQTR6Y.js +26 -0
- package/dist/context-62DC6EC3.js +31 -0
- package/dist/council-convene-NJWPNBDU.js +46 -0
- package/dist/create-agent-config-ODSQWNVC.js +55 -0
- package/dist/default-registry-2PU3BTAU.js +68 -0
- package/dist/deliver-task-KONV4C4M.js +57 -0
- package/dist/delivery-gate-v2-F2YVMVGK.js +27 -0
- package/dist/domain-knowledge-store-DDZ3F4J7.js +11 -0
- package/dist/fetch-core-ZPPYDSZH.js +14 -0
- package/dist/galaxy-K72BBDQN.js +91 -0
- package/dist/goal-criteria-SCALAU2D.js +141 -0
- package/dist/goal-persist-XWY2GDQX.js +19 -0
- package/dist/goal-tracker-FXMJ2GVK.js +11 -0
- package/dist/headless-LSB6I7PT.js +162 -0
- package/dist/headless-coordinator-VDPDMVUT.js +90 -0
- package/dist/inject-U55SMB6A.js +39 -0
- package/dist/login-flow-CD4ZGXOC.js +59 -0
- package/dist/logs-cli-SQVYFMMN.js +283 -0
- package/dist/loop-ULZYBDA3.js +76 -0
- package/dist/main.js +4064 -0
- package/dist/manager-ROZBCWPA.js +171 -0
- package/dist/manager-Z7XFFUOM.js +10670 -0
- package/dist/meridian-indexer-ZIW363L7.js +21 -0
- package/dist/native-resolver-PN34UIVV.js +13 -0
- package/dist/node_modules/better-sqlite3/lib/database.js +90 -0
- package/dist/node_modules/better-sqlite3/lib/index.js +3 -0
- package/dist/node_modules/better-sqlite3/lib/methods/aggregate.js +43 -0
- package/dist/node_modules/better-sqlite3/lib/methods/backup.js +67 -0
- package/dist/node_modules/better-sqlite3/lib/methods/function.js +31 -0
- package/dist/node_modules/better-sqlite3/lib/methods/inspect.js +7 -0
- package/dist/node_modules/better-sqlite3/lib/methods/pragma.js +12 -0
- package/dist/node_modules/better-sqlite3/lib/methods/serialize.js +16 -0
- package/dist/node_modules/better-sqlite3/lib/methods/table.js +189 -0
- package/dist/node_modules/better-sqlite3/lib/methods/transaction.js +78 -0
- package/dist/node_modules/better-sqlite3/lib/methods/wrappers.js +54 -0
- package/dist/node_modules/better-sqlite3/lib/sqlite-error.js +20 -0
- package/dist/node_modules/better-sqlite3/lib/util.js +12 -0
- package/dist/node_modules/better-sqlite3/package.json +59 -0
- package/dist/ownership-ledger-E3WIEKPL.js +9 -0
- package/dist/package.json +3 -0
- package/dist/path-grants-XRRXHXG7.js +40 -0
- package/dist/paths-LVV5IMQN.js +49 -0
- package/dist/plan-fact-anchors-LMVQZCW5.js +13 -0
- package/dist/plan-store-ODLTTPFB.js +17 -0
- package/dist/plan-templates-5FPFBOL6.js +109 -0
- package/dist/plugin-loader-ZZKX7ZE6.js +22 -0
- package/dist/prefix-budget-62OV5HQC.js +13 -0
- package/dist/project-trust-5WS5MOMU.js +31 -0
- package/dist/provider-cli-ALDQXIT7.js +37 -0
- package/dist/providers-XQYTAVPK.js +11 -0
- package/dist/proxy-resolver-V2Y6534D.js +15 -0
- package/dist/recovery-cli-KPGY6FY3.js +106 -0
- package/dist/review-discipline-MNSYCST5.js +55 -0
- package/dist/review-router-BVQZW3MX.js +18 -0
- package/dist/seed-capsules/seed-capsule-attack-methodology.md +62 -0
- package/dist/seed-capsules/seed-capsule-changgeng.md +31 -0
- package/dist/seed-capsules/seed-capsule-design-aesthetics.md +38 -0
- package/dist/seed-capsules/seed-capsule-diagnostic-ladder.md +54 -0
- package/dist/seed-capsules/seed-capsule-fu.md +39 -0
- package/dist/seed-capsules/seed-capsule-huagai.md +73 -0
- package/dist/seed-capsules/seed-capsule-kaiyang.md +65 -0
- package/dist/seed-capsules/seed-capsule-knowledge-work.md +40 -0
- package/dist/seed-capsules/seed-capsule-tanlang.md +47 -0
- package/dist/seed-capsules/seed-capsule-tianfu.md +23 -0
- package/dist/seed-capsules/seed-capsule-tianliang.md +63 -0
- package/dist/seed-capsules/seed-capsule-tianquan.md +32 -0
- package/dist/seed-capsules/seed-capsule-tianxuan-ccr.md +22 -0
- package/dist/seed-capsules/seed-capsule-tianxuan.md +64 -0
- package/dist/seed-capsules/seed-capsule-yaoguang.md +87 -0
- package/dist/serve-X2R2UTLF.js +170 -0
- package/dist/serve-agent-KHSU6RVV.js +965 -0
- package/dist/session-persist-HUUC772H.js +37 -0
- package/dist/session-registry-6XUD5C4Y.js +15 -0
- package/dist/skill-loader-CK3RMO47.js +48 -0
- package/dist/skills/cli-harness-sop.md +207 -0
- package/dist/spawn-git-4HFU65AH.js +29 -0
- package/dist/sse-EYUTBWUK.js +512 -0
- package/dist/starflow-NOFBMPFU.js +30 -0
- package/dist/streamableHttp-V67CNJMO.js +447 -0
- package/dist/task-contract-6XHBNJQK.js +32 -0
- package/dist/task-ledger-3K4TJIER.js +9 -0
- package/dist/team-orchestrate-S6NHZP7X.js +64 -0
- package/dist/title-extract-QX4XGCYN.js +50 -0
- package/dist/todo-QDXGRZZP.js +31 -0
- package/dist/todo-store-V3TTO5AH.js +12 -0
- package/dist/tool-preset-LU5BYEDZ.js +23 -0
- package/dist/tool-tiers-GD742YBN.js +23 -0
- package/dist/turndown.es-OI55K6C3.js +17373 -0
- package/dist/verification-attribution-EKG4CNUV.js +13 -0
- package/dist/volatile-git-MBTST7RA.js +15 -0
- package/dist/wave-checkpoint-XLIIHXQA.js +30 -0
- package/dist/web-cli-DUG4I35O.js +233 -0
- package/dist/web-search-3IK542AA.js +34 -0
- package/dist/workers/cpu-worker.js +45 -0
- package/dist/workflow-runner-HX7UBAYG.js +297 -0
- package/dist/worktree-baseline-O5NCU6M2.js +9 -0
- package/package.json +122 -0
- package/scripts/check-mobile-env.mjs +76 -0
- package/scripts/fetch-native-sqlite.js +392 -0
- package/scripts/prune-installed-wasms.js +45 -0
- package/scripts/tree-sitter-wasm-keep.js +40 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --expose-gc --max-old-space-size=4096
|
|
2
|
+
import { createRequire as __rivetCreateRequire } from 'node:module'; const require = __rivetCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
init_esm_shims
|
|
5
|
+
} from "./chunk-5GGOGLSN.js";
|
|
6
|
+
|
|
7
|
+
// src/plan/plan-store.ts
|
|
8
|
+
init_esm_shims();
|
|
9
|
+
import { mkdir, readdir, readFile, stat, writeFile, rm } from "fs/promises";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
12
|
+
var PLAN_OPTIONS_FRONTMATTER_RE = /^---\r?\nrivet-options:\s*(\[[\s\S]*?\])\s*\r?\n---\r?\n/;
|
|
13
|
+
var PLAN_STATUS_LINE_RE = /^>\s*\*\*Status:\s*(?:APPROVED|REJECTED|EXECUTED)\*\*.*(?:\r?\n)+/gm;
|
|
14
|
+
function stripPlanStatusMarkers(content) {
|
|
15
|
+
return content.replace(PLAN_STATUS_LINE_RE, "");
|
|
16
|
+
}
|
|
17
|
+
var PLAN_MODEL_LINE_RE = /^>\s*\*\*Model:\s*(.+?)(?:\s*\((cheap|balanced|strong)\))?\*\*.*(?:\r?\n)+/m;
|
|
18
|
+
function parsePlanModel(content) {
|
|
19
|
+
const m = content.match(PLAN_MODEL_LINE_RE);
|
|
20
|
+
if (!m) return void 0;
|
|
21
|
+
return { model: m[1].trim(), tier: m[2] ?? null };
|
|
22
|
+
}
|
|
23
|
+
function insertPlanModelMarker(content, model, tier) {
|
|
24
|
+
const stripped = content.replace(new RegExp(PLAN_MODEL_LINE_RE, "gm"), "");
|
|
25
|
+
const line = `> **Model: ${model}${tier ? ` (${tier})` : ""}**
|
|
26
|
+
|
|
27
|
+
`;
|
|
28
|
+
const h1Match = stripped.match(/^#\s+.*$/m);
|
|
29
|
+
if (h1Match) {
|
|
30
|
+
const idx = stripped.indexOf(h1Match[0]);
|
|
31
|
+
return stripped.slice(0, idx) + line + stripped.slice(idx);
|
|
32
|
+
}
|
|
33
|
+
return line + stripped;
|
|
34
|
+
}
|
|
35
|
+
var PLANS_DIR = ".rivet/plans";
|
|
36
|
+
function isDraftSlug(slug) {
|
|
37
|
+
return /^draft-\d+$/.test(slug);
|
|
38
|
+
}
|
|
39
|
+
function plansRoot(cwd) {
|
|
40
|
+
return join(cwd, PLANS_DIR);
|
|
41
|
+
}
|
|
42
|
+
function planFilePath(cwd, slug) {
|
|
43
|
+
return join(plansRoot(cwd), `${slug}.md`);
|
|
44
|
+
}
|
|
45
|
+
async function ensurePlansDir(cwd) {
|
|
46
|
+
const dir = plansRoot(cwd);
|
|
47
|
+
if (!existsSync(dir)) {
|
|
48
|
+
await mkdir(dir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function slugify(text) {
|
|
52
|
+
return text.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "plan";
|
|
53
|
+
}
|
|
54
|
+
function extractTitle(content) {
|
|
55
|
+
const m = content.match(/^#\s+(.+)$/m);
|
|
56
|
+
return m?.[1]?.trim() || "Untitled Plan";
|
|
57
|
+
}
|
|
58
|
+
function parsePlanOptions(content) {
|
|
59
|
+
const m = content.match(PLAN_OPTIONS_FRONTMATTER_RE);
|
|
60
|
+
if (!m) return void 0;
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(m[1]);
|
|
63
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
64
|
+
const options = parsed.filter(
|
|
65
|
+
(item) => item !== null && typeof item === "object" && typeof item.label === "string" && typeof item.description === "string"
|
|
66
|
+
);
|
|
67
|
+
return options.length > 0 ? options : void 0;
|
|
68
|
+
} catch {
|
|
69
|
+
return void 0;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function resolvePlanOptionLabel(options, input) {
|
|
73
|
+
const normalize = (s) => s.trim().toLowerCase();
|
|
74
|
+
const stripSuffix = (s) => normalize(s).replace(/\s*\([^)]*\)\s*$/, "");
|
|
75
|
+
const wanted = normalize(input);
|
|
76
|
+
const exact = options.find((o) => normalize(o.label) === wanted);
|
|
77
|
+
if (exact) return exact.label;
|
|
78
|
+
const wantedBare = stripSuffix(input);
|
|
79
|
+
const bareMatches = options.filter((o) => stripSuffix(o.label) === wantedBare);
|
|
80
|
+
return bareMatches.length === 1 ? bareMatches[0].label : void 0;
|
|
81
|
+
}
|
|
82
|
+
function stripCopiedTitleSuffix(input) {
|
|
83
|
+
const idx = input.indexOf(" \u2014 ");
|
|
84
|
+
return (idx >= 0 ? input.slice(0, idx) : input).trim();
|
|
85
|
+
}
|
|
86
|
+
function resolvePlanRef(plans, input) {
|
|
87
|
+
const stripped = stripCopiedTitleSuffix(input);
|
|
88
|
+
const wanted = stripped.toLowerCase();
|
|
89
|
+
if (!wanted) return { kind: "none" };
|
|
90
|
+
const exact = plans.find((p) => p.slug.toLowerCase() === wanted);
|
|
91
|
+
if (exact) return { kind: "match", plan: exact };
|
|
92
|
+
const wantedSlug = slugify(stripped);
|
|
93
|
+
const byTitle = plans.filter((p) => slugify(p.title) === wantedSlug);
|
|
94
|
+
if (byTitle.length === 1) return { kind: "match", plan: byTitle[0] };
|
|
95
|
+
if (byTitle.length > 1) return { kind: "ambiguous", slugs: byTitle.map((p) => p.slug) };
|
|
96
|
+
const prefix = plans.filter((p) => p.slug.toLowerCase().startsWith(wanted));
|
|
97
|
+
if (prefix.length === 1) return { kind: "match", plan: prefix[0] };
|
|
98
|
+
if (prefix.length > 1) return { kind: "ambiguous", slugs: prefix.map((p) => p.slug) };
|
|
99
|
+
return { kind: "none" };
|
|
100
|
+
}
|
|
101
|
+
function buildPlanFrontmatter(options) {
|
|
102
|
+
if (!options || options.length === 0) return "";
|
|
103
|
+
return `---
|
|
104
|
+
rivet-options: ${JSON.stringify(options)}
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
109
|
+
async function writePlan(cwd, slug, content, options) {
|
|
110
|
+
await ensurePlansDir(cwd);
|
|
111
|
+
const filePath = planFilePath(cwd, slug);
|
|
112
|
+
const body = buildPlanFrontmatter(options) + content.replace(PLAN_OPTIONS_FRONTMATTER_RE, "");
|
|
113
|
+
await writeFile(filePath, body, "utf-8");
|
|
114
|
+
return `${PLANS_DIR}/${slug}.md`;
|
|
115
|
+
}
|
|
116
|
+
async function readPlan(cwd, slug) {
|
|
117
|
+
const filePath = planFilePath(cwd, slug);
|
|
118
|
+
try {
|
|
119
|
+
const content = await readFile(filePath, "utf-8");
|
|
120
|
+
const s = await stat(filePath);
|
|
121
|
+
const status = parsePlanStatus(content);
|
|
122
|
+
const provenance = parsePlanModel(content);
|
|
123
|
+
return {
|
|
124
|
+
slug,
|
|
125
|
+
title: extractTitle(content),
|
|
126
|
+
content,
|
|
127
|
+
path: `${PLANS_DIR}/${slug}.md`,
|
|
128
|
+
createdAt: s.birthtime,
|
|
129
|
+
status,
|
|
130
|
+
options: parsePlanOptions(content),
|
|
131
|
+
...provenance ? { model: provenance.model, modelTier: provenance.tier } : {}
|
|
132
|
+
};
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function readPlanSync(cwd, slug) {
|
|
138
|
+
const filePath = planFilePath(cwd, slug);
|
|
139
|
+
try {
|
|
140
|
+
const content = readFileSync(filePath, "utf-8");
|
|
141
|
+
const s = statSync(filePath);
|
|
142
|
+
const provenance = parsePlanModel(content);
|
|
143
|
+
return {
|
|
144
|
+
slug,
|
|
145
|
+
title: extractTitle(content),
|
|
146
|
+
content,
|
|
147
|
+
path: `${PLANS_DIR}/${slug}.md`,
|
|
148
|
+
createdAt: s.birthtime,
|
|
149
|
+
status: parsePlanStatus(content),
|
|
150
|
+
options: parsePlanOptions(content),
|
|
151
|
+
...provenance ? { model: provenance.model, modelTier: provenance.tier } : {}
|
|
152
|
+
};
|
|
153
|
+
} catch {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function stripPlanChrome(content) {
|
|
158
|
+
const rawLines = content.split("\n");
|
|
159
|
+
let start = 0;
|
|
160
|
+
if (rawLines[0]?.trim() === "---") {
|
|
161
|
+
const close = rawLines.findIndex((l, i) => i > 0 && l.trim() === "---");
|
|
162
|
+
if (close > 0) start = close + 1;
|
|
163
|
+
}
|
|
164
|
+
const out = [];
|
|
165
|
+
for (const raw of rawLines.slice(start)) {
|
|
166
|
+
const t = raw.trim();
|
|
167
|
+
if (t.startsWith("> **Status:") || t.startsWith("> **Model:")) continue;
|
|
168
|
+
out.push(raw);
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
async function listPlans(cwd) {
|
|
173
|
+
const dir = plansRoot(cwd);
|
|
174
|
+
if (!existsSync(dir)) return [];
|
|
175
|
+
const entries = await readdir(dir);
|
|
176
|
+
const plans = [];
|
|
177
|
+
for (const entry of entries) {
|
|
178
|
+
if (!entry.endsWith(".md")) continue;
|
|
179
|
+
const slug = entry.replace(/\.md$/, "");
|
|
180
|
+
if (isDraftSlug(slug)) continue;
|
|
181
|
+
const plan = await readPlan(cwd, slug);
|
|
182
|
+
if (plan) plans.push(plan);
|
|
183
|
+
}
|
|
184
|
+
return plans.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
185
|
+
}
|
|
186
|
+
function listPlansSync(cwd) {
|
|
187
|
+
const dir = plansRoot(cwd);
|
|
188
|
+
if (!existsSync(dir)) return [];
|
|
189
|
+
const plans = [];
|
|
190
|
+
for (const entry of readdirSync(dir)) {
|
|
191
|
+
if (!entry.endsWith(".md")) continue;
|
|
192
|
+
const slug = entry.replace(/\.md$/, "");
|
|
193
|
+
if (isDraftSlug(slug)) continue;
|
|
194
|
+
try {
|
|
195
|
+
const filePath = planFilePath(cwd, slug);
|
|
196
|
+
const content = readFileSync(filePath, "utf-8");
|
|
197
|
+
const s = statSync(filePath);
|
|
198
|
+
const provenance = parsePlanModel(content);
|
|
199
|
+
plans.push({
|
|
200
|
+
slug,
|
|
201
|
+
title: extractTitle(content),
|
|
202
|
+
content,
|
|
203
|
+
path: `${PLANS_DIR}/${slug}.md`,
|
|
204
|
+
createdAt: s.birthtime,
|
|
205
|
+
status: parsePlanStatus(content),
|
|
206
|
+
options: parsePlanOptions(content),
|
|
207
|
+
...provenance ? { model: provenance.model, modelTier: provenance.tier } : {}
|
|
208
|
+
});
|
|
209
|
+
} catch {
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return plans.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
213
|
+
}
|
|
214
|
+
async function approvePlan(cwd, slug) {
|
|
215
|
+
return markPlanStatus(cwd, slug, "APPROVED");
|
|
216
|
+
}
|
|
217
|
+
async function rejectPlan(cwd, slug) {
|
|
218
|
+
return markPlanStatus(cwd, slug, "REJECTED");
|
|
219
|
+
}
|
|
220
|
+
function insertPlanStatusMarker(content, status) {
|
|
221
|
+
const statusLine = `> **Status: ${status}** \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
222
|
+
|
|
223
|
+
`;
|
|
224
|
+
const h1Match = content.match(/^#\s+.*$/m);
|
|
225
|
+
if (h1Match) {
|
|
226
|
+
const idx = content.indexOf(h1Match[0]);
|
|
227
|
+
return content.slice(0, idx) + statusLine + content.slice(idx);
|
|
228
|
+
}
|
|
229
|
+
return statusLine + content;
|
|
230
|
+
}
|
|
231
|
+
async function markPlanStatus(cwd, slug, status) {
|
|
232
|
+
const plan = await readPlan(cwd, slug);
|
|
233
|
+
if (!plan) return null;
|
|
234
|
+
const newContent = insertPlanStatusMarker(plan.content, status);
|
|
235
|
+
await writePlan(cwd, slug, newContent, plan.options);
|
|
236
|
+
return readPlan(cwd, slug);
|
|
237
|
+
}
|
|
238
|
+
function parsePlanStatus(content) {
|
|
239
|
+
if (/Status:\s*EXECUTED/i.test(content)) return "executed";
|
|
240
|
+
if (/Status:\s*APPROVED/i.test(content)) return "approved";
|
|
241
|
+
if (/Status:\s*REJECTED/i.test(content)) return "rejected";
|
|
242
|
+
return "submitted";
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export {
|
|
246
|
+
stripPlanStatusMarkers,
|
|
247
|
+
insertPlanModelMarker,
|
|
248
|
+
isDraftSlug,
|
|
249
|
+
slugify,
|
|
250
|
+
parsePlanOptions,
|
|
251
|
+
resolvePlanOptionLabel,
|
|
252
|
+
stripCopiedTitleSuffix,
|
|
253
|
+
resolvePlanRef,
|
|
254
|
+
writePlan,
|
|
255
|
+
readPlan,
|
|
256
|
+
readPlanSync,
|
|
257
|
+
stripPlanChrome,
|
|
258
|
+
listPlans,
|
|
259
|
+
listPlansSync,
|
|
260
|
+
approvePlan,
|
|
261
|
+
rejectPlan,
|
|
262
|
+
insertPlanStatusMarker
|
|
263
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --expose-gc --max-old-space-size=4096
|
|
2
|
+
import { createRequire as __rivetCreateRequire } from 'node:module'; const require = __rivetCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
init_esm_shims
|
|
5
|
+
} from "./chunk-5GGOGLSN.js";
|
|
6
|
+
|
|
7
|
+
// src/tools/output-markers.ts
|
|
8
|
+
init_esm_shims();
|
|
9
|
+
var BROWSER_NAVIGATED_PREFIX = "\u5DF2\u5BFC\u822A\u81F3";
|
|
10
|
+
var BROWSER_SCREENSHOT_OF_PREFIX = "\u622A\u56FE\u4E8E";
|
|
11
|
+
var COMPUTER_USE_A11Y_TREE_PREFIX = "\u53EF\u8BBF\u95EE\u6027\u6811";
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
BROWSER_NAVIGATED_PREFIX,
|
|
15
|
+
BROWSER_SCREENSHOT_OF_PREFIX,
|
|
16
|
+
COMPUTER_USE_A11Y_TREE_PREFIX
|
|
17
|
+
};
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --expose-gc --max-old-space-size=4096
|
|
2
|
+
import { createRequire as __rivetCreateRequire } from 'node:module'; const require = __rivetCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
init_esm_shims
|
|
5
|
+
} from "./chunk-5GGOGLSN.js";
|
|
6
|
+
|
|
7
|
+
// src/agent/verification-attribution.ts
|
|
8
|
+
init_esm_shims();
|
|
9
|
+
function normalizeCommand(command) {
|
|
10
|
+
return command.trim().replace(/["']/g, "").replace(/\s+/g, " ").toLowerCase();
|
|
11
|
+
}
|
|
12
|
+
function asNumber(value, fallback) {
|
|
13
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
14
|
+
}
|
|
15
|
+
function asString(value) {
|
|
16
|
+
return typeof value === "string" ? value : void 0;
|
|
17
|
+
}
|
|
18
|
+
function extractTestFiles(command) {
|
|
19
|
+
const files = /* @__PURE__ */ new Set();
|
|
20
|
+
const matches = command.matchAll(/[^\s'"]+\.(?:test|spec)\.(?:ts|tsx|js|jsx|mjs|cjs)/g);
|
|
21
|
+
for (const match of matches) {
|
|
22
|
+
const file = match[0]?.trim().replace(/^['"]|['"]$/g, "");
|
|
23
|
+
if (file) files.add(file);
|
|
24
|
+
}
|
|
25
|
+
return [...files].sort();
|
|
26
|
+
}
|
|
27
|
+
function getMetaTargetFiles(meta) {
|
|
28
|
+
const raw = meta?.targetFiles;
|
|
29
|
+
if (!Array.isArray(raw)) return [];
|
|
30
|
+
return raw.filter((f) => typeof f === "string" && f.length > 0).sort();
|
|
31
|
+
}
|
|
32
|
+
function runnerFamily(command) {
|
|
33
|
+
const normalized = normalizeCommand(command);
|
|
34
|
+
if (normalized.startsWith("run_tests") || normalized.includes("tsx --test") || normalized.includes("node --test")) {
|
|
35
|
+
return "node-test";
|
|
36
|
+
}
|
|
37
|
+
return normalized.split(" ")[0] ?? normalized;
|
|
38
|
+
}
|
|
39
|
+
function isInvocationFailureMeta(status, meta) {
|
|
40
|
+
if (status !== "failed") return false;
|
|
41
|
+
return asNumber(meta?.exitCode, 1) !== 0 && asNumber(meta?.passed, 0) === 0 && asNumber(meta?.failed, 1) === 0 && asNumber(meta?.skipped, 0) === 0;
|
|
42
|
+
}
|
|
43
|
+
function eventToVerificationMetadata(event) {
|
|
44
|
+
const scope = event.meta?.scope === "full" ? "full" : "targeted";
|
|
45
|
+
const status = event.status ?? "passed";
|
|
46
|
+
const command = event.command ?? "unknown";
|
|
47
|
+
const targetFiles = getMetaTargetFiles(event.meta);
|
|
48
|
+
const resolvedCommand = asString(event.meta?.resolvedCommand);
|
|
49
|
+
const recommendedCommand = asString(event.meta?.recommendedCommand);
|
|
50
|
+
const snapshotRef = asString(event.meta?.snapshotRef);
|
|
51
|
+
const phaseRaw = asString(event.meta?.verificationPhase);
|
|
52
|
+
const verificationPhase = phaseRaw === "isolated" || phaseRaw === "integration" ? phaseRaw : void 0;
|
|
53
|
+
const failureKind = asString(event.meta?.failureKind) === "tool_invocation_failure" || isInvocationFailureMeta(status, event.meta) ? "tool_invocation_failure" : asString(event.meta?.failureKind) === "test_failure" ? "test_failure" : void 0;
|
|
54
|
+
return {
|
|
55
|
+
command,
|
|
56
|
+
status,
|
|
57
|
+
scope,
|
|
58
|
+
exitCode: asNumber(event.meta?.exitCode, status === "failed" ? 1 : 0),
|
|
59
|
+
passed: asNumber(event.meta?.passed, status === "passed" ? 1 : 0),
|
|
60
|
+
failed: asNumber(event.meta?.failed, status === "failed" ? 1 : 0),
|
|
61
|
+
skipped: asNumber(event.meta?.skipped, 0),
|
|
62
|
+
durationMs: asNumber(event.meta?.durationMs, 0),
|
|
63
|
+
...failureKind ? { failureKind } : {},
|
|
64
|
+
...targetFiles.length > 0 ? { targetFiles } : {},
|
|
65
|
+
...resolvedCommand ? { resolvedCommand } : {},
|
|
66
|
+
...recommendedCommand ? { recommendedCommand } : {},
|
|
67
|
+
...snapshotRef ? { snapshotRef } : {},
|
|
68
|
+
...verificationPhase ? { verificationPhase } : {}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function verificationKey(event) {
|
|
72
|
+
const command = event.command ?? "unknown";
|
|
73
|
+
const scope = event.meta?.scope === "full" ? "full" : "targeted";
|
|
74
|
+
const resolvedCommand = asString(event.meta?.resolvedCommand) ?? "";
|
|
75
|
+
const metaTargetFiles = getMetaTargetFiles(event.meta);
|
|
76
|
+
const cmdTargetFiles = extractTestFiles(command);
|
|
77
|
+
const resolvedTargetFiles = extractTestFiles(resolvedCommand);
|
|
78
|
+
const targetFiles = metaTargetFiles.length > 0 ? metaTargetFiles : [...cmdTargetFiles, ...resolvedTargetFiles];
|
|
79
|
+
const uniqueTargetFiles = [...new Set(targetFiles)].sort();
|
|
80
|
+
if (uniqueTargetFiles.length > 0) {
|
|
81
|
+
return `tests::${scope}::${runnerFamily(`${command} ${resolvedCommand}`)}::${uniqueTargetFiles.join("|")}`;
|
|
82
|
+
}
|
|
83
|
+
return `${normalizeCommand(command)}::${scope}`;
|
|
84
|
+
}
|
|
85
|
+
function getEffectiveVerifications(events, currentSnapshotRef) {
|
|
86
|
+
const allVerificationEvents = events.filter((e) => e.type === "verification");
|
|
87
|
+
let staleSnapshotDropped = 0;
|
|
88
|
+
const verificationEvents = currentSnapshotRef ? allVerificationEvents.filter((e) => {
|
|
89
|
+
const ref = asString(e.meta?.snapshotRef);
|
|
90
|
+
if (ref && ref !== currentSnapshotRef) {
|
|
91
|
+
staleSnapshotDropped++;
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}) : allVerificationEvents;
|
|
96
|
+
const keyMap = /* @__PURE__ */ new Map();
|
|
97
|
+
let supersededFailures = 0;
|
|
98
|
+
for (let i = 0; i < verificationEvents.length; i++) {
|
|
99
|
+
const event = verificationEvents[i];
|
|
100
|
+
const key = verificationKey(event);
|
|
101
|
+
const existing = keyMap.get(key);
|
|
102
|
+
if (existing) {
|
|
103
|
+
if (existing.event.status === "failed" && event.status === "passed") {
|
|
104
|
+
supersededFailures++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
keyMap.set(key, { event, index: i });
|
|
108
|
+
}
|
|
109
|
+
const effective = [];
|
|
110
|
+
for (const { event } of keyMap.values()) {
|
|
111
|
+
effective.push(eventToVerificationMetadata(event));
|
|
112
|
+
}
|
|
113
|
+
return { effective, supersededFailures, totalRawCount: allVerificationEvents.length, staleSnapshotDropped };
|
|
114
|
+
}
|
|
115
|
+
function normalizePathForMatch(p) {
|
|
116
|
+
return p.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
117
|
+
}
|
|
118
|
+
function pathsMatch(a, b) {
|
|
119
|
+
if (a === b) return true;
|
|
120
|
+
return a.endsWith(`/${b}`) || b.endsWith(`/${a}`);
|
|
121
|
+
}
|
|
122
|
+
function assessImpactedTestCoverage(impactedTests, verifications, existsFn) {
|
|
123
|
+
if (impactedTests.length === 0) return { uncovered: [], uncoverable: [] };
|
|
124
|
+
const passed = verifications.filter((v) => v.status === "passed");
|
|
125
|
+
if (passed.some((v) => v.scope === "full")) return { uncovered: [], uncoverable: [] };
|
|
126
|
+
const coveredFiles = [];
|
|
127
|
+
for (const v of passed) {
|
|
128
|
+
const targets = v.targetFiles && v.targetFiles.length > 0 ? v.targetFiles : [...extractTestFiles(v.command), ...extractTestFiles(v.resolvedCommand ?? "")];
|
|
129
|
+
for (const t of targets) coveredFiles.push(normalizePathForMatch(t));
|
|
130
|
+
}
|
|
131
|
+
const uncovered = [];
|
|
132
|
+
const uncoverable = [];
|
|
133
|
+
for (const test of [...new Set(impactedTests)].sort()) {
|
|
134
|
+
if (!existsFn(test)) {
|
|
135
|
+
uncoverable.push(test);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const normalized = normalizePathForMatch(test);
|
|
139
|
+
if (!coveredFiles.some((c) => pathsMatch(normalized, c))) {
|
|
140
|
+
uncovered.push(test);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { uncovered, uncoverable };
|
|
144
|
+
}
|
|
145
|
+
function isInvocationFailure(result) {
|
|
146
|
+
return result.status === "failed" && result.exitCode !== 0 && result.passed === 0 && result.failed === 0 && result.skipped === 0;
|
|
147
|
+
}
|
|
148
|
+
function createVerificationAttribution(_opts) {
|
|
149
|
+
function attribute(result) {
|
|
150
|
+
if (result.status === "passed") {
|
|
151
|
+
return {
|
|
152
|
+
attribution: "verified",
|
|
153
|
+
isBlocking: false,
|
|
154
|
+
reason: `Verification passed: ${result.command}`,
|
|
155
|
+
source: result
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (result.status === "blocked") {
|
|
159
|
+
const blockedReason = result.blockedReason;
|
|
160
|
+
if (blockedReason === "no_test_framework" || blockedReason === "no_tests_found") {
|
|
161
|
+
const userGuidance = result.userGuidance ?? "\u9879\u76EE\u7F3A\u5C11\u53EF\u81EA\u52A8\u68C0\u6D4B\u7684\u6D4B\u8BD5\u6846\u67B6\u3002";
|
|
162
|
+
return {
|
|
163
|
+
attribution: "no_test_infra",
|
|
164
|
+
isBlocking: false,
|
|
165
|
+
reason: `Verification infrastructure missing (${blockedReason}): ${result.command}. ${userGuidance}`,
|
|
166
|
+
source: result
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
attribution: "external_blocked",
|
|
171
|
+
isBlocking: false,
|
|
172
|
+
reason: `Verification blocked by external factors: ${result.command} (exit ${result.exitCode})`,
|
|
173
|
+
source: result
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (result.status === "failed") {
|
|
177
|
+
if (result.verificationPhase === "integration") {
|
|
178
|
+
return {
|
|
179
|
+
attribution: "integration_conflict",
|
|
180
|
+
isBlocking: false,
|
|
181
|
+
reason: `Integration verification failed on current HEAD: ${result.command} \u2014 ${result.failed} test(s) failed. The owned diff passed in isolation; this is a concurrent-change conflict. Rebase/coordinate before merging; delivery is not blocked.`,
|
|
182
|
+
source: result
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (result.failureKind === "tool_invocation_failure" || isInvocationFailure(result)) {
|
|
186
|
+
return {
|
|
187
|
+
attribution: "tool_invocation_failure",
|
|
188
|
+
isBlocking: true,
|
|
189
|
+
reason: `Verification invocation failed: ${result.command}. No tests were executed; rerun with the repo recommended command.`,
|
|
190
|
+
source: result
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (result.scope === "targeted") {
|
|
194
|
+
return {
|
|
195
|
+
attribution: "owned_failure",
|
|
196
|
+
isBlocking: true,
|
|
197
|
+
reason: `Targeted verification failed: ${result.command} \u2014 ${result.failed} test(s) failed`,
|
|
198
|
+
source: result
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
attribution: "unattributed_failure",
|
|
203
|
+
isBlocking: false,
|
|
204
|
+
reason: `Full-scope verification failed: ${result.command} \u2014 ${result.failed} test(s) failed. Attribution to owned vs external files is unresolved.`,
|
|
205
|
+
source: result
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
attribution: "unverified",
|
|
210
|
+
isBlocking: true,
|
|
211
|
+
reason: `Unknown verification status for: ${result.command}`,
|
|
212
|
+
source: result
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function getAggregateAttribution(results) {
|
|
216
|
+
if (results.length === 0) {
|
|
217
|
+
return {
|
|
218
|
+
attribution: "unverified",
|
|
219
|
+
isBlocking: true,
|
|
220
|
+
reason: "No verifications have been run.",
|
|
221
|
+
source: {
|
|
222
|
+
command: "(none)",
|
|
223
|
+
status: "blocked",
|
|
224
|
+
scope: "full",
|
|
225
|
+
exitCode: -1,
|
|
226
|
+
passed: 0,
|
|
227
|
+
failed: 0,
|
|
228
|
+
skipped: 0,
|
|
229
|
+
durationMs: 0
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const attributions = results.map((r) => attribute(r));
|
|
234
|
+
const hasOwnedFailure = attributions.some((a) => a.attribution === "owned_failure");
|
|
235
|
+
if (hasOwnedFailure) {
|
|
236
|
+
const first = attributions.find((a) => a.attribution === "owned_failure");
|
|
237
|
+
return {
|
|
238
|
+
attribution: "owned_failure",
|
|
239
|
+
isBlocking: true,
|
|
240
|
+
reason: `Owned verification failure: ${first.source.command}`,
|
|
241
|
+
source: first.source
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const hasToolInvocationFailure = attributions.some((a) => a.attribution === "tool_invocation_failure");
|
|
245
|
+
if (hasToolInvocationFailure) {
|
|
246
|
+
const first = attributions.find((a) => a.attribution === "tool_invocation_failure");
|
|
247
|
+
return {
|
|
248
|
+
attribution: "tool_invocation_failure",
|
|
249
|
+
isBlocking: true,
|
|
250
|
+
reason: `Verification invocation failure: ${first.source.command}`,
|
|
251
|
+
source: first.source
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const hasNoTestInfra = attributions.some((a) => a.attribution === "no_test_infra");
|
|
255
|
+
if (hasNoTestInfra) {
|
|
256
|
+
const first = attributions.find((a) => a.attribution === "no_test_infra");
|
|
257
|
+
return {
|
|
258
|
+
attribution: "no_test_infra",
|
|
259
|
+
isBlocking: false,
|
|
260
|
+
reason: `Project test infrastructure missing: ${first.source.command}. ${first.source.userGuidance ?? ""}`,
|
|
261
|
+
source: first.source
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
const hasUnattributedFailure = attributions.some((a) => a.attribution === "unattributed_failure");
|
|
265
|
+
if (hasUnattributedFailure) {
|
|
266
|
+
const first = attributions.find((a) => a.attribution === "unattributed_failure");
|
|
267
|
+
return {
|
|
268
|
+
attribution: "unattributed_failure",
|
|
269
|
+
isBlocking: false,
|
|
270
|
+
reason: `Full-suite verification failed without owned-file attribution: ${first.source.command}. Treat as delivery caveat until diagnosed.`,
|
|
271
|
+
source: first.source
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const hasExternalBlocked = attributions.some((a) => a.attribution === "external_blocked");
|
|
275
|
+
if (hasExternalBlocked) {
|
|
276
|
+
const first = attributions.find((a) => a.attribution === "external_blocked");
|
|
277
|
+
return {
|
|
278
|
+
attribution: "external_blocked",
|
|
279
|
+
isBlocking: false,
|
|
280
|
+
reason: `Verification blocked by external factors: ${first.source.command}`,
|
|
281
|
+
source: first.source
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const hasIntegrationConflict = attributions.some((a) => a.attribution === "integration_conflict");
|
|
285
|
+
if (hasIntegrationConflict) {
|
|
286
|
+
const first = attributions.find((a) => a.attribution === "integration_conflict");
|
|
287
|
+
return {
|
|
288
|
+
attribution: "integration_conflict",
|
|
289
|
+
isBlocking: false,
|
|
290
|
+
reason: `Integration conflict on current HEAD: ${first.source.command}. Owned changes passed in isolation; rebase/coordinate before merging. Delivery not blocked.`,
|
|
291
|
+
source: first.source
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
attribution: "verified",
|
|
296
|
+
isBlocking: false,
|
|
297
|
+
reason: `${results.length} verification(s) passed.`,
|
|
298
|
+
source: results[0]
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
return { attribute, getAggregateAttribution };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export {
|
|
305
|
+
getEffectiveVerifications,
|
|
306
|
+
assessImpactedTestCoverage,
|
|
307
|
+
createVerificationAttribution
|
|
308
|
+
};
|