tegami 1.0.0-beta.3 → 1.0.0-beta.4

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.
@@ -1,6 +1,4 @@
1
- import { p as PublishPlan, t as Awaitable, w as Draft } from "../types-BHT_9k9p.js";
2
- import { n as Tegami } from "../index-syNgzQTi.js";
3
- import { Command } from "commander";
1
+ import { O as Draft, _ as PublishPlan, t as Awaitable, u as Tegami } from "../types-DKZsadC8.js";
4
2
 
5
3
  //#region src/cli/index.d.ts
6
4
  interface TegamiCLIOptions {
@@ -8,6 +6,10 @@ interface TegamiCLIOptions {
8
6
  version?: () => Awaitable<Draft>;
9
7
  publish?: () => Awaitable<PublishPlan>;
10
8
  }
11
- declare function createCli(tegami: Tegami, options?: TegamiCLIOptions): Command;
9
+ interface TegamiCLI {
10
+ parseAsync(argv?: string[]): Promise<void>;
11
+ }
12
+ declare function createCli(tegami: Tegami, options?: TegamiCLIOptions): TegamiCLI;
13
+ declare function runCli(tegami: Tegami, options?: TegamiCLIOptions): Promise<void>;
12
14
  //#endregion
13
- export { TegamiCLIOptions, createCli };
15
+ export { TegamiCLI, TegamiCLIOptions, createCli, runCli };
package/dist/cli/index.js CHANGED
@@ -1,14 +1,10 @@
1
- import { r as formatNpmDistTag } from "../semver-EKJ8yK5U.js";
2
1
  import { i as renderChangelog, n as generateFromCommits, t as changelogFilename } from "../generate-BfYdNTFi.js";
3
- import { n as execFailure, o as isCI, r as handlePluginError, t as CancelledError } from "../error-We7chQVJ.js";
4
- import { i as findIssueCommentByPrefix, l as updateIssueComment, o as getPullRequest, t as createIssueComment } from "../api-CGfXmmEM.js";
2
+ import { o as isCI, r as handlePluginError, t as CancelledError } from "../error-We7chQVJ.js";
5
3
  import { mkdir, readFile, writeFile } from "node:fs/promises";
6
- import path, { basename, join, relative } from "node:path";
4
+ import path, { join, relative } from "node:path";
7
5
  import { x } from "tinyexec";
8
- import z from "zod";
9
- import { resolveCommand } from "package-manager-detector";
10
6
  import { autocompleteMultiselect, confirm, intro, isCancel, multiline, note, outro, select, spinner } from "@clack/prompts";
11
- import { Command, InvalidArgumentError } from "commander";
7
+ import { parseArgs } from "node:util";
12
8
  //#region src/utils/git-changes.ts
13
9
  async function getChangedPackages(graph, cwd) {
14
10
  return resolveChangedPackages(graph, await getChangedFilePaths(cwd), cwd);
@@ -203,7 +199,6 @@ async function promptPackageBumpTypes(selectedPackages) {
203
199
  }
204
200
  //#endregion
205
201
  //#region src/cli/init-agent.ts
206
- const CHANGELOG_DOCS_URL$1 = "https://tegami.fuma-nama.dev/changelog";
207
202
  async function initAgent(context, options = {}) {
208
203
  const output = path.resolve(context.cwd, options.output ?? "AGENTS.md");
209
204
  const content = renderAgentsMd(context);
@@ -233,7 +228,7 @@ function renderAgentsMd(context) {
233
228
  "",
234
229
  `Create pending changelog files under \`${changelogDir}/\` as \`YYYY-MM-DD-{hash}.md\`.`,
235
230
  "",
236
- `See the [changelog format docs](${CHANGELOG_DOCS_URL$1}) for details.`,
231
+ `See the [changelog format docs](https://tegami.fuma-nama.dev/changelog) for details.`,
237
232
  "",
238
233
  "### Example",
239
234
  "",
@@ -266,225 +261,231 @@ function renderAgentsMd(context) {
266
261
  ].join("\n");
267
262
  }
268
263
  //#endregion
269
- //#region src/cli/pr.ts
270
- const TEGAMI_DOCS_URL = "https://tegami.fuma-nama.dev";
271
- const CHANGELOG_DOCS_URL = `${TEGAMI_DOCS_URL}/changelog`;
272
- const COMMENT_MARKER = "<!-- tegami -->";
273
- async function buildPrPreview(context, draft, options = {}) {
274
- const pullRequest = await resolvePullRequest(context, options);
275
- const tegamiCommandRaw = resolveCommand(context.npm?.client ?? "npm", "run", ["tegami"]);
276
- const tegamiCommand = [tegamiCommandRaw.command, ...tegamiCommandRaw.args].join(" ");
277
- const prChangelogFiles = await listPullRequestChangelogFiles(context, pullRequest.baseSha, pullRequest.headSha);
278
- const createLink = createChangelogUrl(context, pullRequest.headRepo, pullRequest.headRef, changelogFilename());
279
- const lines = [
280
- "### Tegami",
281
- "",
282
- `This repository uses [Tegami](${TEGAMI_DOCS_URL}) to manage releases. When your changes affect published packages, add a changelog file under \`.tegami/\` before merging.`,
283
- "",
284
- `[**Create a changelog →**](${createLink}) · [Changelog format](${CHANGELOG_DOCS_URL})`,
285
- ""
286
- ];
287
- const pendingPackages = [];
288
- for (const pkg of context.graph.getPackages()) {
289
- const plan = draft.getPackageDraft(pkg.id);
290
- if (!plan) continue;
291
- const bumped = plan.bumpVersion(pkg);
292
- if (!bumped || !pkg.version || bumped === pkg.version) continue;
293
- pendingPackages.push({
294
- name: pkg.name,
295
- type: plan.type ?? "—",
296
- from: pkg.version,
297
- to: bumped,
298
- distTag: plan.npm?.distTag
299
- });
300
- }
301
- const prChangelogs = draft.getChangelogs().filter((entry) => prChangelogFiles.has(entry.filename));
302
- if (pendingPackages.length > 0) {
303
- lines.push("#### Release preview", "", "| Package | Bump | Version |", "| --- | --- | --- |");
304
- for (const { name, type, from, to, distTag } of pendingPackages) lines.push(`| \`${name}\` | ${type} | \`${from}\` → \`${to}\`${formatNpmDistTag(distTag)} |`);
305
- lines.push("");
264
+ //#region src/cli/core.ts
265
+ function createTegamiCliRegistry(tegami) {
266
+ const commands = /* @__PURE__ */ new Map();
267
+ function getChildCommands(command) {
268
+ const out = [];
269
+ const prefix = command.path.join("\0");
270
+ for (const [key, candidate] of commands) if (key.startsWith(prefix) && key.length > prefix.length) out.push(candidate);
271
+ return out;
306
272
  }
307
- if (prChangelogs.length > 0) {
308
- lines.push("#### Changelogs in this PR", "", "| Changelog | Title |", "| --- | --- |");
309
- for (const entry of prChangelogs) for (const section of entry.sections) lines.push(`| \`${entry.filename}\` | ${section.title} |`);
310
- lines.push("");
311
- } else if (pendingPackages.length === 0) lines.push("#### No changelogs yet", "", "This PR has no pending changelog files. If your changes require a release, add a changelog before merging.", "");
312
- else if (prChangelogFiles.size === 0) lines.push("This PR does not add changelog files. Pending changelogs from other branches are included in the preview above.", "");
313
- lines.push(`Run \`${tegamiCommand}\` locally to create a changelog interactively.`, "", `<sub>Managed by [Tegami](${TEGAMI_DOCS_URL}).</sub>`, "");
314
- return lines.join("\n");
273
+ return {
274
+ command(path, options) {
275
+ const definition = {
276
+ path: path.length === 0 ? [] : path.split(/\s+/),
277
+ positionals: [],
278
+ description: options?.description,
279
+ options: [],
280
+ resolve: options?.resolve ?? true
281
+ };
282
+ commands.set(definition.path.join("\0"), definition);
283
+ const api = {
284
+ option(name, { short, description = "", type }) {
285
+ definition.options.push({
286
+ name,
287
+ short,
288
+ type,
289
+ description
290
+ });
291
+ return api;
292
+ },
293
+ positional(name, required) {
294
+ definition.positionals.push({
295
+ name,
296
+ required: required ?? true
297
+ });
298
+ return api;
299
+ },
300
+ action(fn) {
301
+ definition.action = fn;
302
+ }
303
+ };
304
+ return api;
305
+ },
306
+ help: () => formatRootHelp(commands),
307
+ async parse(argv) {
308
+ if (argv[0] === "--help" || argv[0] === "-h") {
309
+ console.log(formatRootHelp(commands));
310
+ return;
311
+ }
312
+ const match = findCommand(commands, argv);
313
+ if (!match) throw new Error(`Unknown command: ${argv[0]}`);
314
+ const args = argv.slice(match.path.length);
315
+ if (args.includes("--help") || args.includes("-h")) {
316
+ console.log(formatCommandHelp(match, getChildCommands(match)));
317
+ return;
318
+ }
319
+ if (!match.action) {
320
+ if (args.length === 0) {
321
+ console.log(formatCommandHelp(match, getChildCommands(match)));
322
+ return;
323
+ }
324
+ throw new Error(`Unknown command: ${argv.slice(0, match.path.length + 1).join(" ")}`);
325
+ }
326
+ const { values, positionals } = parseCommandArgs(match, args);
327
+ const context = match.resolve ? await tegami._internal.context() : await tegami._internal.contextUnresolved();
328
+ await match.action({
329
+ context,
330
+ values,
331
+ positionals
332
+ });
333
+ }
334
+ };
315
335
  }
316
- async function postPrComment(body) {
317
- const repo = process.env.GITHUB_REPOSITORY;
318
- if (!repo) {
319
- outro("GITHUB_REPOSITORY is required.");
320
- return;
321
- }
322
- const pr = await readPullRequestFromWorkflowRunEvent();
323
- if (!pr.found) {
324
- outro(pr.reason);
325
- return;
326
- }
327
- const markedBody = `${COMMENT_MARKER}\n${body}`;
328
- const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;
329
- const existingId = await findIssueCommentByPrefix(repo, pr.number, COMMENT_MARKER, token);
330
- if (existingId) {
331
- await updateIssueComment(repo, existingId, markedBody, token);
332
- return;
336
+ function formatUsage(command) {
337
+ return [...command.path, ...command.positionals.map((positional) => positional.required ? `<${positional.name}>` : `[${positional.name}]`)].join(" ");
338
+ }
339
+ function findCommand(commands, argv) {
340
+ if (argv.length === 0) return commands.get("");
341
+ for (let i = 0; i < argv.length; i++) {
342
+ const search = argv.slice(0, argv.length - i).join("\0");
343
+ const res = commands.get(search);
344
+ if (res) return res;
333
345
  }
334
- await createIssueComment(repo, pr.number, markedBody, token);
335
346
  }
336
- const eventSchema = z.looseObject({ workflow_run: z.looseObject({
337
- event: z.literal("pull_request", { error: "The preview workflow was not triggered by a pull request." }),
338
- conclusion: z.literal("success", { error: "The preview workflow did not complete successfully." }),
339
- pull_requests: z.array(z.looseObject({ number: z.int() }), { error: "The preview workflow is not associated with a pull request." }).min(1)
340
- }, { error: "A workflow_run event is required." }) });
341
- async function readPullRequestFromWorkflowRunEvent() {
342
- const eventPath = process.env.GITHUB_EVENT_PATH;
343
- if (!eventPath) return {
344
- found: false,
345
- reason: "GITHUB_EVENT_PATH is required."
347
+ function parseCommandArgs(command, args) {
348
+ const optionConfig = { help: {
349
+ type: "boolean",
350
+ short: "h"
351
+ } };
352
+ for (const option of command.options) optionConfig[option.name] = {
353
+ type: option.type,
354
+ short: option.short
346
355
  };
347
- let raw;
348
- try {
349
- raw = JSON.parse(await readFile(eventPath, "utf8"));
350
- } catch {
351
- return {
352
- found: false,
353
- reason: "Failed to read workflow_run event."
354
- };
356
+ const parsed = parseArgs({
357
+ args,
358
+ options: optionConfig,
359
+ strict: true,
360
+ allowPositionals: command.positionals.length > 0
361
+ });
362
+ const positionals = {};
363
+ if (parsed.positionals.length > command.positionals.length) throw new Error("Too many arguments");
364
+ for (const positional of command.positionals) {
365
+ const value = parsed.positionals.shift();
366
+ if (value === void 0 && positional.required) throw new Error(`missing required argument: ${positional.name}`);
367
+ if (value === void 0) continue;
368
+ positionals[positional.name] = value;
355
369
  }
356
- const { error, data } = eventSchema.safeParse(raw);
357
- if (error) return {
358
- found: false,
359
- reason: z.prettifyError(error)
360
- };
361
370
  return {
362
- found: true,
363
- number: data.workflow_run.pull_requests[0].number
371
+ values: parsed.values,
372
+ positionals
364
373
  };
365
374
  }
366
- async function resolvePullRequest(context, options) {
367
- const repo = context.github?.repo ?? process.env.GITHUB_REPOSITORY;
368
- if (!repo) throw new Error("GITHUB_REPOSITORY is required.");
369
- const token = context.github?.token ?? process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;
370
- if (!repo) throw new Error("GITHUB_TOKEN is required.");
371
- if (options.number !== void 0) {
372
- if (!Number.isInteger(options.number) || options.number <= 0) throw new Error("--number must be a positive integer.");
373
- const data = await getPullRequest(repo, options.number, token);
374
- return {
375
- repo,
376
- headRepo: data.headRepository ? `${data.headRepository.owner.login}/${data.headRepository.name}` : repo,
377
- headRef: data.headRefName,
378
- baseSha: data.baseRefOid,
379
- headSha: data.headRefOid
380
- };
375
+ function formatRootHelp(commands) {
376
+ let width = 0;
377
+ const rows = [];
378
+ for (const command of commands.values()) {
379
+ if (command.path.length === 0) continue;
380
+ const key = formatUsage(command);
381
+ width = Math.max(width, key.length);
382
+ rows.push([key, command.description ?? ""]);
381
383
  }
382
- const event = await readPullRequestEvent();
383
- if (event) return {
384
- repo,
385
- ...event
386
- };
387
- throw new Error("A pull request event or --number is required.");
384
+ return `${[
385
+ "Usage: tegami [command]",
386
+ "",
387
+ commands.get("")?.description ?? "create changelogs",
388
+ "",
389
+ "Commands:",
390
+ ...rows.map(([usage, description]) => ` ${usage.padEnd(width)} ${description}`),
391
+ "",
392
+ "Run without a command to open the changelog TUI."
393
+ ].join("\n")}\n`;
388
394
  }
389
- async function readPullRequestEvent() {
390
- const eventPath = process.env.GITHUB_EVENT_PATH;
391
- if (!eventPath) return;
392
- let event;
393
- try {
394
- event = JSON.parse(await readFile(eventPath, "utf8"));
395
- } catch {
396
- return;
395
+ function formatCommandHelp(command, childCommands) {
396
+ let width = 0;
397
+ let childWidth = 0;
398
+ const optionRows = command.options.map((option) => {
399
+ const short = option.short ? `-${option.short}, ` : "";
400
+ const long = `--${option.name}`;
401
+ const key = option.type === "string" ? `${short}${long} <value>` : `${short}${long}`;
402
+ width = Math.max(width, key.length);
403
+ return [key, option.description ?? ""];
404
+ });
405
+ const childRows = childCommands.map((child) => {
406
+ const key = formatUsage(child);
407
+ childWidth = Math.max(childWidth, key.length);
408
+ return [key, child.description ?? ""];
409
+ });
410
+ const lines = [];
411
+ if (command.action) lines.push(`Usage: ${formatUsage(command)}`, "");
412
+ if (command.description) lines.push(command.description, "");
413
+ if (optionRows.length > 0) {
414
+ lines.push("Options:");
415
+ for (const [flags, description] of optionRows) lines.push(` ${flags.padEnd(width)} ${description}`);
416
+ lines.push("");
397
417
  }
398
- const pullRequest = event.pull_request;
399
- if (!pullRequest) return;
400
- return {
401
- headRepo: pullRequest.head.repo.full_name,
402
- headRef: pullRequest.head.ref,
403
- baseSha: pullRequest.base.sha,
404
- headSha: pullRequest.head.sha
405
- };
406
- }
407
- async function listPullRequestChangelogFiles(context, baseSha, headSha) {
408
- const dir = relative(context.cwd, context.changelogDir);
409
- const result = await x("git", [
410
- "diff",
411
- "--name-only",
412
- "--diff-filter=ACMRD",
413
- `${baseSha}...${headSha}`,
414
- "--",
415
- `${dir}/`
416
- ], { nodeOptions: { cwd: context.cwd } });
417
- if (result.exitCode !== 0) throw execFailure("Failed to list pull request changelog files.", result);
418
- const files = /* @__PURE__ */ new Set();
419
- for (const line of result.stdout.split("\n")) {
420
- const trimmed = line.trim();
421
- if (trimmed.endsWith(".md")) files.add(basename(trimmed));
418
+ if (childRows.length > 0) {
419
+ lines.push("Commands:");
420
+ for (const [usage, description] of childRows) lines.push(` ${usage.padEnd(childWidth)} ${description}`);
421
+ lines.push("");
422
422
  }
423
- return files;
424
- }
425
- function createChangelogUrl(context, repo, branch, filename) {
426
- const filePath = join(relative(context.cwd, context.changelogDir), filename).replaceAll("\\", "/");
427
- return `https://github.com/${repo}/new/${branch.split("/").map(encodeURIComponent).join("/")}?${new URLSearchParams({ filename: filePath })}`;
423
+ return lines.join("\n");
428
424
  }
429
425
  //#endregion
430
426
  //#region src/cli/index.ts
431
427
  function createCli(tegami, options = {}) {
432
- const program = new Command();
433
- program.name("tegami").description("create changelogs").action(() => runAction(tegami, () => runChangelogTui(tegami)));
434
- program.command("version").description("draft version changes and write the publish lock").action(() => runAction(tegami, async () => {
428
+ const $cli = init();
429
+ async function init() {
430
+ const ctx = await tegami._internal.contextUnresolved();
431
+ const cli = createTegamiCliRegistry(tegami);
432
+ registerCoreCommands(cli, tegami, options);
433
+ for (const plugin of ctx.plugins) await handlePluginError(plugin, "initCli", () => plugin.initCli?.call(ctx, cli));
434
+ return cli;
435
+ }
436
+ return { async parseAsync(argv = process.argv.slice(2)) {
437
+ try {
438
+ await (await $cli).parse(argv);
439
+ } catch (error) {
440
+ if (error instanceof CancelledError) outro(error.message);
441
+ else {
442
+ note(error instanceof Error ? error.message : String(error), "Error");
443
+ outro("Command failed.");
444
+ }
445
+ process.exit(1);
446
+ }
447
+ } };
448
+ }
449
+ async function runCli(tegami, options = {}) {
450
+ await createCli(tegami, options).parseAsync();
451
+ }
452
+ function registerCoreCommands(cli, tegami, options) {
453
+ cli.command("", { description: "create changelog files interactively" }).action(async () => {
454
+ await runChangelogTui(tegami);
455
+ });
456
+ cli.command("version", { description: "draft version changes and write the publish lock" }).action(async () => {
435
457
  await versionPackages(tegami, { cli: options });
436
- }));
437
- program.command("ci").description("version and publish packages").action(() => runAction(tegami, async () => {
458
+ });
459
+ cli.command("ci", { description: "version and publish packages" }).action(async () => {
438
460
  if (await versionPackages(tegami, { cli: options })) return;
439
461
  await publishPackages(tegami, { cli: options });
440
- }));
441
- program.command("check-publish").description("exit with code 1 if no publishing needed, otherwise 0").action(() => runAction(tegami, async () => {
462
+ });
463
+ cli.command("check-publish", { description: "exit with code 1 if no publishing needed, otherwise 0" }).action(async () => {
442
464
  const status = await tegami.publishStatus();
443
465
  process.exit(status === "pending" ? 0 : 1);
444
- }));
445
- const programPr = program.command("pr");
446
- programPr.command("preview").description("(should be executed in a GitHub action) show a pull request release preview and changelog guidance").option("--artifact <path>", "write preview markdown to a file").option("--number <number>", "pull request number", (value) => {
447
- const number = Number(value);
448
- if (!Number.isInteger(number) || number <= 0) throw new InvalidArgumentError("--number must be a positive integer.");
449
- return number;
450
- }).action((commandOptions) => runAction(tegami, async () => {
451
- const context = await tegami._internal.context();
452
- const body = await buildPrPreview(context, await tegami.draft(), commandOptions);
453
- if (commandOptions.artifact) {
454
- const artifactPath = path.resolve(context.cwd, commandOptions.artifact);
455
- await writeFile(artifactPath, body);
456
- if (!isCI()) {
457
- note(path.relative(context.cwd, artifactPath) || commandOptions.artifact, "Release preview");
458
- outro("Release preview ready.");
459
- }
460
- return;
461
- }
462
- if (isCI()) {
463
- process.stdout.write(`${body}\n`);
464
- return;
465
- }
466
- note(body, "Release preview");
467
- outro("Release preview ready.");
468
- }));
469
- programPr.command("comment").description("(should be used with 'pr preview') post the pull request release preview as a comment").argument("<artifact>", "the file path of GitHub artifact").action(async (artifact) => {
470
- try {
471
- await postPrComment(await readFile(artifact, "utf8"));
472
- outro("Pull request comment updated.");
473
- } catch (error) {
474
- note(error instanceof Error ? error.message : String(error), "Error");
475
- outro("Command failed.");
476
- process.exit(1);
477
- }
478
466
  });
479
- program.command("publish").description("publish packages from the publish lock").option("--dry-run", "validate the publish lock without publishing packages").action((commandOptions) => runAction(tegami, async () => {
467
+ cli.command("publish", { description: "publish packages from the publish lock" }).option("dry-run", {
468
+ type: "boolean",
469
+ description: "validate the publish lock without publishing"
470
+ }).action(async ({ values }) => {
480
471
  await publishPackages(tegami, {
481
- ...commandOptions,
472
+ dryRun: values["dry-run"],
482
473
  cli: options
483
474
  });
484
- }));
485
- program.command("cleanup").description("remove the publish lock after all packages have been published").action(() => runAction(tegami, () => runCleanup(tegami)));
486
- program.command("init-agent").description("write AGENTS.md with changelog instructions for AI agents").option("-o, --output <path>", "output path", "AGENTS.md").action((commandOptions) => runAction(tegami, () => runInitAgent(tegami, commandOptions)));
487
- return program;
475
+ });
476
+ cli.command("cleanup", { description: "remove the publish lock after all packages have been published" }).action(async () => {
477
+ await runCleanup(tegami);
478
+ });
479
+ cli.command("init-agent", {
480
+ description: "write AGENTS.md with changelog instructions for AI agents",
481
+ resolve: false
482
+ }).option("output", {
483
+ type: "string",
484
+ short: "o",
485
+ description: "output path"
486
+ }).action(async ({ values }) => {
487
+ await runInitAgent(tegami, { output: values.output ?? "AGENTS.md" });
488
+ });
488
489
  }
489
490
  async function versionPackages(tegami, options) {
490
491
  intro("Version Packages");
@@ -492,7 +493,7 @@ async function versionPackages(tegami, options) {
492
493
  const context = await tegami._internal.context();
493
494
  const draft = customVersion ? await customVersion() : await tegami.draft();
494
495
  if (!draft.canApply()) throw new Error(`The draft from custom "version" hook must not be applied`);
495
- for (const plugin of context.plugins) await handlePluginError(plugin, "cli.draftCreated", () => plugin.cli?.draftCreated?.call(context, draft));
496
+ for (const plugin of context.plugins) await handlePluginError(plugin, "initCliDraft", () => plugin.initCliDraft?.call(context, draft));
496
497
  if (!draft.hasPending()) {
497
498
  note("No pending version changes matched workspace packages.", "Nothing to version");
498
499
  outro("No versions changed.");
@@ -522,7 +523,7 @@ async function versionPackages(tegami, options) {
522
523
  throw error;
523
524
  }
524
525
  s.stop("Package versions updated");
525
- for (const plugin of context.plugins) await handlePluginError(plugin, "cli.draftApplied", () => plugin.cli?.draftApplied?.call(context, draft));
526
+ for (const plugin of context.plugins) await handlePluginError(plugin, "applyCliDraft", () => plugin.applyCliDraft?.call(context, draft));
526
527
  outro("Publish lock written.");
527
528
  return true;
528
529
  }
@@ -589,19 +590,5 @@ async function runCleanup(tegami) {
589
590
  }
590
591
  outro(`Publish lock at ${lockPath} is still pending. Publish it before cleanup.`);
591
592
  }
592
- async function runAction(tegami, action) {
593
- try {
594
- const context = await tegami._internal.context();
595
- for (const plugin of context.plugins) await handlePluginError(plugin, "cli.init", () => plugin.cli?.init?.call(context));
596
- await action();
597
- } catch (error) {
598
- if (error instanceof CancelledError) outro(error.message);
599
- else {
600
- note(error instanceof Error ? error.message : String(error), "Error");
601
- outro("Command failed.");
602
- }
603
- process.exit(1);
604
- }
605
- }
606
593
  //#endregion
607
- export { createCli };
594
+ export { createCli, runCli };