@theholocron/cli 2.0.0-alpha.62 → 2.0.0-alpha.64

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/dist/cli.mjs CHANGED
@@ -3,11 +3,13 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSy
3
3
  import path, { basename, dirname, join } from "node:path";
4
4
  import yargs from "yargs";
5
5
  import { hideBin } from "yargs/helpers";
6
+ import { createInterface } from "node:readline";
7
+ import { stdin, stdout } from "node:process";
6
8
  import { ProviderApiError, ProviderApiError as ProviderApiError$1 } from "@theholocron/http-client";
7
9
  import { Entry, findCredentials } from "@napi-rs/keyring";
8
10
  import { createHash } from "node:crypto";
9
11
  import { createGitHubClient } from "@theholocron/github-client";
10
- import { execFile, spawnSync } from "node:child_process";
12
+ import { execFile, execFileSync, spawnSync } from "node:child_process";
11
13
  import { access, readFile, readdir, stat, writeFile } from "node:fs/promises";
12
14
  import { pathToFileURL } from "node:url";
13
15
  import { promisify } from "node:util";
@@ -948,8 +950,8 @@ jobs:
948
950
  BUILD_SCRIPT: \${{ inputs.build-script }}
949
951
  CODECOV_TOKEN: \${{ secrets.CODECOV_TOKEN }}
950
952
  `,
951
- "bookkeeping-pr": `\
952
- name: PR Bookkeeping
953
+ bookkeeping: `\
954
+ name: Bookkeeping
953
955
 
954
956
  on: # yamllint disable-line rule:truthy
955
957
  workflow_call:
@@ -962,7 +964,7 @@ on: # yamllint disable-line rule:truthy
962
964
 
963
965
  jobs:
964
966
  label:
965
- name: Add Labels to PRs
967
+ name: Apply Labels
966
968
  permissions:
967
969
  contents: read
968
970
  issues: write
@@ -970,7 +972,7 @@ jobs:
970
972
  runs-on: ubuntu-latest
971
973
  timeout-minutes: 5
972
974
  concurrency:
973
- group: bookkeeping-pr-\${{ github.event.pull_request.number }}
975
+ group: bookkeeping-\${{ github.event.pull_request.number || github.event.issue.number }}
974
976
  cancel-in-progress: true
975
977
  steps:
976
978
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -1902,14 +1904,18 @@ jobs:
1902
1904
  uses: ${ref("dependencies")}
1903
1905
  secrets: inherit
1904
1906
  `,
1905
- "bookkeeping-pr": `\
1906
- name: PR Bookkeeping
1907
+ bookkeeping: `\
1908
+ name: Bookkeeping
1907
1909
 
1908
1910
  on: # yamllint disable-line rule:truthy
1909
1911
  pull_request:
1910
1912
  types:
1911
1913
  - opened
1912
1914
  - edited
1915
+ issues:
1916
+ types:
1917
+ - opened
1918
+ - edited
1913
1919
 
1914
1920
  permissions:
1915
1921
  contents: read
@@ -1918,7 +1924,7 @@ permissions:
1918
1924
 
1919
1925
  jobs:
1920
1926
  bookkeeping:
1921
- uses: ${ref("bookkeeping-pr")}
1927
+ uses: ${ref("bookkeeping")}
1922
1928
  secrets: inherit
1923
1929
  `,
1924
1930
  audit: `\
