@kungfu-tech/buildchain 3.0.3 → 3.0.4-alpha.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.
@@ -31,8 +31,33 @@ import {
31
31
  sha256Text,
32
32
  stableJson,
33
33
  } from "./paper-repository.js";
34
+ import {
35
+ PAPER_AGENT_ENTRY_CONTRACT,
36
+ collectPaperAgentEntry,
37
+ paperAgentEntryFiles,
38
+ } from "./paper-agent-entry.js";
39
+ import {
40
+ managedPaperPackageJson,
41
+ scaffoldMainTex,
42
+ scaffoldMakefile,
43
+ scaffoldMap,
44
+ scaffoldPackageJson,
45
+ scaffoldReadme,
46
+ } from "./paper-scaffold-content.js";
34
47
 
35
48
  export { PAPER_PATHS, resolvePaperRepository } from "./paper-repository.js";
49
+ export {
50
+ PAPER_AGENT_ENTRY_CONTRACT,
51
+ PAPER_AGENT_ENTRY_SCHEMA_VERSION,
52
+ PAPER_AGENT_ENTRY_SECTION_END,
53
+ PAPER_AGENT_ENTRY_SECTION_START,
54
+ collectPaperAgentEntry,
55
+ createPaperAgentEntry,
56
+ mergePaperAgentEntryInstructions,
57
+ paperAgentEntryFiles,
58
+ paperAgentEntryInstructions,
59
+ resolvePaperBuildchainSha,
60
+ } from "./paper-agent-entry.js";
36
61
  export {
37
62
  PAPER_WORK_START_PLAN_CONTRACT,
38
63
  PAPER_WORK_SUBMIT_PLAN_CONTRACT,
@@ -79,9 +104,12 @@ export const PAPER_STATE_ORDER = Object.freeze([
79
104
 
80
105
  const PAPER_SCAFFOLD_PATHS = Object.freeze([
81
106
  PAPER_PATHS.config,
107
+ PAPER_PATHS.agentEntry,
108
+ PAPER_PATHS.agentInstructions,
82
109
  PAPER_PATHS.contractLock,
83
110
  PAPER_PATHS.versionPin,
84
111
  PAPER_PATHS.buildWorkflow,
112
+ PAPER_PATHS.verifyWorkflow,
85
113
  PAPER_PATHS.releaseWorkflow,
86
114
  PAPER_PATHS.provisioningAuthority,
87
115
  "Makefile",
@@ -227,18 +255,6 @@ function tomlString(value) {
227
255
  return JSON.stringify(String(value || ""));
228
256
  }
229
257
 
230
- function texEscape(value) {
231
- return String(value || "")
232
- .replaceAll("\\", "\\textbackslash{}")
233
- .replaceAll("&", "\\&")
234
- .replaceAll("%", "\\%")
235
- .replaceAll("$", "\\$")
236
- .replaceAll("#", "\\#")
237
- .replaceAll("_", "\\_")
238
- .replaceAll("{", "\\{")
239
- .replaceAll("}", "\\}");
240
- }
241
-
242
258
  function joinUrl(base, suffix = "") {
243
259
  const normalizedBase = String(base || "")
244
260
  .trim()
@@ -334,6 +350,31 @@ jobs:
334
350
  `;
335
351
  }
336
352
 
353
+ function scaffoldVerifyWorkflow(buildchainSha) {
354
+ return `name: Verify
355
+
356
+ on:
357
+ pull_request:
358
+ push:
359
+ branches:
360
+ - "dev/v*/v*"
361
+ - "alpha/v*/v*"
362
+ - "release/v*/v*"
363
+ workflow_dispatch:
364
+
365
+ permissions:
366
+ contents: read
367
+
368
+ jobs:
369
+ check:
370
+ uses: kungfu-systems/buildchain/.github/workflows/check.yml@${buildchainSha}
371
+ with:
372
+ buildchain-ref: ${buildchainSha}
373
+ require-version-state: true
374
+ upload-artifacts: true
375
+ `;
376
+ }
377
+
337
378
  function scaffoldReleaseWorkflow(
338
379
  buildchainSha,
339
380
  { artifactPaths = "_build/main.pdf", releasePassportProductName = "" } = {},
@@ -413,7 +454,10 @@ export function createPaperProvisioningAuthority({
413
454
  buildchainSha,
414
455
  contractLock,
415
456
  buildWorkflow,
457
+ verifyWorkflow,
416
458
  releaseWorkflow,
459
+ agentEntry,
460
+ agentInstructions,
417
461
  environment = "",
418
462
  }) {
419
463
  const policy = paperProvisioningPolicy();
@@ -439,6 +483,12 @@ export function createPaperProvisioningAuthority({
439
483
  reusablePath: ".github/workflows/publication-artifact.yml",
440
484
  reusableRef: buildchainSha,
441
485
  },
486
+ verify: {
487
+ path: PAPER_PATHS.verifyWorkflow,
488
+ sourceDigest: sha256Text(verifyWorkflow),
489
+ reusablePath: ".github/workflows/check.yml",
490
+ reusableRef: buildchainSha,
491
+ },
442
492
  release: {
443
493
  path: PAPER_PATHS.releaseWorkflow,
444
494
  sourceDigest: sha256Text(releaseWorkflow),
@@ -446,6 +496,13 @@ export function createPaperProvisioningAuthority({
446
496
  reusableRef: buildchainSha,
447
497
  },
448
498
  },
499
+ agentEntry: {
500
+ contract: PAPER_AGENT_ENTRY_CONTRACT,
501
+ policyPath: PAPER_PATHS.agentEntry,
502
+ policyDigest: sha256Text(agentEntry),
503
+ instructionsPath: PAPER_PATHS.agentInstructions,
504
+ instructionsDigest: sha256Text(agentInstructions),
505
+ },
449
506
  admission: {
450
507
  contractLockPath: PAPER_PATHS.contractLock,
451
508
  contractLockDigest: sha256Text(contractLock),
@@ -469,150 +526,6 @@ export function createPaperProvisioningAuthority({
469
526
  };
470
527
  }
471
528
 
472
- function scaffoldMakefile() {
473
- const image = `${DEFAULT_TOOLCHAIN_IMAGE}@${DEFAULT_TOOLCHAIN_DIGEST}`;
474
- return `.PHONY: check pdf clean
475
-
476
- BUILDER_IMAGE := ${image}
477
- SOURCE_DATE_EPOCH ?= 0
478
-
479
- check:
480
- \t@test -f paper/main.tex
481
- \t@test -f paper/references.bib
482
- \t@git diff --check
483
-
484
- pdf:
485
- \t@mkdir -p _build
486
- \tdocker run --rm --network=none \\
487
- \t\t-e SOURCE_DATE_EPOCH="$(SOURCE_DATE_EPOCH)" \\
488
- \t\t-e TZ=UTC -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -e HOME=/tmp \\
489
- \t\t-v "$(CURDIR):/workspace" -w /workspace \\
490
- \t\t"$(BUILDER_IMAGE)" bash -lc '${DEFAULT_TOOLCHAIN_COMMAND}'
491
-
492
- clean:
493
- \trm -rf _build
494
- `;
495
- }
496
-
497
- function paperPackageScripts(current = {}) {
498
- return {
499
- ...current,
500
- "buildchain:paper": "buildchain paper",
501
- "paper:preflight": "buildchain paper preflight --json",
502
- "paper:work:start": "buildchain paper work start",
503
- "paper:work:submit": "buildchain paper work submit",
504
- "paper:status": "buildchain paper status --json",
505
- };
506
- }
507
-
508
- function managedPaperPackageJson(current, buildchainVersion) {
509
- if (!/^3\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(buildchainVersion)) {
510
- throw new Error(
511
- "paper repositories require an exact Buildchain v3 version",
512
- );
513
- }
514
- const packageManager = current.packageManager || "pnpm@11.7.0";
515
- if (!packageManager.startsWith("pnpm@")) {
516
- throw new Error("paper repositories require a pnpm packageManager");
517
- }
518
- return {
519
- ...current,
520
- private: true,
521
- scripts: paperPackageScripts(current.scripts),
522
- devDependencies: {
523
- ...(current.devDependencies || {}),
524
- "@kungfu-tech/buildchain": buildchainVersion,
525
- },
526
- packageManager,
527
- };
528
- }
529
-
530
- function scaffoldPackageJson({
531
- name,
532
- packageName,
533
- repository,
534
- buildchainVersion,
535
- }) {
536
- return jsonText({
537
- ...managedPaperPackageJson(
538
- {
539
- name: packageName,
540
- description: `${name} publication source repository.`,
541
- repository: {
542
- type: "git",
543
- url: `git+https://github.com/${repository}.git`,
544
- },
545
- license: "Apache-2.0",
546
- },
547
- buildchainVersion,
548
- ),
549
- });
550
- }
551
-
552
- function scaffoldReadme({ title, packageName }) {
553
- return `# ${title}
554
-
555
- This repository is a Buildchain-governed publication artifact source.
556
-
557
- ## Local workflow
558
-
559
- \`\`\`sh
560
- pnpm paper:preflight
561
- pnpm paper:work:start -- <topic>
562
- pnpm paper:work:submit
563
- make pdf
564
- \`\`\`
565
-
566
- The public package identity is \`${packageName}\`. Buildchain owns reproducible
567
- artifact generation, sealed publication, npm Trusted Publishing, and recovery;
568
- this repository owns the paper source and review history.
569
-
570
- See [docs/MAP.md](docs/MAP.md) for the repository map.
571
- `;
572
- }
573
-
574
- function scaffoldMap() {
575
- return `# Repository Map
576
-
577
- - \`paper/main.tex\`: paper source entrypoint.
578
- - \`paper/references.bib\`: bibliography source.
579
- - \`.buildchain/buildchain.toml\`: publication identity, toolchain, package, and lifecycle contract.
580
- - \`.buildchain/contract-lock.json\`: accepted Buildchain runtime contract.
581
- - \`.github/workflows/build.yml\`: thin read-only build and reproducibility caller.
582
- - \`.github/workflows/paper-release.yml\`: thin protected sealed-release caller.
583
-
584
- The repository does not own npm transaction logic, publication authority,
585
- release-state recovery, or site deployment mechanics. Those remain Buildchain,
586
- npm/GitHub, and downstream site responsibilities respectively.
587
- `;
588
- }
589
-
590
- function scaffoldMainTex(title) {
591
- return `\\documentclass[11pt]{article}
592
- \\usepackage[T1]{fontenc}
593
- \\usepackage{lmodern}
594
- \\usepackage{hyperref}
595
-
596
- \\title{${texEscape(title)}}
597
- \\author{}
598
- \\date{}
599
-
600
- \\begin{document}
601
- \\maketitle
602
-
603
- \\begin{abstract}
604
- Replace this paragraph with the paper abstract.
605
- \\end{abstract}
606
-
607
- \\section{Introduction}
608
- Replace this section with the reviewed paper content.
609
-
610
- \\bibliographystyle{plain}
611
- \\bibliography{paper/references}
612
- \\end{document}
613
- `;
614
- }
615
-
616
529
  function scaffoldFiles({
617
530
  buildchainRoot,
618
531
  buildchainVersion,
@@ -647,6 +560,15 @@ function scaffoldFiles({
647
560
  artifactPaths: "_build/main.pdf",
648
561
  releasePassportProductName: title,
649
562
  });
563
+ const verifyWorkflow = scaffoldVerifyWorkflow(buildchainSha);
564
+ const agentEntry = paperAgentEntryFiles({
565
+ cwd,
566
+ buildchainVersion,
567
+ buildchainSha,
568
+ developmentRef: `dev/v${parsePaperVersion(version).major}/v${
569
+ parsePaperVersion(version).major
570
+ }.${parsePaperVersion(version).minor}`,
571
+ });
650
572
  const provisioningAuthority = createPaperProvisioningAuthority({
651
573
  repository,
652
574
  packageName,
@@ -654,7 +576,10 @@ function scaffoldFiles({
654
576
  buildchainSha,
655
577
  contractLock: contractLockText,
656
578
  buildWorkflow,
579
+ verifyWorkflow,
657
580
  releaseWorkflow,
581
+ agentEntry: agentEntry.get(PAPER_PATHS.agentEntry),
582
+ agentInstructions: agentEntry.get(PAPER_PATHS.agentInstructions),
658
583
  });
659
584
  const licenseText = runtimeLicenseText(buildchainRoot);
660
585
  return new Map([
@@ -671,9 +596,18 @@ function scaffoldFiles({
671
596
  [PAPER_PATHS.contractLock, contractLockText],
672
597
  [PAPER_PATHS.versionPin, `${buildchainVersion}\n`],
673
598
  [PAPER_PATHS.buildWorkflow, buildWorkflow],
599
+ [PAPER_PATHS.verifyWorkflow, verifyWorkflow],
674
600
  [PAPER_PATHS.releaseWorkflow, releaseWorkflow],
675
601
  [PAPER_PATHS.provisioningAuthority, jsonText(provisioningAuthority)],
676
- ["Makefile", scaffoldMakefile()],
602
+ ...agentEntry,
603
+ [
604
+ "Makefile",
605
+ scaffoldMakefile({
606
+ image: DEFAULT_TOOLCHAIN_IMAGE,
607
+ digest: DEFAULT_TOOLCHAIN_DIGEST,
608
+ command: DEFAULT_TOOLCHAIN_COMMAND,
609
+ }),
610
+ ],
677
611
  [
678
612
  "package.json",
679
613
  scaffoldPackageJson({
@@ -957,6 +891,12 @@ function migrationFiles({
957
891
  artifactPaths: config.publication.artifactPaths.join(","),
958
892
  releasePassportProductName: config.publication.title,
959
893
  });
894
+ const verifyWorkflow = scaffoldVerifyWorkflow(runtimeSha);
895
+ const agentEntry = paperAgentEntryFiles({
896
+ cwd,
897
+ buildchainVersion: runtimeIdentity.version,
898
+ buildchainSha: runtimeSha,
899
+ });
960
900
  const provisioningAuthority = createPaperProvisioningAuthority({
961
901
  repository,
962
902
  packageName,
@@ -964,7 +904,10 @@ function migrationFiles({
964
904
  buildchainSha: runtimeSha,
965
905
  contractLock: contractLockText,
966
906
  buildWorkflow,
907
+ verifyWorkflow,
967
908
  releaseWorkflow,
909
+ agentEntry: agentEntry.get(PAPER_PATHS.agentEntry),
910
+ agentInstructions: agentEntry.get(PAPER_PATHS.agentInstructions),
968
911
  });
969
912
  const currentPackage = readJson(path.resolve(cwd, "package.json"));
970
913
  if (!currentPackage.exists || currentPackage.error || !currentPackage.value) {
@@ -978,21 +921,12 @@ function migrationFiles({
978
921
  [PAPER_PATHS.contractLock, contractLockText],
979
922
  [PAPER_PATHS.versionPin, `${runtimeIdentity.version}\n`],
980
923
  [PAPER_PATHS.buildWorkflow, buildWorkflow],
924
+ [PAPER_PATHS.verifyWorkflow, verifyWorkflow],
981
925
  [PAPER_PATHS.releaseWorkflow, releaseWorkflow],
982
926
  [PAPER_PATHS.provisioningAuthority, jsonText(provisioningAuthority)],
927
+ ...agentEntry,
983
928
  ["package.json", jsonText(packageJson)],
984
929
  ]);
985
- const verifyWorkflowPath = path.resolve(cwd, PAPER_PATHS.verifyWorkflow);
986
- if (fs.existsSync(verifyWorkflowPath)) {
987
- const currentVerifyWorkflow = fs.readFileSync(verifyWorkflowPath, "utf8");
988
- const migratedVerifyWorkflow = currentVerifyWorkflow.replace(
989
- /(uses:\s*kungfu-systems\/buildchain\/\.github\/workflows\/check\.yml@)[^\s]+/g,
990
- `$1${runtimeSha}`,
991
- );
992
- if (migratedVerifyWorkflow !== currentVerifyWorkflow) {
993
- files.set(PAPER_PATHS.verifyWorkflow, migratedVerifyWorkflow);
994
- }
995
- }
996
930
  return files;
997
931
  }
998
932
 
@@ -1687,7 +1621,27 @@ function validatePaperProvisioningAuthority(cwd) {
1687
1621
  "paper release policy permits avoidable bookkeeping pull requests",
1688
1622
  );
1689
1623
  }
1690
- for (const workflow of [value.workflows?.build, value.workflows?.release]) {
1624
+ if (value.agentEntry?.contract !== PAPER_AGENT_ENTRY_CONTRACT) {
1625
+ errors.push("paper agent-entry authority contract mismatch");
1626
+ }
1627
+ for (const [entryPath, expectedDigest] of [
1628
+ [value.agentEntry?.policyPath, value.agentEntry?.policyDigest],
1629
+ [value.agentEntry?.instructionsPath, value.agentEntry?.instructionsDigest],
1630
+ ]) {
1631
+ if (!entryPath || !SHA256_PATTERN.test(String(expectedDigest || ""))) {
1632
+ errors.push("paper agent-entry authority is incomplete");
1633
+ continue;
1634
+ }
1635
+ const absolute = path.resolve(cwd, entryPath);
1636
+ if (!fs.existsSync(absolute) || sha256File(absolute) !== expectedDigest) {
1637
+ errors.push(`paper agent-entry source digest mismatch: ${entryPath}`);
1638
+ }
1639
+ }
1640
+ for (const workflow of [
1641
+ value.workflows?.build,
1642
+ value.workflows?.verify,
1643
+ value.workflows?.release,
1644
+ ]) {
1691
1645
  if (!workflow?.path || !workflow?.sourceDigest) {
1692
1646
  errors.push("paper workflow authority is incomplete");
1693
1647
  continue;
@@ -1707,7 +1661,10 @@ function validatePaperProvisioningAuthority(cwd) {
1707
1661
  `paper workflow reusable source is not exact: ${workflow.path}`,
1708
1662
  );
1709
1663
  }
1710
- if (!text.includes(`buildchain-ref: ${value.runtime.resolvedSha}`)) {
1664
+ if (
1665
+ workflow.reusablePath !== ".github/workflows/check.yml" &&
1666
+ !text.includes(`buildchain-ref: ${value.runtime.resolvedSha}`)
1667
+ ) {
1711
1668
  errors.push(
1712
1669
  `paper workflow runtime input is not exact: ${workflow.path}`,
1713
1670
  );
@@ -2094,6 +2051,7 @@ export function collectPaperPreflight({
2094
2051
  buildchainSha = "",
2095
2052
  registry = NPM_REGISTRY,
2096
2053
  offline = false,
2054
+ agentEntryMode = "contract",
2097
2055
  } = {}) {
2098
2056
  const resolvedCwd = path.resolve(cwd);
2099
2057
  const status = collectPaperStatus({ cwd: resolvedCwd });
@@ -2114,6 +2072,11 @@ export function collectPaperPreflight({
2114
2072
  buildchainRef: provisioning.value?.runtime?.ref || buildchainRef,
2115
2073
  buildchainSha,
2116
2074
  });
2075
+ const agentEntry = collectPaperAgentEntry({
2076
+ cwd: resolvedCwd,
2077
+ buildchainSha: runtime.resolvedSha,
2078
+ mode: agentEntryMode,
2079
+ });
2117
2080
  const lockPath = path.resolve(resolvedCwd, PAPER_PATHS.contractLock);
2118
2081
  let lockEvaluation = {
2119
2082
  status: "missing-lock",
@@ -2220,6 +2183,11 @@ export function collectPaperPreflight({
2220
2183
  configResult.loaded?.config?.publication,
2221
2184
  );
2222
2185
  const checks = [
2186
+ ...agentEntry.checks.map((entry) => ({
2187
+ ...entry,
2188
+ blocking: true,
2189
+ scope: "local",
2190
+ })),
2223
2191
  {
2224
2192
  id: "provisioning.authority",
2225
2193
  status: provisioning.valid ? "pass" : "fail",
@@ -2486,6 +2454,7 @@ export function collectPaperPreflight({
2486
2454
  policyDigest: provisioning.value?.policy?.policyDigest || "",
2487
2455
  errors: provisioning.errors,
2488
2456
  },
2457
+ agentEntry,
2489
2458
  repositoryPermissions,
2490
2459
  repositoryActions,
2491
2460
  generatedWriteAuthority,
@@ -199,6 +199,7 @@ export const BUILDCHAIN_USAGE = `Usage:
199
199
  buildchain paper work submit [--cwd <dir>] [--title <title>] [--body <body>] [--execute] [--json]
200
200
  buildchain paper fleet audit [--root <dir>] [--offline] [--json]
201
201
  buildchain paper fleet update [--root <dir>] [--write] [--json]
202
+ buildchain paper agent verify [--cwd <dir>] [--offline] [--json]
202
203
  buildchain paper preflight [--cwd <dir>] [--offline] [--json]
203
204
  buildchain paper bootstrap npm [--cwd <dir>] [--execute]
204
205
  [--confirm-public-package <name>] [--json]
@@ -0,0 +1,35 @@
1
+ import { collectPaperPreflight } from "../packages/core/paper.js";
2
+
3
+ function readFlag(args, name, fallback = "") {
4
+ const index = args.indexOf(`--${name}`);
5
+ if (index === -1) return fallback;
6
+ return args[index + 1] || "";
7
+ }
8
+
9
+ export function runPaperAgentCli({
10
+ command,
11
+ subcommand,
12
+ args,
13
+ cwd,
14
+ buildchainRoot,
15
+ buildchainVersion,
16
+ buildchainRef,
17
+ buildchainSha,
18
+ }) {
19
+ if (command !== "agent" || subcommand !== "verify") {
20
+ return { handled: false, result: null };
21
+ }
22
+ return {
23
+ handled: true,
24
+ result: collectPaperPreflight({
25
+ cwd,
26
+ buildchainRoot,
27
+ buildchainVersion,
28
+ buildchainRef: readFlag(args, "buildchain-ref", buildchainRef),
29
+ buildchainSha,
30
+ registry: readFlag(args, "registry", "https://registry.npmjs.org/"),
31
+ offline: args.includes("--offline"),
32
+ agentEntryMode: "local",
33
+ }),
34
+ };
35
+ }
@@ -368,12 +368,13 @@ function githubGovernance(cwd, repository) {
368
368
  }
369
369
  }
370
370
 
371
- function runWorkStart({ args, cwd }) {
371
+ function runWorkStart({ args, cwd, buildchainSha }) {
372
372
  const topic = args[0]?.startsWith("--") ? "" : args[0] || "";
373
373
  const plan = createPaperWorkStartPlan({
374
374
  cwd,
375
375
  topic,
376
376
  branch: readFlag(args, "branch"),
377
+ buildchainSha,
377
378
  });
378
379
  return args.includes("--execute") ? executePaperWorkStart(plan) : plan;
379
380
  }
@@ -382,7 +383,11 @@ function runScaffold(options) {
382
383
  const plan = planPaperScaffold({
383
384
  cwd: options.cwd,
384
385
  buildchainRoot: options.buildchainRoot,
385
- buildchainVersion: options.buildchainVersion,
386
+ buildchainVersion: readFlag(
387
+ options.args,
388
+ "buildchain-version",
389
+ options.buildchainVersion,
390
+ ),
386
391
  buildchainRef: readFlag(
387
392
  options.args,
388
393
  "buildchain-ref",
@@ -405,7 +410,11 @@ function runMigration(options) {
405
410
  const plan = planPaperMigration({
406
411
  cwd: options.cwd,
407
412
  buildchainRoot: options.buildchainRoot,
408
- buildchainVersion: options.buildchainVersion,
413
+ buildchainVersion: readFlag(
414
+ options.args,
415
+ "buildchain-version",
416
+ options.buildchainVersion,
417
+ ),
409
418
  buildchainSha: options.buildchainSha,
410
419
  });
411
420
  return options.args.some((entry) => ["--write", "--execute"].includes(entry))
@@ -413,7 +422,7 @@ function runMigration(options) {
413
422
  : plan;
414
423
  }
415
424
 
416
- function runWorkSubmit({ args, cwd }) {
425
+ function runWorkSubmit({ args, cwd, buildchainSha }) {
417
426
  const repository = collectPaperStatus({ cwd }).identity.repository;
418
427
  const branch = commandResult("git", ["branch", "--show-current"], {
419
428
  cwd,
@@ -426,6 +435,7 @@ function runWorkSubmit({ args, cwd }) {
426
435
  cwd,
427
436
  pullRequests: observation.rows,
428
437
  pullRequestObservation: observation,
438
+ buildchainSha,
429
439
  });
430
440
  return args.includes("--execute") ? executeWorkSubmit(plan, args) : plan;
431
441
  }
package/scripts/paper.mjs CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  PAPER_SCAFFOLD_CONTRACT,
14
14
  PAPER_STATUS_CONTRACT,
15
15
  collectPaperPreflight,
16
+ resolvePaperBuildchainSha,
16
17
  collectPaperStatus,
17
18
  createPaperAlphaPlan,
18
19
  createPaperBuildPlan,
@@ -24,6 +25,7 @@ import {
24
25
  printPaperWorkFleetSummary,
25
26
  runPaperWorkFleetCli,
26
27
  } from "./paper-work-fleet-cli.mjs";
28
+ import { runPaperAgentCli } from "./paper-agent-cli.mjs";
27
29
 
28
30
  function usage() {
29
31
  return `Usage:
@@ -38,6 +40,7 @@ function usage() {
38
40
  [--execute] [--json]
39
41
  buildchain paper fleet audit [--root <dir>] [--offline] [--json]
40
42
  buildchain paper fleet update [--root <dir>] [--write] [--json]
43
+ buildchain paper agent verify [--cwd <dir>] [--offline] [--json]
41
44
  buildchain paper preflight [--cwd <dir>] [--offline] [--json]
42
45
  buildchain paper bootstrap npm [--cwd <dir>] [--package <name>]
43
46
  [--repository <owner/repo>] [--workflow <filename>]
@@ -455,6 +458,7 @@ export async function runPaperCli(
455
458
  buildchainSha = "",
456
459
  } = {},
457
460
  ) {
461
+ buildchainSha = resolvePaperBuildchainSha(buildchainRoot, buildchainSha);
458
462
  const [command = "", maybeSubcommand = "", ...rest] = args;
459
463
  const json = hasFlag(args, "json");
460
464
  try {
@@ -476,8 +480,12 @@ export async function runPaperCli(
476
480
  buildchainRef,
477
481
  buildchainSha,
478
482
  });
483
+ // prettier-ignore
484
+ const paperAgent = runPaperAgentCli({ command, subcommand: maybeSubcommand, args: effectiveArgs, cwd, buildchainRoot, buildchainVersion, buildchainRef, buildchainSha });
479
485
  let result;
480
- if (workFleet.handled) {
486
+ if (paperAgent.handled) {
487
+ result = paperAgent.result;
488
+ } else if (workFleet.handled) {
481
489
  result = workFleet.result;
482
490
  } else if (command === "preflight") {
483
491
  result = collectPaperPreflight({
@@ -492,6 +500,11 @@ export async function runPaperCli(
492
500
  "https://registry.npmjs.org/",
493
501
  ),
494
502
  offline: hasFlag(effectiveArgs, "offline"),
503
+ agentEntryMode: hasFlag(effectiveArgs, "ci")
504
+ ? "ci"
505
+ : hasFlag(effectiveArgs, "agent-entry")
506
+ ? "local"
507
+ : "contract",
495
508
  });
496
509
  } else if (command === "bootstrap" && maybeSubcommand === "npm") {
497
510
  result = executePaperNpmBootstrap({
@@ -577,7 +590,7 @@ export async function runPaperCli(
577
590
  : plan;
578
591
  } else {
579
592
  throw new Error(
580
- "usage: buildchain paper <scaffold|migrate|work start|work submit|fleet audit|fleet update|preflight|bootstrap npm|build|alpha|status|resume> ...",
593
+ "usage: buildchain paper <scaffold|migrate|work start|work submit|fleet audit|fleet update|agent verify|preflight|bootstrap npm|build|alpha|status|resume> ...",
581
594
  );
582
595
  }
583
596
  printResult(result, json);
@@ -97,6 +97,7 @@ export function cliCommandMeta(id) {
97
97
  "portable-cache-receipt": { group: "observability-diagnostics", purpose: "Seal exact, compatible, miss, or corrupt provider evidence against one cache plan." },
98
98
  "npm-dry-run": { group: "release-passport-trust", purpose: "Verify npm publish shape before a release transaction." },
99
99
  paper: { group: "reusable-build", purpose: "Inspect the unified paper repository and publication command families." },
100
+ "paper-agent": { group: "getting-started", purpose: "Verify the mandatory managed Paper agent entry contract on an existing work branch." },
100
101
  "paper-alpha": { group: "release-passport-trust", purpose: "Plan or open the protected dev-to-alpha paper publication PR without direct publication." },
101
102
  "paper-bootstrap-npm": { group: "release-passport-trust", purpose: "Dry-run or explicitly bootstrap the public npm package and bind GitHub Trusted Publishing." },
102
103
  "paper-build": { group: "reusable-build", purpose: "Plan or execute the existing two-clean-build reproducibility gate for a paper." },
@@ -199,4 +200,3 @@ export function nodeApiMeta(exportName) {
199
200
  }
200
201
  return { capabilityGroup: capabilityGroup(meta.group), summary: meta.summary, audience: ["developer", "agent"], maturity: "stable" };
201
202
  }
202
-