dunstan 0.1.7 → 0.1.8
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/README.md +1 -1
- package/dist/dunstan.mjs +37 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ report a pull request's handback before it says done ([`plugins/dunstan/`](plugi
|
|
|
27
27
|
/plugin install dunstan@barglabs
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
The plugin runs the MCP server with `npx -y dunstan@0.1.
|
|
30
|
+
The plugin runs the MCP server with `npx -y dunstan@0.1.8 mcp`, the `dunstan` npm package at that
|
|
31
31
|
exact version: one self-contained file, no dependencies.
|
|
32
32
|
|
|
33
33
|
**The token.** When you enable the plugin, Claude Code asks for an optional GitHub token and keeps it
|
package/dist/dunstan.mjs
CHANGED
|
@@ -8468,6 +8468,14 @@ function closedBy(reference, field, evidence, repository, at, observed) {
|
|
|
8468
8468
|
"not_closing"
|
|
8469
8469
|
);
|
|
8470
8470
|
}
|
|
8471
|
+
function closesBlock(issue2, headCommit) {
|
|
8472
|
+
return {
|
|
8473
|
+
dunstan: BLOCK_VERSION,
|
|
8474
|
+
headCommit,
|
|
8475
|
+
filesChanged: [],
|
|
8476
|
+
references: [{ issue: issue2, relation: "closes" }]
|
|
8477
|
+
};
|
|
8478
|
+
}
|
|
8471
8479
|
function checkReferences(block, evidence, repository) {
|
|
8472
8480
|
return (block.references ?? []).map((reference, i) => {
|
|
8473
8481
|
const field = `/references/${i}`;
|
|
@@ -9741,7 +9749,7 @@ async function reportFromComment(client, repository, number4, login) {
|
|
|
9741
9749
|
// src/record/checker.ts
|
|
9742
9750
|
import { readFileSync } from "node:fs";
|
|
9743
9751
|
var CHECKER_NAME = "dunstan";
|
|
9744
|
-
var CHECKER_VERSION = "0.1.
|
|
9752
|
+
var CHECKER_VERSION = "0.1.8";
|
|
9745
9753
|
function checkerIdentity(artifact) {
|
|
9746
9754
|
return {
|
|
9747
9755
|
name: CHECKER_NAME,
|
|
@@ -10400,7 +10408,7 @@ var FILES = { "handback-block-0.1.schema.json": `{
|
|
|
10400
10408
|
},
|
|
10401
10409
|
"readerReason": {
|
|
10402
10410
|
"type": "string",
|
|
10403
|
-
"pattern": "^(?:no_matching_record_item|declared_item_not_among_candidates|candidate_not_in_evidence|no_comparable_record_field|file_list_truncated|checks_incomplete|all_succeeded_mismatch|test_not_executed|test_outcome_mismatch|evidence_field_unpopulated:[A-Za-z0-9_.]+|source_unreadable:(?:pull_request_files|check_runs|pull_request_commits|timeline|artifact))$"
|
|
10411
|
+
"pattern": "^(?:no_matching_record_item|declared_item_not_among_candidates|candidate_not_in_evidence|ambiguous_candidates|no_comparable_record_field|file_list_truncated|checks_incomplete|all_succeeded_mismatch|test_not_executed|test_outcome_mismatch|not_closing|not_found|closing_link_unsettled|closing_base_not_default|closing_event_unsettled|evidence_field_unpopulated:[A-Za-z0-9_.]+|source_unreadable:(?:pull_request_files|check_runs|pull_request_commits|closing_references|repository|issue|timeline|artifact))$"
|
|
10404
10412
|
}
|
|
10405
10413
|
}
|
|
10406
10414
|
}
|
|
@@ -11409,7 +11417,7 @@ function blockFor(kind, value, headSha) {
|
|
|
11409
11417
|
case "file_changed":
|
|
11410
11418
|
return typeof value === "string" ? { ...base, filesChanged: [value] } : void 0;
|
|
11411
11419
|
case "reference_closes":
|
|
11412
|
-
return typeof value === "string" ?
|
|
11420
|
+
return typeof value === "string" ? closesBlock(value, headSha) : void 0;
|
|
11413
11421
|
case "commit":
|
|
11414
11422
|
return typeof value === "string" && value.length === 40 ? { ...base, references: [{ commit: value, relation: "cites" }] } : void 0;
|
|
11415
11423
|
case "head_commit":
|
|
@@ -12574,7 +12582,7 @@ var FILL_TO_K = "to-k";
|
|
|
12574
12582
|
var ARM_A_FILL = "A-fill";
|
|
12575
12583
|
var BM25_FLOOR = 1;
|
|
12576
12584
|
var SCORE_DECIMALS = 6;
|
|
12577
|
-
function
|
|
12585
|
+
function roundScore(score) {
|
|
12578
12586
|
const scale = 10 ** SCORE_DECIMALS;
|
|
12579
12587
|
return Math.round(score * scale) / scale;
|
|
12580
12588
|
}
|
|
@@ -12622,7 +12630,7 @@ function retrieve(claim2, items, opts) {
|
|
|
12622
12630
|
});
|
|
12623
12631
|
return;
|
|
12624
12632
|
}
|
|
12625
|
-
const score =
|
|
12633
|
+
const score = roundScore(scores[order] ?? 0);
|
|
12626
12634
|
if (!fill && score < BM25_FLOOR) return;
|
|
12627
12635
|
ranked.push({
|
|
12628
12636
|
order,
|
|
@@ -12645,6 +12653,7 @@ var READER_CLAIM_KINDS = /* @__PURE__ */ new Map([
|
|
|
12645
12653
|
["file_changed", "file"],
|
|
12646
12654
|
["commit_present", "commit"],
|
|
12647
12655
|
["reference_in_timeline", "timeline_event"],
|
|
12656
|
+
["reference_closes", "timeline_event"],
|
|
12648
12657
|
["check_succeeded", "check_run"],
|
|
12649
12658
|
["test_passed", "test"]
|
|
12650
12659
|
]);
|
|
@@ -12698,6 +12707,19 @@ function combinedCandidates(typed, floor) {
|
|
|
12698
12707
|
const exact = typed.filter((c) => c.score === null);
|
|
12699
12708
|
return exact.length > 0 ? exact : typed.filter((c) => c.score !== null && c.score >= floor);
|
|
12700
12709
|
}
|
|
12710
|
+
function outcomeOf(type, entry) {
|
|
12711
|
+
if (type === "test") return entry.outcome;
|
|
12712
|
+
const run = entry;
|
|
12713
|
+
if (run.status !== "completed") return "not_completed";
|
|
12714
|
+
return run.conclusion === "success" ? "succeeded" : "failed";
|
|
12715
|
+
}
|
|
12716
|
+
function ambiguousCandidates(combined, outcome) {
|
|
12717
|
+
const scores = combined.map((c) => c.score === null ? null : roundScore(c.score));
|
|
12718
|
+
if (scores.length < 2 || scores.includes(null)) return false;
|
|
12719
|
+
const top = Math.max(...scores);
|
|
12720
|
+
const tied = combined.filter((_, i) => scores[i] === top);
|
|
12721
|
+
return tied.length >= 2 && new Set(tied.map(outcome)).size > 1;
|
|
12722
|
+
}
|
|
12701
12723
|
function checkReaderClaim(claim2, evidence, repository) {
|
|
12702
12724
|
const type = READER_CLAIM_KINDS.get(claim2.kind);
|
|
12703
12725
|
if (type === void 0) return unverifiable2("no_comparable_record_field");
|
|
@@ -12706,6 +12728,13 @@ function checkReaderClaim(claim2, evidence, repository) {
|
|
|
12706
12728
|
if (wantsBoolean ? typeof declared !== "boolean" : typeof declared !== "string") {
|
|
12707
12729
|
return unverifiable2("no_comparable_record_field");
|
|
12708
12730
|
}
|
|
12731
|
+
if (claim2.kind === "reference_closes") {
|
|
12732
|
+
if (!ISSUE_REF2.test(declared)) return unverifiable2("no_comparable_record_field");
|
|
12733
|
+
const head = evidence.pullRequest.headSha;
|
|
12734
|
+
const row = checkReferences(closesBlock(declared, head), evidence, repository)[0];
|
|
12735
|
+
if (row === void 0) return unverifiable2("no_comparable_record_field");
|
|
12736
|
+
return verdictOf(row.verdict, row.observed ?? null, row.reason);
|
|
12737
|
+
}
|
|
12709
12738
|
const missing = sectionReason(type, evidence);
|
|
12710
12739
|
if (missing !== void 0) return unverifiable2(missing);
|
|
12711
12740
|
const entries = lookup(type, evidence);
|
|
@@ -12719,6 +12748,9 @@ function checkReaderClaim(claim2, evidence, repository) {
|
|
|
12719
12748
|
if (relevant.length === 0) {
|
|
12720
12749
|
return unverifiable2(truncated ? "file_list_truncated" : "no_matching_record_item");
|
|
12721
12750
|
}
|
|
12751
|
+
if (wantsBoolean && ambiguousCandidates(relevant, (c) => outcomeOf(type, entries.get(c.id)))) {
|
|
12752
|
+
return unverifiable2("ambiguous_candidates");
|
|
12753
|
+
}
|
|
12722
12754
|
switch (type) {
|
|
12723
12755
|
case "file": {
|
|
12724
12756
|
const files = observed;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dunstan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"mcpName": "io.github.BargLabs/dunstan",
|
|
5
5
|
"description": "Holds a coding agent's completion report to the record: deterministic checks of a declared handback block against the repository's own metadata.",
|
|
6
6
|
"license": "AGPL-3.0-only",
|