@@ -2361,7 +2367,7 @@ async function runNpmPublishInitial(input = {}) {
2361
2367
  const dryRun = input.dryRun ?? false;
2362
2368
  const otp = input.otp;
2363
2369
  const env = input.env ?? process.env;
2364
- const exec = input.exec ?? defaultExec;
2370
+ const exec = input.exec ?? defaultExec$1;
2365
2371
  const publishArgs = [
2366
2372
  "-r",
2367
2373
  "--filter=./packages/*",
@@ -2437,7 +2443,7 @@ function printNextSteps$1(print, env) {
2437
2443
  print(" https://www.npmjs.com/settings/~/tokens");
2438
2444
  }
2439
2445
  }
2440
- const defaultExec = async (cmd, args, opts) => {
2446
+ const defaultExec$1 = async (cmd, args, opts) => {
2441
2447
  const result = spawnSync(cmd, args, {
2442
2448
  cwd: opts.cwd,
2443
2449
  encoding: "utf8",
@@ -3288,13 +3294,11 @@ export default defineConfig({
3288
3294
  * 2. Slug collision — packages/holocron-plugin-<slug>/ must not exist.
3289
3295
  * 3. Capability sanity — must be one of the 14 known keys; warn for
3290
3296
  * many-cardinality caps.
3291
- * 4. Promptfill in any missing flags via cli-utils / inquirer
3292
- * (Phase B; Phase A takes fully-populated input).
3293
- * 5. Generate — for each template, write to
3297
+ * 4. Generatefor each template, write to
3294
3298
  * packages/holocron-plugin-<slug>/<path>.
3295
- * 6. Verify (unless --no-verify) — Phase B; runs pnpm install +
3299
+ * 5. Verify (unless --no-verify) — runs pnpm install +
3296
3300
  * pnpm --filter <pkg> typecheck lint test.
3297
- * 7. Print next steps.
3301
+ * 6. Print next steps.
3298
3302
  */
3299
3303
  var PluginCreateError = class extends Error {
3300
3304
  name = "PluginCreateError";
@@ -3417,6 +3421,51 @@ function runPluginCreate(input) {
3417
3421
  }
3418
3422
  filesWritten.push(resolvedPath);
3419
3423
  }
3424
+ if (!input.dryRun && !input.noVerify) {
3425
+ const execFn = input.exec ?? defaultExec;
3426
+ const pkg = `@theholocron/holocron-plugin-${inputs.slug}`;
3427
+ print("");
3428
+ print(" Verifying scaffold…");
3429
+ try {
3430
+ execFn("pnpm", ["install", "--frozen-lockfile=false"], {
3431
+ cwd,
3432
+ stdio: "inherit"
3433
+ });
3434
+ execFn("pnpm", [
3435
+ "--filter",
3436
+ pkg,
3437
+ "typecheck"
3438
+ ], {
3439
+ cwd,
3440
+ stdio: "inherit"
3441
+ });
3442
+ execFn("pnpm", [
3443
+ "--filter",
3444
+ pkg,
3445
+ "lint"
3446
+ ], {
3447
+ cwd,
3448
+ stdio: "inherit"
3449
+ });
3450
+ execFn("pnpm", [
3451
+ "--filter",
3452
+ pkg,
3453
+ "test"
3454
+ ], {
3455
+ cwd,
3456
+ stdio: "inherit"
3457
+ });
3458
+ print(" ✓ scaffold verified");
3459
+ } catch (err) {
3460
+ print(` ✗ verify failed — ${err instanceof Error ? err.message : String(err)}`);
3461
+ return {
3462
+ status: "fail",
3463
+ packagePath: packageDir,
3464
+ filesWritten,
3465
+ message: "post-scaffold verify failed; inspect output above"
3466
+ };
3467
+ }
3468
+ }
3420
3469
  if (!input.dryRun) printNextSteps(print, inputs);
3421
3470
  return {
3422
3471
  status: "ok",
@@ -3460,6 +3509,12 @@ function defaultWrite(filepath, content) {
3460
3509
  mkdirSync(path.dirname(filepath), { recursive: true });
3461
3510
  writeFileSync(filepath, content, "utf8");
3462
3511
  }
3512
+ function defaultExec(cmd, args, opts) {
3513
+ execFileSync(cmd, args, {
3514
+ cwd: opts.cwd,
3515
+ stdio: opts.stdio
3516
+ });
3517
+ }
3463
3518
  function printNextSteps(print, inputs) {
3464
3519
  print("");
3465
3520
  print(` Scaffolded @theholocron/holocron-plugin-${inputs.slug} (18 files).`);
@@ -4148,7 +4203,7 @@ async function runSetup(input) {
4148
4203
  print(formatStep(steps[steps.length - 1]));
4149
4204
  }
4150
4205
  }
4151
- if (loader.has("source") && (config.workflows ?? []).map((e) => typeof e === "string" ? e : e.name).includes("bookkeeping-pr")) {
4206
+ if (loader.has("source") && (config.workflows ?? []).map((e) => typeof e === "string" ? e : e.name).includes("bookkeeping")) {
4152
4207
  const source = loader.get("source");
4153
4208
  steps.push(await runStep("source", "write .github/labeler.yml", dryRun, async () => {
4154
4209
  await source.writeRepoFile(".github/labeler.yml", labelerConfig());
@@ -4361,8 +4416,9 @@ async function runStep(capability, step, dryRun, body) {
4361
4416
  }
4362
4417
  }
4363
4418
  function classify403(err) {
4364
- const msg = `${err.message} ${String(err.details)}`.toLowerCase();
4365
- if (msg.includes("advanced security") || msg.includes("not enabled for this repository") || msg.includes("upgrade") || msg.includes("not available on")) return "plan";
4419
+ const detailText = typeof err.details === "string" ? err.details : typeof err.details === "object" && err.details !== null && "message" in err.details ? String(err.details.message) : "";
4420
+ const text = `${err.message} ${detailText}`.toLowerCase();
4421
+ if (text.includes("advanced security") || text.includes("not enabled for this repository") || text.includes("upgrade") || text.includes("not available on")) return "plan";
4366
4422
  return "permissions";
4367
4423
  }
4368
4424
  function formatStep(step) {
@@ -4938,15 +4994,40 @@ await yargs(hideBin(process.argv)).scriptName("holocron").usage("$0 <command> [o
4938
4994
  type: "boolean",
4939
4995
  default: true,
4940
4996
  describe: "Run post-scaffold pnpm install + typecheck + lint + test (default true; --no-verify skips)"
4941
- }), (argv) => {
4997
+ }), async (argv) => {
4942
4998
  try {
4943
- if (!argv.capability || !argv.vendorEnv || !argv.baseUrl) throw new PluginCreateError("Phase A: --capability, --vendor-env, and --base-url are required. Interactive prompts land in Phase B.");
4999
+ const capabilityKeys = Object.keys(CARDINALITY).join(", ");
5000
+ const needsPrompt = !argv.capability || !argv.vendorEnv || !argv.baseUrl;
5001
+ let capability;
5002
+ let vendorEnv;
5003
+ let baseUrl;
5004
+ if (needsPrompt) {
5005
+ const rl = createInterface({
5006
+ input: stdin,
5007
+ output: stdout
5008
+ });
5009
+ const ask = (question) => new Promise((resolve) => rl.question(` ${question} `, (answer) => resolve(answer.trim())));
5010
+ try {
5011
+ if (!argv.capability) {
5012
+ console.log(` Available capabilities: ${capabilityKeys}`);
5013
+ capability = await ask("Capability:");
5014
+ } else capability = argv.capability;
5015
+ vendorEnv = argv.vendorEnv ? argv.vendorEnv : await ask(`Vendor-native env var for the ${argv.vendor} token (e.g. MYVENDOR_API_KEY):`);
5016
+ baseUrl = argv.baseUrl ? argv.baseUrl : await ask(`REST base URL for the ${argv.vendor} API (e.g. https://api.myvendor.com):`);
5017
+ } finally {
5018
+ rl.close();
5019
+ }
5020
+ } else {
5021
+ capability = argv.capability;
5022
+ vendorEnv = argv.vendorEnv;
5023
+ baseUrl = argv.baseUrl;
5024
+ }
4944
5025
  if (runPluginCreate({
4945
5026
  slug: argv.slug,
4946
5027
  vendorName: argv.vendor,
4947
- capability: argv.capability,
4948
- vendorEnv: argv.vendorEnv,
4949
- baseUrl: argv.baseUrl,
5028
+ capability,
5029
+ vendorEnv,
5030
+ baseUrl,
4950
5031
  ...argv.tokenEnv ? { tokenEnv: argv.tokenEnv } : {},
4951
5032
  dryRun: argv.dryRun,
4952
5033
  noVerify: !argv.verify,
package/dist/index.d.mts CHANGED
@@ -77,7 +77,7 @@ interface HolocronConfig {
77
77
  * Use the object form to pass `with:` inputs to the reusable workflow.
78
78
  *
79
79
  * Supported values: "lint" | "test" | "typecheck" | "codeql" | "review" |
80
- * "release" | "stale" | "greetings" | "dependencies" | "bookkeeping-pr" | "audit"
80
+ * "release" | "stale" | "greetings" | "dependencies" | "bookkeeping" | "audit"
81
81
  *
82
82
  * `holocron setup` writes `.github/workflows/<name>.yml` for each entry,
83
83
  * calling the corresponding `ci-<name>.yml@main` reusable workflow.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/cli",
3
- "version": "2.0.0-alpha.62",
3
+ "version": "2.0.0-alpha.64",
4
4
  "description": "The Holocron CLI — a pluggable, capability-based orchestrator for spinning up and operating software projects.",
5
5
  "homepage": "https://github.com/theholocron/holocron/tree/main/packages/cli#readme",
6
6
  "bugs": "https://github.com/theholocron/holocron/issues",