@kungfu-tech/buildchain 3.0.3-alpha.1 → 3.0.3-alpha.2

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.
@@ -0,0 +1,563 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import path from "node:path";
3
+ import {
4
+ PAPER_FLEET_AUDIT_CONTRACT,
5
+ PAPER_FLEET_UPDATE_PLAN_CONTRACT,
6
+ PAPER_MIGRATION_CONTRACT,
7
+ PAPER_SCAFFOLD_CONTRACT,
8
+ PAPER_WORK_START_PLAN_CONTRACT,
9
+ PAPER_WORK_SUBMIT_PLAN_CONTRACT,
10
+ collectPaperFleetAudit,
11
+ collectPaperStatus,
12
+ createPaperWorkStartPlan,
13
+ createPaperWorkSubmitPlan,
14
+ discoverPaperFleet,
15
+ executePaperWorkStart,
16
+ executePaperWorkSubmitPush,
17
+ planPaperMigration,
18
+ planPaperScaffold,
19
+ planPaperFleetUpdate,
20
+ writePaperFleetUpdate,
21
+ writePaperMigration,
22
+ writePaperScaffold,
23
+ } from "../packages/core/paper.js";
24
+ import {
25
+ BUILDCHAIN_GITHUB_GOVERNANCE_AUTHORITY,
26
+ compileEffectiveGithubGovernancePolicy,
27
+ } from "../packages/core/github-governance-authority.js";
28
+
29
+ function commandResult(command, args, { cwd, timeout = 60000 } = {}) {
30
+ const result = spawnSync(command, args, {
31
+ cwd,
32
+ env: process.env,
33
+ encoding: "utf8",
34
+ timeout,
35
+ maxBuffer: 2 * 1024 * 1024,
36
+ });
37
+ return {
38
+ ok: result.status === 0,
39
+ stdout: String(result.stdout || "").trim(),
40
+ stderr: String(result.stderr || "").trim(),
41
+ error: result.error?.message || "",
42
+ };
43
+ }
44
+
45
+ function readFlag(args, name, fallback = "") {
46
+ const index = args.indexOf(`--${name}`);
47
+ return index === -1 ? fallback : args[index + 1] || "";
48
+ }
49
+
50
+ function githubPullRequests({ cwd, repository, branch }) {
51
+ const query = commandResult(
52
+ "gh",
53
+ [
54
+ "pr",
55
+ "list",
56
+ "--repo",
57
+ repository,
58
+ "--head",
59
+ branch,
60
+ "--state",
61
+ "open",
62
+ "--json",
63
+ "number,url,headRefName,baseRefName",
64
+ ],
65
+ { cwd },
66
+ );
67
+ if (!query.ok) {
68
+ return {
69
+ ok: false,
70
+ rows: [],
71
+ errorCode: query.error ? "gh-unavailable" : "github-pr-query-failed",
72
+ };
73
+ }
74
+ try {
75
+ const rows = JSON.parse(query.stdout || "[]");
76
+ return {
77
+ ok: Array.isArray(rows),
78
+ rows: Array.isArray(rows) ? rows : [],
79
+ errorCode: "",
80
+ };
81
+ } catch {
82
+ return { ok: false, rows: [], errorCode: "github-pr-response-invalid" };
83
+ }
84
+ }
85
+
86
+ function createPullRequest(plan, title, body) {
87
+ const prTitle =
88
+ title ||
89
+ `chore(paper): ${plan.source.branch.replace(/^[^/]+\//, "").replaceAll("-", " ")}`;
90
+ const prBody =
91
+ body ||
92
+ [
93
+ "## Summary",
94
+ "",
95
+ "Submit this Paper work branch through the protected Buildchain development path.",
96
+ "",
97
+ "## Safety",
98
+ "",
99
+ "- No direct push to a protected channel.",
100
+ "- No force push.",
101
+ "- Publication remains behind the accepted PR and release gates.",
102
+ ].join("\n");
103
+ return commandResult(
104
+ "gh",
105
+ [
106
+ "pr",
107
+ "create",
108
+ "--repo",
109
+ plan.repository,
110
+ "--base",
111
+ plan.target.branch,
112
+ "--head",
113
+ plan.source.branch,
114
+ "--title",
115
+ prTitle,
116
+ "--body",
117
+ prBody,
118
+ ],
119
+ { cwd: plan.cwd },
120
+ );
121
+ }
122
+
123
+ function executeWorkSubmit(plan, args) {
124
+ const pushed = executePaperWorkSubmitPush(plan);
125
+ if (!pushed.ok) return pushed;
126
+ if (plan.pullRequest?.url)
127
+ return { ...pushed, reused: true, pr: plan.pullRequest };
128
+ const created = createPullRequest(
129
+ plan,
130
+ readFlag(args, "title"),
131
+ readFlag(args, "body"),
132
+ );
133
+ if (!created.ok) {
134
+ return {
135
+ ...pushed,
136
+ ok: false,
137
+ errorCode: created.error ? "gh-unavailable" : "github-pr-create-failed",
138
+ stderr: created.error || created.stderr,
139
+ };
140
+ }
141
+ const url =
142
+ created.stdout
143
+ .split(/\s+/)
144
+ .find((entry) => /^https:\/\/github\.com\//.test(entry)) || "";
145
+ return {
146
+ ...pushed,
147
+ reused: false,
148
+ pr: {
149
+ url,
150
+ headRefName: plan.source.branch,
151
+ baseRefName: plan.target.branch,
152
+ },
153
+ };
154
+ }
155
+
156
+ function compactRuleset(value) {
157
+ return {
158
+ id: value.id,
159
+ name: value.name || "",
160
+ enforcement: value.enforcement || "",
161
+ target: value.target || "",
162
+ bypass_actors: value.bypass_actors || [],
163
+ conditions: value.conditions || {},
164
+ rules: (value.rules || []).map((rule) => ({
165
+ type: rule.type || "",
166
+ parameters: rule.parameters || {},
167
+ })),
168
+ };
169
+ }
170
+
171
+ function fetchRulesets(cwd, repository) {
172
+ const listed = commandResult(
173
+ "gh",
174
+ ["api", `repos/${repository}/rulesets?includes_parents=true`],
175
+ { cwd },
176
+ );
177
+ if (!listed.ok) return { ok: false, rows: [] };
178
+ try {
179
+ const summaries = JSON.parse(listed.stdout || "[]");
180
+ const rows = summaries.flatMap((summary) => {
181
+ const detail = commandResult(
182
+ "gh",
183
+ ["api", `repos/${repository}/rulesets/${summary.id}`],
184
+ { cwd },
185
+ );
186
+ if (!detail.ok) return [];
187
+ try {
188
+ return [compactRuleset(JSON.parse(detail.stdout || "{}"))];
189
+ } catch {
190
+ return [];
191
+ }
192
+ });
193
+ return { ok: rows.length === summaries.length, rows };
194
+ } catch {
195
+ return { ok: false, rows: [] };
196
+ }
197
+ }
198
+
199
+ function paperGovernanceTargetPolicies(repository) {
200
+ const name = String(repository || "").split("/")[1] || "";
201
+ return (
202
+ BUILDCHAIN_GITHUB_GOVERNANCE_AUTHORITY.repositoryAdmission
203
+ .publicAuthoritativeTargets[name] || []
204
+ ).filter((entry) => /^(dev|alpha|release)\//.test(entry.targetRef));
205
+ }
206
+
207
+ function bindingKey(entry) {
208
+ return `${entry.context}:${entry.appId ?? ""}`;
209
+ }
210
+
211
+ function sameBindings(observed, expected) {
212
+ const left = (observed || []).map(bindingKey).sort();
213
+ const right = (expected || []).map(bindingKey).sort();
214
+ return JSON.stringify(left) === JSON.stringify(right);
215
+ }
216
+
217
+ function bypassAllowed(observed, allowed) {
218
+ return (observed || []).every((actor) =>
219
+ (allowed || []).some(
220
+ (candidate) =>
221
+ candidate.actorType === actor.actorType &&
222
+ candidate.actorId === actor.actorId &&
223
+ candidate.bypassMode === actor.bypassMode,
224
+ ),
225
+ );
226
+ }
227
+
228
+ export function evaluatePaperGithubGovernance({
229
+ repository,
230
+ actions = {},
231
+ rulesets = [],
232
+ protections = {},
233
+ } = {}) {
234
+ const targetPolicies = paperGovernanceTargetPolicies(repository);
235
+ const checks = [
236
+ {
237
+ id: "actions.default-workflow-permissions",
238
+ ok: actions.default_workflow_permissions === "read",
239
+ },
240
+ {
241
+ id: "actions.pull-request-approval-disabled",
242
+ ok: actions.can_approve_pull_request_reviews === false,
243
+ },
244
+ ];
245
+ const targets = targetPolicies.map((expected) => {
246
+ const observation = protections[expected.targetRef] || {};
247
+ const effective = compileEffectiveGithubGovernancePolicy({
248
+ branch: expected.targetRef,
249
+ defaultBranch: "",
250
+ protectedBranch: observation.ok === true,
251
+ protection: observation.protection || null,
252
+ rulesets,
253
+ });
254
+ const targetChecks = [
255
+ ["observed", observation.ok === true],
256
+ ["native-pull-request", effective.nativePullRequestRequired === true],
257
+ ["approving-review", Number(effective.requiredApprovals) >= 1],
258
+ ["code-owner-review", effective.codeOwnerReviewRequired === true],
259
+ [
260
+ "fresh-review",
261
+ effective.dismissStaleReviews === true ||
262
+ effective.requireLastPushApproval === true,
263
+ ],
264
+ ["administrator-enforcement", effective.enforceAdmins === true],
265
+ ["conversation-resolution", effective.conversationResolution === true],
266
+ [
267
+ "required-check-bindings",
268
+ sameBindings(
269
+ effective.requiredCheckBindings,
270
+ expected.requiredCheckBindings,
271
+ ),
272
+ ],
273
+ [
274
+ "strict-required-checks",
275
+ effective.strictRequiredChecks === expected.strictRequiredChecks,
276
+ ],
277
+ ["force-push-blocked", effective.allowForcePushes === false],
278
+ ["deletion-blocked", effective.allowDeletions === false],
279
+ [
280
+ "bypass-policy",
281
+ bypassAllowed(effective.bypassActors, expected.allowedBypassActors),
282
+ ],
283
+ ].map(([id, ok]) => ({
284
+ id: `protection.${expected.targetRef}.${id}`,
285
+ ok,
286
+ }));
287
+ checks.push(...targetChecks);
288
+ return {
289
+ targetRef: expected.targetRef,
290
+ status: targetChecks.every((entry) => entry.ok) ? "pass" : "fail",
291
+ effectivePolicy: effective,
292
+ };
293
+ });
294
+ const normalizedChecks = checks.map((entry) => ({
295
+ ...entry,
296
+ status: entry.ok ? "pass" : "fail",
297
+ }));
298
+ return {
299
+ status:
300
+ targetPolicies.length > 0 && normalizedChecks.every((entry) => entry.ok)
301
+ ? "pass"
302
+ : "fail",
303
+ checks: normalizedChecks,
304
+ targets,
305
+ };
306
+ }
307
+
308
+ function fetchProtection(cwd, repository, targetRef) {
309
+ const result = commandResult(
310
+ "gh",
311
+ [
312
+ "api",
313
+ `repos/${repository}/branches/${encodeURIComponent(targetRef)}/protection`,
314
+ ],
315
+ { cwd },
316
+ );
317
+ if (!result.ok) return { ok: false, protection: null };
318
+ try {
319
+ return { ok: true, protection: JSON.parse(result.stdout || "{}") };
320
+ } catch {
321
+ return { ok: false, protection: null };
322
+ }
323
+ }
324
+
325
+ function githubGovernance(cwd, repository) {
326
+ const actions = commandResult(
327
+ "gh",
328
+ ["api", `repos/${repository}/actions/permissions/workflow`],
329
+ { cwd },
330
+ );
331
+ const rulesets = fetchRulesets(cwd, repository);
332
+ const targets = paperGovernanceTargetPolicies(repository);
333
+ const protections = Object.fromEntries(
334
+ targets.map((entry) => [
335
+ entry.targetRef,
336
+ fetchProtection(cwd, repository, entry.targetRef),
337
+ ]),
338
+ );
339
+ if (!actions.ok || !rulesets.ok) {
340
+ return {
341
+ status: "fail",
342
+ errorCode: actions.error
343
+ ? "gh-unavailable"
344
+ : "github-governance-query-failed",
345
+ checks: [],
346
+ };
347
+ }
348
+ try {
349
+ const policy = JSON.parse(actions.stdout || "{}");
350
+ const evaluation = evaluatePaperGithubGovernance({
351
+ repository,
352
+ actions: policy,
353
+ rulesets: rulesets.rows,
354
+ protections,
355
+ });
356
+ return {
357
+ ...evaluation,
358
+ errorCode: "",
359
+ actions: policy,
360
+ rulesets: rulesets.rows,
361
+ };
362
+ } catch {
363
+ return {
364
+ status: "fail",
365
+ errorCode: "github-governance-response-invalid",
366
+ checks: [],
367
+ };
368
+ }
369
+ }
370
+
371
+ function runWorkStart({ args, cwd }) {
372
+ const topic = args[0]?.startsWith("--") ? "" : args[0] || "";
373
+ const plan = createPaperWorkStartPlan({
374
+ cwd,
375
+ topic,
376
+ branch: readFlag(args, "branch"),
377
+ });
378
+ return args.includes("--execute") ? executePaperWorkStart(plan) : plan;
379
+ }
380
+
381
+ function runScaffold(options) {
382
+ const plan = planPaperScaffold({
383
+ cwd: options.cwd,
384
+ buildchainRoot: options.buildchainRoot,
385
+ buildchainVersion: options.buildchainVersion,
386
+ buildchainRef: readFlag(
387
+ options.args,
388
+ "buildchain-ref",
389
+ options.buildchainRef,
390
+ ),
391
+ buildchainSha: options.buildchainSha,
392
+ name: readFlag(options.args, "name", path.basename(options.cwd)),
393
+ title: readFlag(options.args, "title"),
394
+ packageName: readFlag(options.args, "package"),
395
+ repository: readFlag(options.args, "repository"),
396
+ version: readFlag(options.args, "version", "0.1.0-alpha.0"),
397
+ siteBaseUrl: readFlag(options.args, "site-base-url"),
398
+ });
399
+ return options.args.some((entry) => ["--write", "--execute"].includes(entry))
400
+ ? writePaperScaffold(plan)
401
+ : plan;
402
+ }
403
+
404
+ function runMigration(options) {
405
+ const plan = planPaperMigration({
406
+ cwd: options.cwd,
407
+ buildchainRoot: options.buildchainRoot,
408
+ buildchainVersion: options.buildchainVersion,
409
+ buildchainSha: options.buildchainSha,
410
+ });
411
+ return options.args.some((entry) => ["--write", "--execute"].includes(entry))
412
+ ? writePaperMigration(plan)
413
+ : plan;
414
+ }
415
+
416
+ function runWorkSubmit({ args, cwd }) {
417
+ const repository = collectPaperStatus({ cwd }).identity.repository;
418
+ const branch = commandResult("git", ["branch", "--show-current"], {
419
+ cwd,
420
+ }).stdout;
421
+ const observation =
422
+ repository && branch
423
+ ? githubPullRequests({ cwd, repository, branch })
424
+ : { ok: false, rows: [], errorCode: "paper-repository-unresolved" };
425
+ const plan = createPaperWorkSubmitPlan({
426
+ cwd,
427
+ pullRequests: observation.rows,
428
+ pullRequestObservation: observation,
429
+ });
430
+ return args.includes("--execute") ? executeWorkSubmit(plan, args) : plan;
431
+ }
432
+
433
+ function runFleetAudit(options) {
434
+ const root = path.resolve(readFlag(options.args, "root", options.cwd));
435
+ const repositories = discoverPaperFleet(root);
436
+ const governance = {};
437
+ if (!options.args.includes("--offline")) {
438
+ for (const repositoryCwd of repositories) {
439
+ const repository = collectPaperStatus({ cwd: repositoryCwd }).identity
440
+ .repository;
441
+ if (repository)
442
+ governance[repository] = githubGovernance(repositoryCwd, repository);
443
+ }
444
+ }
445
+ return collectPaperFleetAudit({
446
+ ...options,
447
+ root,
448
+ repositories,
449
+ governance,
450
+ args: undefined,
451
+ command: undefined,
452
+ subcommand: undefined,
453
+ cwd: undefined,
454
+ });
455
+ }
456
+
457
+ function refreshFleetLocks(result) {
458
+ for (const entry of result.results || []) {
459
+ if (!entry.ok) continue;
460
+ const lock = commandResult("pnpm", ["install", "--lockfile-only"], {
461
+ cwd: entry.cwd,
462
+ });
463
+ if (lock.ok) continue;
464
+ return {
465
+ ...result,
466
+ ok: false,
467
+ errorCode: "paper-fleet-lock-refresh-failed",
468
+ lockFailure: { cwd: entry.cwd, stderr: lock.error || lock.stderr },
469
+ };
470
+ }
471
+ return result;
472
+ }
473
+
474
+ function runFleetUpdate(options) {
475
+ const plan = planPaperFleetUpdate({
476
+ root: path.resolve(readFlag(options.args, "root", options.cwd)),
477
+ buildchainRoot: options.buildchainRoot,
478
+ buildchainVersion: options.buildchainVersion,
479
+ buildchainSha: options.buildchainSha,
480
+ });
481
+ return options.args.includes("--write")
482
+ ? refreshFleetLocks(writePaperFleetUpdate(plan))
483
+ : plan;
484
+ }
485
+
486
+ export function runPaperWorkFleetCli(options) {
487
+ const route = `${options.command}:${options.subcommand}`;
488
+ if (options.command === "scaffold")
489
+ return { handled: true, result: runScaffold(options) };
490
+ if (options.command === "migrate")
491
+ return { handled: true, result: runMigration(options) };
492
+ if (options.command === "status") {
493
+ return { handled: true, result: collectPaperStatus({ cwd: options.cwd }) };
494
+ }
495
+ if (route === "work:start")
496
+ return { handled: true, result: runWorkStart(options) };
497
+ if (route === "work:submit")
498
+ return { handled: true, result: runWorkSubmit(options) };
499
+ if (route === "fleet:audit")
500
+ return { handled: true, result: runFleetAudit(options) };
501
+ if (route === "fleet:update")
502
+ return { handled: true, result: runFleetUpdate(options) };
503
+ return { handled: false, result: undefined };
504
+ }
505
+
506
+ export function printPaperWorkFleetSummary(result, fallback = () => {}) {
507
+ if (
508
+ [PAPER_SCAFFOLD_CONTRACT, PAPER_MIGRATION_CONTRACT].includes(
509
+ result.contract,
510
+ )
511
+ )
512
+ return false;
513
+ if (result.contract === PAPER_WORK_START_PLAN_CONTRACT) {
514
+ process.stdout.write(
515
+ `paper work start: ${result.ok ? (result.dryRun ? "ready" : "created") : "blocked"}\n`,
516
+ );
517
+ process.stdout.write(
518
+ `${result.source.developmentRef} -> ${result.target.branch || "<invalid>"}\n`,
519
+ );
520
+ for (const check of result.checks)
521
+ process.stdout.write(
522
+ `- ${check.status}: ${check.id}: ${check.message}\n`,
523
+ );
524
+ return true;
525
+ }
526
+ if (result.contract === PAPER_WORK_SUBMIT_PLAN_CONTRACT) {
527
+ process.stdout.write(
528
+ `paper work submit: ${result.ok ? (result.dryRun ? "ready" : result.pr?.url || "submitted") : "blocked"}\n`,
529
+ );
530
+ process.stdout.write(
531
+ `${result.source.branch} -> ${result.target.branch}\n`,
532
+ );
533
+ for (const check of result.checks)
534
+ process.stdout.write(
535
+ `- ${check.status}: ${check.id}: ${check.message}\n`,
536
+ );
537
+ return true;
538
+ }
539
+ if (result.contract === PAPER_FLEET_AUDIT_CONTRACT) {
540
+ process.stdout.write(
541
+ `paper fleet audit: ${result.summary.current}/${result.summary.repositories} current\n`,
542
+ );
543
+ process.stdout.write(`audit root: ${result.auditRoot}\n`);
544
+ for (const entry of result.repositories)
545
+ process.stdout.write(
546
+ `- ${entry.ok ? "current" : "drifted"}: ${entry.name}\n`,
547
+ );
548
+ return true;
549
+ }
550
+ if (result.contract === PAPER_FLEET_UPDATE_PLAN_CONTRACT) {
551
+ process.stdout.write(
552
+ `paper fleet update: ${result.ok ? (result.dryRun ? "ready" : "written") : "blocked"}\n`,
553
+ );
554
+ process.stdout.write(`plan root: ${result.planRoot}\n`);
555
+ for (const entry of result.plans)
556
+ process.stdout.write(
557
+ `- ${entry.ok ? "ready" : "blocked"}: ${entry.cwd}\n`,
558
+ );
559
+ return true;
560
+ }
561
+ fallback(result);
562
+ return false;
563
+ }
package/scripts/paper.mjs CHANGED
@@ -18,12 +18,12 @@ import {
18
18
  createPaperBuildPlan,
19
19
  createPaperResumePlan,
20
20
  executePaperNpmBootstrap,
21
- planPaperMigration,
22
- planPaperScaffold,
23
- writePaperMigration,
24
- writePaperScaffold,
25
21
  } from "../packages/core/paper.js";
26
22
  import { verifyPublicationReproducibility } from "../packages/core/publication-reproducibility.js";
23
+ import {
24
+ printPaperWorkFleetSummary,
25
+ runPaperWorkFleetCli,
26
+ } from "./paper-work-fleet-cli.mjs";
27
27
 
28
28
  function usage() {
29
29
  return `Usage:
@@ -32,6 +32,12 @@ function usage() {
32
32
  [--version <semver>] [--site-base-url <url>]
33
33
  [--buildchain-ref <ref>] [--write] [--json]
34
34
  buildchain paper migrate [--cwd <dir>] [--write] [--json]
35
+ buildchain paper work start <topic> [--cwd <dir>] [--branch <branch>]
36
+ [--execute] [--json]
37
+ buildchain paper work submit [--cwd <dir>] [--title <title>] [--body <body>]
38
+ [--execute] [--json]
39
+ buildchain paper fleet audit [--root <dir>] [--offline] [--json]
40
+ buildchain paper fleet update [--root <dir>] [--write] [--json]
35
41
  buildchain paper preflight [--cwd <dir>] [--offline] [--json]
36
42
  buildchain paper bootstrap npm [--cwd <dir>] [--package <name>]
37
43
  [--repository <owner/repo>] [--workflow <filename>]
@@ -49,7 +55,10 @@ function usage() {
49
55
 
50
56
  Safety:
51
57
  scaffold is a no-overwrite dry-run unless --write is present. migrate only
52
- rewrites the five Buildchain-owned authority, workflow, lock, and version files.
58
+ rewrites only Buildchain-owned authority, workflow, lock, version, and package
59
+ control surfaces. work start/submit refuse dirty, stale, forked, ambiguous,
60
+ protected, or non-fast-forward sources. fleet update requires isolated work
61
+ branches and is a dry-run unless --write is present.
53
62
  npm bootstrap, Alpha PR creation, and resume dispatch never mutate externally
54
63
  unless --execute is present. Real npm bootstrap additionally requires the
55
64
  exact --confirm-public-package value.
@@ -87,10 +96,6 @@ function commandResult(command, args, { cwd, timeout = 60000 } = {}) {
87
96
  };
88
97
  }
89
98
 
90
- function publicScaffoldPlan(plan) {
91
- return plan;
92
- }
93
-
94
99
  function humanSummary(result) {
95
100
  if (result.contract === PAPER_SCAFFOLD_CONTRACT) {
96
101
  process.stdout.write(
@@ -169,7 +174,7 @@ function humanSummary(result) {
169
174
  }
170
175
  return;
171
176
  }
172
- printJson(result);
177
+ printPaperWorkFleetSummary(result, printJson);
173
178
  }
174
179
 
175
180
  function printResult(result, json) {
@@ -177,7 +182,8 @@ function printResult(result, json) {
177
182
  else humanSummary(result);
178
183
  }
179
184
 
180
- function githubPrRows({ cwd, repository, sourceRef, targetRef }) {
185
+ function githubPrRows({ cwd, repository, sourceRef, targetRef = "" }) {
186
+ const targetArgs = targetRef ? ["--base", targetRef] : [];
181
187
  const query = commandResult(
182
188
  "gh",
183
189
  [
@@ -187,8 +193,7 @@ function githubPrRows({ cwd, repository, sourceRef, targetRef }) {
187
193
  repository,
188
194
  "--head",
189
195
  sourceRef,
190
- "--base",
191
- targetRef,
196
+ ...targetArgs,
192
197
  "--state",
193
198
  "open",
194
199
  "--json",
@@ -461,36 +466,19 @@ export async function runPaperCli(
461
466
  ? [maybeSubcommand, ...rest]
462
467
  : rest;
463
468
  const cwd = path.resolve(readFlag(effectiveArgs, "cwd", process.cwd()));
469
+ const workFleet = runPaperWorkFleetCli({
470
+ command,
471
+ subcommand: maybeSubcommand,
472
+ args: effectiveArgs,
473
+ cwd,
474
+ buildchainRoot,
475
+ buildchainVersion,
476
+ buildchainRef,
477
+ buildchainSha,
478
+ });
464
479
  let result;
465
- if (command === "scaffold") {
466
- const plan = planPaperScaffold({
467
- cwd,
468
- buildchainRoot,
469
- buildchainVersion,
470
- buildchainRef: readFlag(effectiveArgs, "buildchain-ref", buildchainRef),
471
- buildchainSha,
472
- name: readFlag(effectiveArgs, "name", path.basename(cwd)),
473
- title: readFlag(effectiveArgs, "title", ""),
474
- packageName: readFlag(effectiveArgs, "package", ""),
475
- repository: readFlag(effectiveArgs, "repository", ""),
476
- version: readFlag(effectiveArgs, "version", "0.1.0-alpha.0"),
477
- siteBaseUrl: readFlag(effectiveArgs, "site-base-url", ""),
478
- });
479
- result =
480
- hasFlag(effectiveArgs, "write") || hasFlag(effectiveArgs, "execute")
481
- ? writePaperScaffold(plan)
482
- : publicScaffoldPlan(plan);
483
- } else if (command === "migrate") {
484
- const plan = planPaperMigration({
485
- cwd,
486
- buildchainRoot,
487
- buildchainVersion,
488
- buildchainSha,
489
- });
490
- result =
491
- hasFlag(effectiveArgs, "write") || hasFlag(effectiveArgs, "execute")
492
- ? writePaperMigration(plan)
493
- : plan;
480
+ if (workFleet.handled) {
481
+ result = workFleet.result;
494
482
  } else if (command === "preflight") {
495
483
  result = collectPaperPreflight({
496
484
  cwd,
@@ -505,8 +493,6 @@ export async function runPaperCli(
505
493
  ),
506
494
  offline: hasFlag(effectiveArgs, "offline"),
507
495
  });
508
- } else if (command === "status") {
509
- result = collectPaperStatus({ cwd });
510
496
  } else if (command === "bootstrap" && maybeSubcommand === "npm") {
511
497
  result = executePaperNpmBootstrap({
512
498
  cwd,
@@ -591,7 +577,7 @@ export async function runPaperCli(
591
577
  : plan;
592
578
  } else {
593
579
  throw new Error(
594
- "usage: buildchain paper <scaffold|migrate|preflight|bootstrap npm|build|alpha|status|resume> ...",
580
+ "usage: buildchain paper <scaffold|migrate|work start|work submit|fleet audit|fleet update|preflight|bootstrap npm|build|alpha|status|resume> ...",
595
581
  );
596
582
  }
597
583
  printResult(result, json);