madeby 0.3.3 → 0.3.5

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.
Files changed (2) hide show
  1. package/dist/madeby.mjs +113 -48
  2. package/package.json +1 -1
package/dist/madeby.mjs CHANGED
@@ -1880,47 +1880,57 @@ function whoCommand(args) {
1880
1880
  }
1881
1881
 
1882
1882
  // src/init-repo.ts
1883
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
1883
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
1884
1884
  import { dirname as dirname2, join as join5 } from "node:path";
1885
- var GH_WORKFLOW = `name: Disclosure
1886
- on: pull_request
1887
- jobs:
1888
- madeby:
1889
- runs-on: ubuntu-latest
1890
- steps:
1891
- - uses: actions/checkout@v4
1892
- with:
1893
- fetch-depth: 0
1894
- - uses: MadeByFYI/MadeBy/packages/action@v0.2.0
1895
- `;
1896
- var AGENTS_CONVENTION = `# AGENTS.md \u2014 Authorship disclosure convention (ACO)
1897
-
1898
- This repository asks any AI agent \u2014 or a human working with one \u2014 to **disclose who authored the
1899
- changes they make**, per **ACO, the Authorship Certificate of Origin**
1900
- (https://github.com/MadeByFYI/MadeBy/blob/main/ACO.md).
1901
-
1902
- ## The rule
1903
-
1904
- When you author or modify content here, disclose the authorship **category** on your commit \u2014 one of:
1905
-
1906
- - \`human\` \u2014 a human authored it, no AI involvement.
1907
- - \`with_ai\` \u2014 a human authored it with disclosed AI assistance.
1908
- - \`ai\` \u2014 an AI agent authored it (a human remains accountable).
1885
+ var ACO_VERSION = 1;
1886
+ var ACO_OPEN = `<!-- madeby:aco v${ACO_VERSION} -->`;
1887
+ var ACO_CLOSE = `<!-- /madeby:aco -->`;
1888
+ var ACO_OPEN_RE = /<!-- madeby:aco(?: v(\d+))? -->/;
1889
+ var ACO_BODY = `## Authorship disclosure (ACO)
1909
1890
 
