madeby 0.3.7 → 0.3.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 +3 -1
- package/dist/madeby.mjs +50 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,7 +103,9 @@ authorship coverage — last 500 commits (estimate · disclosure, not detection
|
|
|
103
103
|
It is a **labeled estimate**, honest by construction: an undisclosed commit is **unknown**, never
|
|
104
104
|
inferred as human — disclosure, not detection. The human/with_ai/ai mix is reported *of the known*,
|
|
105
105
|
never of the whole repo, and the asserted-vs-verified split shows how much is signed. `--json` emits
|
|
106
|
-
counts only (percentages are derived at the edge, never stored).
|
|
106
|
+
counts only (percentages are derived at the edge, never stored). A plain merge authors nothing and
|
|
107
|
+
isn't scored; a merge that changes content of its own (a conflict resolution) is, like any other
|
|
108
|
+
commit — chosen by what it changes, never by whether it discloses. Use it to see your gap, then
|
|
107
109
|
`madeby init --required` to close it going forward.
|
|
108
110
|
|
|
109
111
|
### `madeby me` — affirm human authorship
|
package/dist/madeby.mjs
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
var FIELD = "";
|
|
6
6
|
var RECORD = "";
|
|
7
|
+
var GROUP = "";
|
|
8
|
+
var parseMeta = (rec) => {
|
|
9
|
+
const parts = rec.split(FIELD);
|
|
10
|
+
const sig = parts[3] ?? "N";
|
|
11
|
+
return {
|
|
12
|
+
sha: parts[0] ?? "",
|
|
13
|
+
authorName: parts[1] ?? "",
|
|
14
|
+
authorEmail: parts[2] ?? "",
|
|
15
|
+
signed: sig !== "N" && sig !== "",
|
|
16
|
+
message: parts.slice(4).join(FIELD).trimEnd()
|
|
17
|
+
};
|
|
18
|
+
};
|
|
7
19
|
function readGitLog(repoPath, limit, range) {
|
|
8
20
|
try {
|
|
9
21
|
const args = [
|
|
@@ -11,7 +23,7 @@ function readGitLog(repoPath, limit, range) {
|
|
|
11
23
|
repoPath,
|
|
12
24
|
"log",
|
|
13
25
|
"--no-merges",
|
|
14
|
-
// merge
|
|
26
|
+
// a merge is not authored content by default; readAuthoredMerges finds those that are
|
|
15
27
|
...limit ? ["-n", String(limit)] : [],
|
|
16
28
|
// %G? is a signature-PRESENCE probe for the Disclosure Score: 'N' = unsigned; any other code
|
|
17
29
|
// (G/U/E/…) = a signature is present (E = present but unverifiable here — no keyring). We only
|
|
@@ -22,19 +34,38 @@ function readGitLog(repoPath, limit, range) {
|
|
|
22
34
|
...range ? [range] : []
|
|
23
35
|
];
|
|
24
36
|
const out = execFileSync("git", args, { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] });
|
|
25
|
-
return out.split(RECORD).map((r) => r.replace(/^\s+/, "")).filter((r) => r.length > 0).map(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
return out.split(RECORD).map((r) => r.replace(/^\s+/, "")).filter((r) => r.length > 0).map(parseMeta);
|
|
38
|
+
} catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function readAuthoredMerges(repoPath, opts = {}) {
|
|
43
|
+
try {
|
|
44
|
+
const args = [
|
|
45
|
+
"-C",
|
|
46
|
+
repoPath,
|
|
47
|
+
"log",
|
|
48
|
+
"--merges",
|
|
49
|
+
"--cc",
|
|
50
|
+
"--name-only",
|
|
51
|
+
`--format=${RECORD}%H${FIELD}%an${FIELD}%ae${FIELD}%G?${FIELD}%B${GROUP}`,
|
|
52
|
+
...opts.since !== void 0 && !opts.range ? [`--since=@${opts.since}`] : [],
|
|
53
|
+
...opts.range ? [opts.range] : []
|
|
54
|
+
];
|
|
55
|
+
const out = execFileSync("git", args, { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] });
|
|
56
|
+
return out.split(RECORD).filter((r) => r.includes(GROUP)).filter((r) => r.slice(r.lastIndexOf(GROUP) + 1).trim().length > 0).map((r) => parseMeta(r.slice(0, r.lastIndexOf(GROUP))));
|
|
34
57
|
} catch {
|
|
35
58
|
return [];
|
|
36
59
|
}
|
|
37
60
|
}
|
|
61
|
+
function commitTime(repoPath, sha) {
|
|
62
|
+
try {
|
|
63
|
+
const t = Number(execFileSync("git", ["-C", repoPath, "log", "-1", "--format=%ct", sha], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim());
|
|
64
|
+
return Number.isFinite(t) && t > 0 ? t : void 0;
|
|
65
|
+
} catch {
|
|
66
|
+
return void 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
38
69
|
|
|
39
70
|
// ../classify/src/classify.ts
|
|
40
71
|
var AI_PATTERNS = [
|
|
@@ -1201,7 +1232,12 @@ function provenanceMap(root, opts = {}) {
|
|
|
1201
1232
|
|
|
1202
1233
|
// ../analyzer/src/coverage.ts
|
|
1203
1234
|
function repoCoverage(root, opts = {}) {
|
|
1204
|
-
const
|
|
1235
|
+
const limit = opts.range ? void 0 : opts.limit ?? 500;
|
|
1236
|
+
const authored = readGitLog(root, limit, opts.range);
|
|
1237
|
+
const oldest = authored.at(-1)?.sha;
|
|
1238
|
+
const since = limit && oldest && authored.length >= limit ? commitTime(root, oldest) : void 0;
|
|
1239
|
+
const merges = authored.length > 0 && (!limit || authored.length < limit || since !== void 0) ? readAuthoredMerges(root, { range: opts.range, since }) : [];
|
|
1240
|
+
const commits = [...authored, ...merges];
|
|
1205
1241
|
const byCategory = { human: 0, with_ai: 0, ai: 0, bot: 0 };
|
|
1206
1242
|
const byTier = { asserted: 0, verified: 0 };
|
|
1207
1243
|
let known = 0;
|
|
@@ -1217,8 +1253,8 @@ function repoCoverage(root, opts = {}) {
|
|
|
1217
1253
|
}
|
|
1218
1254
|
return {
|
|
1219
1255
|
isEstimate: true,
|
|
1220
|
-
methodology: "commit-level authorship disclosure (estimate); undisclosed = unknown, never inferred",
|
|
1221
|
-
scope: opts.range ? `range ${opts.range}` : `last ${commits.length}
|
|
1256
|
+
methodology: "commit-level authorship disclosure (estimate); undisclosed = unknown, never inferred; merges scored only when they change content of their own",
|
|
1257
|
+
scope: (opts.range ? `range ${opts.range}` : `last ${authored.length} commits`) + (merges.length ? ` + ${merges.length} merges with changes of their own` : ""),
|
|
1222
1258
|
total: commits.length,
|
|
1223
1259
|
known,
|
|
1224
1260
|
unknown: commits.length - known,
|
|
@@ -2247,7 +2283,7 @@ madeby init \u2014 policy: ${r.policyMode}, host: ${r.host}`);
|
|
|
2247
2283
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
2248
2284
|
import { createInterface } from "node:readline";
|
|
2249
2285
|
var DEFAULT_PROTOCOL = "2024-11-05";
|
|
2250
|
-
var SERVER_INFO = { name: "madeby", version: "0.3.
|
|
2286
|
+
var SERVER_INFO = { name: "madeby", version: "0.3.8" };
|
|
2251
2287
|
function rootFor(path) {
|
|
2252
2288
|
const cwd = path && path.length ? path : process.cwd();
|
|
2253
2289
|
return execFileSync6("git", ["-C", cwd, "-c", "core.quotePath=false", "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "madeby",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"mcpName": "io.github.MadeByFYI/madeby",
|
|
5
5
|
"description": "Disclose AI authorship of code. `npx madeby ai` adds an Authored-by-ai git trailer; AI coding agents disclose per the ACO standard (human/with_ai/ai) from an AGENTS.md convention. Disclosure, not detection. Gate PRs with `madeby check`.",
|
|
6
6
|
"license": "MIT",
|