@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 +104 -23
- package/dist/index.d.mts +1 -1
- package/package.json +1 -1
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
|
-
|
|
952
|
-
name:
|
|
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:
|
|
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
|
|
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
|
-
|
|
1906
|
-
name:
|
|
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
|
|
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.
|
|
3292
|
-
* (Phase B; Phase A takes fully-populated input).
|
|
3293
|
-
* 5. Generate — for each template, write to
|
|
3297
|
+
* 4. Generate — for each template, write to
|
|
3294
3298
|
* packages/holocron-plugin-<slug>/<path>.
|
|
3295
|
-
*
|
|
3299
|
+
* 5. Verify (unless --no-verify) — runs pnpm install +
|
|
3296
3300
|
* pnpm --filter <pkg> typecheck lint test.
|
|
3297
|
-
*
|
|
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
|
|
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
|
|
4365
|
-
|
|
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
|
-
|
|
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
|
|
4948
|
-
vendorEnv
|
|
4949
|
-
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
|
|
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.
|
|
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",
|