1910
- Disclose **per commit, honestly** \u2014 the category describes what actually happened for that change.
1891
+ When you author or modify content here, **disclose who authored it** \u2014 per
1892
+ [ACO, the Authorship Certificate of Origin](https://github.com/MadeByFYI/MadeBy/blob/main/ACO.md).
1893
+ After you commit, run the command for the honest category (no install, no setup):
1911
1894
 
1912
- ## The one-line way (asserted tier \u2014 no keys, no setup)
1895
+ - **ai** \u2014 an AI authored it (the committer stays accountable): \`npx madeby@latest ai [tool]\`
1896
+ - **with_ai** \u2014 a human authored it with AI assistance: \`npx madeby@latest me --with-ai [tool]\`
1897
+ - **human** \u2014 a human authored it: \`npx madeby@latest me\`
1913
1898
 
1914
- After you commit, run the matching command (works with no install via \`npx\`):
1915
-
1916
- | Category | Command |
1917
- |-----------|----------------------------------|
1918
- | \`human\` | \`npx madeby@latest me\` |
1919
- | \`with_ai\` | \`npx madeby@latest me --with-ai <tool>\` |
1920
- | \`ai\` | \`npx madeby@latest ai [tool]\` |
1921
-
1922
- Undisclosed content stays *unknown*, never guessed. See ACO for the standard.
1899
+ Disclose per commit, honestly. Undisclosed content stays *unknown*, never guessed.
1923
1900
  `;
1901
+ var ACO_BLOCK = `${ACO_OPEN}
1902
+ ${ACO_BODY}${ACO_CLOSE}
1903
+ `;
1904
+ var AGENTS_CONVENTION = `# AGENTS.md
1905
+
1906
+ ${ACO_BLOCK}`;
1907
+ var ACO_SECTION = `
1908
+ ${ACO_BLOCK}`;
1909
+ function findAcoBlock(content) {
1910
+ const m = ACO_OPEN_RE.exec(content);
1911
+ if (!m) return null;
1912
+ const start = m.index;
1913
+ const version = m[1] !== void 0 ? Number(m[1]) : null;
1914
+ const closeIdx = content.indexOf(ACO_CLOSE, start);
1915
+ let end;
1916
+ if (closeIdx !== -1) {
1917
+ end = closeIdx + ACO_CLOSE.length;
1918
+ if (content[end] === "\n") end += 1;
1919
+ } else {
1920
+ end = content.length;
1921
+ }
1922
+ return { version, start, end };
1923
+ }
1924
+ function acoStatus(content) {
1925
+ const loc = findAcoBlock(content);
1926
+ if (!loc) return "absent";
1927
+ if (loc.version === null || loc.version < ACO_VERSION) return "outdated";
1928
+ if (loc.version > ACO_VERSION) return "newer";
1929
+ return "current";
1930
+ }
1931
+ function replaceAcoBlock(content, loc) {
1932
+ return content.slice(0, loc.start) + ACO_BLOCK + content.slice(loc.end);
1933
+ }
1924
1934
  function writeIfAbsent(abs, rel, content, created, skipped) {
1925
1935
  if (existsSync4(abs)) {
1926
1936
  skipped.push(rel);
@@ -1930,21 +1940,59 @@ function writeIfAbsent(abs, rel, content, created, skipped) {
1930
1940
  writeFileSync2(abs, content);
1931
1941
  created.push(rel);
1932
1942
  }
1943
+ function ensureAco(abs, rel, res, opts) {
1944
+ if (!existsSync4(abs)) {
1945
+ if (!opts.createIfAbsent) return;
1946
+ mkdirSync2(dirname2(abs), { recursive: true });
1947
+ writeFileSync2(abs, AGENTS_CONVENTION);
1948
+ res.created.push(rel);
1949
+ return;
1950
+ }
1951
+ const content = readFileSync6(abs, "utf8");
1952
+ const status = acoStatus(content);
1953
+ if (status === "absent") {
1954
+ const sep = content.endsWith("\n") ? "" : "\n";
1955
+ writeFileSync2(abs, content + sep + ACO_SECTION);
1956
+ res.merged.push(rel);
1957
+ } else if (status === "outdated") {
1958
+ if (opts.update) {
1959
+ writeFileSync2(abs, replaceAcoBlock(content, findAcoBlock(content)));
1960
+ res.updated.push(rel);
1961
+ } else {
1962
+ res.outdated.push(rel);
1963
+ }
1964
+ } else {
1965
+ res.skipped.push(rel);
1966
+ }
1967
+ }
1933
1968
  function initRepo(root, opts = {}) {
1934
1969
  const mode = opts.mode ?? "advisory";
1935
1970
  const host = opts.host ?? "github";
1971
+ const update = opts.update ?? false;
1936
1972
  const created = [];
1937
1973
  const skipped = [];
1974
+ const merged = [];
1975
+ const updated = [];
1976
+ const outdated = [];
1977
+ const res = { created, skipped, merged, updated, outdated };
1938
1978
  writeIfAbsent(join5(root, ".madeby", "policy.json"), ".madeby/policy.json", JSON.stringify({ version: 0, mode }, null, 2) + "\n", created, skipped);
1939
- writeIfAbsent(join5(root, "AGENTS.md"), "AGENTS.md", AGENTS_CONVENTION, created, skipped);
1979
+ ensureAco(join5(root, "AGENTS.md"), "AGENTS.md", res, { createIfAbsent: true, update });
1980
+ ensureAco(join5(root, "CLAUDE.md"), "CLAUDE.md", res, { createIfAbsent: false, update });
1940
1981
  if (host === "github") {
1941
1982
  writeIfAbsent(join5(root, ".github", "workflows", "disclosure.yml"), ".github/workflows/disclosure.yml", GH_WORKFLOW, created, skipped);
1942
1983
  }
1943
1984
  const nextSteps = ["Commit the created files."];
1944
1985
  if (created.includes("AGENTS.md")) {
1945
- nextSteps.push("An AGENTS.md ACO convention was added \u2014 agents that read it disclose authorship (e.g. 'npx madeby@latest me --with-ai <tool>'). Tune it to your repo's tools.");
1946
- } else if (skipped.includes("AGENTS.md")) {
1947
- nextSteps.push("You already have an AGENTS.md \u2014 add the ACO disclosure rule to it (reference: https://github.com/MadeByFYI/MadeBy/blob/main/AGENTS.md).");
1986
+ nextSteps.push("An AGENTS.md ACO convention was added \u2014 agents that read it disclose authorship (e.g. 'npx madeby@latest ai [tool]'). Tune it to your repo's tools.");
1987
+ }
1988
+ if (merged.length > 0) {
1989
+ nextSteps.push(`Merged the ACO disclosure rule into your existing ${merged.join(" + ")} \u2014 review the appended "Authorship disclosure (ACO)" section and tune it to your repo.`);
1990
+ }
1991
+ if (updated.length > 0) {
1992
+ nextSteps.push(`Refreshed an outdated ACO convention in ${updated.join(" + ")} to the current version \u2014 review the change before committing.`);
1993
+ }
1994
+ if (outdated.length > 0) {
1995
+ nextSteps.push(`${outdated.join(" + ")} carries an OUTDATED ACO convention \u2014 run 'madeby init --update' to refresh it in place (only the ACO block changes).`);
1948
1996
  }
1949
1997
  if (host === "azure-devops") {
1950
1998
  nextSteps.push("Add the Azure Pipelines template (packages/action/azure-pipelines-disclosure.yml) and wire it as a PR build-validation branch policy.");
@@ -1956,8 +2004,19 @@ function initRepo(root, opts = {}) {
1956
2004
  }
1957
2005
  nextSteps.push("Contributors disclose origin with a Co-Authored-By / Generated-by trailer (AI), an Authored-by-human trailer ('madeby me'), an Authored-by-ai trailer ('madeby ai' \u2014 AI authored, committer accountable), a DCO Signed-off-by, or a signed commit. Evidence upgrade: 'madeby ai --witness' records your own AI session's witnessed spans.");
1958
2006
  nextSteps.push("Existing history is accounted for honestly, not fabricated: run 'madeby check' over full history to recognize what's already disclosed; pre-adoption commits stay unknown. See madeby://guide/backfill.");
1959
- return { created, skipped, policyMode: mode, host, nextSteps };
2007
+ return { created, skipped, merged, updated, outdated, policyMode: mode, host, nextSteps };
1960
2008
  }
2009
+ var GH_WORKFLOW = `name: Disclosure
2010
+ on: pull_request
2011
+ jobs:
2012
+ madeby:
2013
+ runs-on: ubuntu-latest
2014
+ steps:
2015
+ - uses: actions/checkout@v4
2016
+ with:
2017
+ fetch-depth: 0
2018
+ - uses: MadeByFYI/MadeBy/packages/action@v0.2.0
2019
+ `;
1961
2020
 
1962
2021
  // src/commands/init.ts
1963
2022
  function initCommand(args) {
@@ -1968,10 +2027,14 @@ function initCommand(args) {
1968
2027
  return;
1969
2028
  }
1970
2029
  const mode = args.includes("--required") ? "required" : "advisory";
2030
+ const update = args.includes("--update");
1971
2031
  const hostIdx = args.indexOf("--host");
1972
2032
  const host = hostIdx >= 0 ? args[hostIdx + 1] : void 0;
1973
- const r = initRepo(root, { mode, host });
2033
+ const r = initRepo(root, { mode, host, update });
1974
2034
  for (const f of r.created) console.log(` + ${f}`);
2035
+ for (const f of r.merged) console.log(` ~ ${f} (merged in the ACO rule)`);
2036
+ for (const f of r.updated) console.log(` \u2191 ${f} (ACO convention refreshed to the current version)`);
2037
+ for (const f of r.outdated) console.log(` ! ${f} (ACO convention OUTDATED \u2014 run 'madeby init --update')`);
1975
2038
  for (const f of r.skipped) console.log(` \xB7 ${f} (exists \u2014 left as-is)`);
1976
2039
  console.log(`
1977
2040
  madeby init \u2014 policy: ${r.policyMode}, host: ${r.host}`);
@@ -1983,7 +2046,7 @@ madeby init \u2014 policy: ${r.policyMode}, host: ${r.host}`);
1983
2046
  import { execFileSync as execFileSync6 } from "node:child_process";
1984
2047
  import { createInterface } from "node:readline";
1985
2048
  var DEFAULT_PROTOCOL = "2024-11-05";
1986
- var SERVER_INFO = { name: "madeby", version: "0.3.3" };
2049
+ var SERVER_INFO = { name: "madeby", version: "0.3.5" };
1987
2050
  function rootFor(path) {
1988
2051
  const cwd = path && path.length ? path : process.cwd();
1989
2052
  return execFileSync6("git", ["-C", cwd, "-c", "core.quotePath=false", "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
@@ -1998,16 +2061,17 @@ var repoInput = {
1998
2061
  var TOOLS = [
1999
2062
  {
2000
2063
  name: "init",
2001
- description: "Align a repository with MadeBy in one call: create .madeby/policy.json (advisory by default \u2014 reports, never fails) and the CI disclosure check for the host (github default; azure-devops guided). Idempotent \u2014 never clobbers an existing policy or workflow. Returns the files created/skipped and the recommended next steps. Read the resources: madeby://guide/align (full workflow), madeby://guide/enforce (make the check required \u2014 the host's control plane, exact commands), madeby://guide/backfill (account for existing history honestly \u2014 never fabricate).",
2064
+ description: "Align a repository with MadeBy in one call: create .madeby/policy.json (advisory by default \u2014 reports, never fails) and the CI disclosure check for the host (github default; azure-devops guided). Idempotent \u2014 never clobbers an existing policy or workflow. Returns the files created/skipped and the recommended next steps. Read the resources: madeby://guide/align (full workflow), madeby://guide/enforce (make the check required \u2014 the host's control plane, exact commands), madeby://guide/backfill (account for existing history honestly \u2014 never fabricate). The ACO convention block is versioned: the result flags an `outdated` AGENTS.md/CLAUDE.md (drift); call again with update:true to refresh just that block in place \u2014 how an agent keeps the convention current.",
2002
2065
  inputSchema: {
2003
2066
  type: "object",
2004
2067
  properties: {
2005
2068
  path: { type: "string", description: "path to the repo (default: the server's working directory)" },
2006
2069
  mode: { enum: ["advisory", "required"], description: "policy mode to seed (default: advisory)" },
2007
- host: { type: "string", description: "CI host to wire: github (default) or azure-devops" }
2070
+ host: { type: "string", description: "CI host to wire: github (default) or azure-devops" },
2071
+ update: { type: "boolean", description: "refresh an outdated ACO convention block in place (drift update); default false (report only)" }
2008
2072
  }
2009
2073
  },
2010
- handler: (args) => initRepo(rootFor(args.path), { mode: args.mode, host: args.host })
2074
+ handler: (args) => initRepo(rootFor(args.path), { mode: args.mode, host: args.host, update: args.update })
2011
2075
  },
2012
2076
  {
2013
2077
  name: "check",
@@ -2270,8 +2334,9 @@ function help() {
2270
2334
  console.log(`madeby \u2014 verifiable content provenance ("made by whom?")
2271
2335
 
2272
2336
  Usage:
2273
- madeby init Set MadeBy up: write .madeby/policy.json + the CI disclosure check.
2274
- --required to enforce now; --host azure-devops for Azure Pipelines.
2337
+ madeby init Set MadeBy up: write .madeby/policy.json + the ACO AGENTS.md convention
2338
+ + the CI disclosure check. --update refreshes an outdated ACO block in
2339
+ place; --required to enforce now; --host azure-devops for Azure Pipelines.
2275
2340
  madeby check [<range>] The gate: do commits meet .madeby/policy.json? (a verdict \u2014 exit
2276
2341
  code gates). <range> e.g. origin/main..HEAD; in CI it's auto-detected.
2277
2342
  --json for a machine-readable result.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "madeby",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
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",