@theholocron/cli 4.8.0 → 4.10.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.
- package/dist/cli.mjs +87 -25
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +25 -7
- package/dist/index.mjs +6 -7
- package/package.json +5 -5
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import path, { basename, dirname, join, relative, resolve } from "node:path";
|
|
5
5
|
import { checkbox, input, select } from "@inquirer/prompts";
|
|
6
|
-
import { KNOWN_WORKFLOWS,
|
|
6
|
+
import { KNOWN_WORKFLOWS, WORKFLOW_TEMPLATES, createAstromech, deriveDeployPaths, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, lintThinCallerWith, normalizeWorkflowWith } from "@theholocron/astromech";
|
|
7
7
|
import { loadTasksConfig } from "@theholocron/astromech/config";
|
|
8
8
|
import yargs from "yargs";
|
|
9
9
|
import { hideBin } from "yargs/helpers";
|
|
@@ -284,6 +284,7 @@ function resolveConfig(raw) {
|
|
|
284
284
|
syncScripts: raw.syncScripts,
|
|
285
285
|
holocronScript: raw.holocronScript,
|
|
286
286
|
extraRequiredChecks: raw.extraRequiredChecks,
|
|
287
|
+
hooks: raw.hooks,
|
|
287
288
|
providers,
|
|
288
289
|
apps: raw.apps ?? [],
|
|
289
290
|
doctor: raw.doctor ?? {},
|
|
@@ -3374,12 +3375,12 @@ var alexrc_default = { allow: [
|
|
|
3374
3375
|
] };
|
|
3375
3376
|
//#endregion
|
|
3376
3377
|
//#region src/templates/configs/alexjs/create-config.ts
|
|
3377
|
-
const { workflowHeader: workflowHeader$
|
|
3378
|
+
const { workflowHeader: workflowHeader$7 } = createHeader({ source: "packages/cli/src/templates/configs/alexjs/create-config.ts" });
|
|
3378
3379
|
function createRcConfig() {
|
|
3379
3380
|
return JSON.stringify(alexrc_default, null, 2) + "\n";
|
|
3380
3381
|
}
|
|
3381
3382
|
function createIgnoreConfig() {
|
|
3382
|
-
return `${workflowHeader$
|
|
3383
|
+
return `${workflowHeader$7()}${alexignore_default}`;
|
|
3383
3384
|
}
|
|
3384
3385
|
//#endregion
|
|
3385
3386
|
//#region src/templates/configs/codecov/codecov.yml
|
|
@@ -3423,15 +3424,15 @@ async function readWorkspacePackages(repoRoot) {
|
|
|
3423
3424
|
//#endregion
|
|
3424
3425
|
//#region src/templates/configs/codecov/create-config.ts
|
|
3425
3426
|
const { scaffoldHeader } = createHeader({ source: "packages/cli/src/templates/configs/codecov/create-config.ts" });
|
|
3426
|
-
function createConfig$
|
|
3427
|
+
function createConfig$5(packages) {
|
|
3427
3428
|
return `${scaffoldHeader()}${codecov_default.trimEnd()}${codecovComponentBlock(packages)}`;
|
|
3428
3429
|
}
|
|
3429
3430
|
//#endregion
|
|
3430
3431
|
//#region src/templates/configs/devmoji/create-config.ts
|
|
3431
|
-
const { workflowHeader: workflowHeader$
|
|
3432
|
-
function createConfig$
|
|
3432
|
+
const { workflowHeader: workflowHeader$6 } = createHeader({ source: "packages/cli/src/templates/configs/devmoji/create-config.ts" });
|
|
3433
|
+
function createConfig$4() {
|
|
3433
3434
|
return [
|
|
3434
|
-
workflowHeader$
|
|
3435
|
+
workflowHeader$6("cjs"),
|
|
3435
3436
|
`/* eslint-disable */`,
|
|
3436
3437
|
`const { defineConfig } = require("@theholocron/devmoji-config");`,
|
|
3437
3438
|
`module.exports = defineConfig();`,
|
|
@@ -3443,9 +3444,9 @@ function createConfig$3() {
|
|
|
3443
3444
|
var editorconfig_default = "root = true\n\n[*]\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_style = tab\nindent_size = 4\n\n[.gitattributes]\nindent_style = space\nindent_size = 2\n\n[*.{json,yml,yaml}]\nindent_style = space\nindent_size = 2\n\n[*.{md,mdx}]\ntrim_trailing_whitespace = false\n\n[.*{rc,ignore}]\nindent_style = space\nindent_size = 2\n";
|
|
3444
3445
|
//#endregion
|
|
3445
3446
|
//#region src/templates/configs/editorconfig/create-config.ts
|
|
3446
|
-
const { workflowHeader: workflowHeader$
|
|
3447
|
-
function createConfig$
|
|
3448
|
-
return `${workflowHeader$
|
|
3447
|
+
const { workflowHeader: workflowHeader$5 } = createHeader({ source: "packages/cli/src/templates/configs/editorconfig/create-config.ts" });
|
|
3448
|
+
function createConfig$3() {
|
|
3449
|
+
return `${workflowHeader$5()}${editorconfig_default}`;
|
|
3449
3450
|
}
|
|
3450
3451
|
//#endregion
|
|
3451
3452
|
//#region src/templates/configs/editorconfig-checker/editorconfig-checker.json
|
|
@@ -3476,10 +3477,27 @@ var editorconfig_checker_default = {
|
|
|
3476
3477
|
};
|
|
3477
3478
|
//#endregion
|
|
3478
3479
|
//#region src/templates/configs/editorconfig-checker/create-config.ts
|
|
3479
|
-
function createConfig$
|
|
3480
|
+
function createConfig$2() {
|
|
3480
3481
|
return JSON.stringify(editorconfig_checker_default, null, 2) + "\n";
|
|
3481
3482
|
}
|
|
3482
3483
|
//#endregion
|
|
3484
|
+
//#region src/templates/configs/pre-push/pre-push
|
|
3485
|
+
var pre_push_default = "# Run the merge-gating checks locally before pushing — the same set CI runs.\n# Bypass once with: git push --no-verify\n\n# CI runners (semantic-release, super-linter auto-commit, bots) push without a\n# built dev environment — the hook has nothing to add there.\n[ -n \"$CI\" ] && exit 0\n\n__HOLOCRON_SCRIPT__ ci\n";
|
|
3486
|
+
//#endregion
|
|
3487
|
+
//#region src/templates/configs/pre-push/create-config.ts
|
|
3488
|
+
const { workflowHeader: workflowHeader$4 } = createHeader({ source: "packages/cli/src/templates/configs/pre-push/create-config.ts" });
|
|
3489
|
+
/**
|
|
3490
|
+
* `.husky/pre-push` — runs `holocron ci` (the merge-gating checks, in CI order)
|
|
3491
|
+
* before every push. Installed by `holocron setup` when hooks are enabled
|
|
3492
|
+
* (default for `protection: "strict"`). `git push --no-verify` bypasses it.
|
|
3493
|
+
*
|
|
3494
|
+
* @param holocronScript - the command that invokes the CLI. Defaults to
|
|
3495
|
+
* `pnpm exec holocron`; the source repo passes `node packages/cli/dist/cli.mjs`.
|
|
3496
|
+
*/
|
|
3497
|
+
function createConfig$1(holocronScript = "pnpm exec holocron") {
|
|
3498
|
+
return `${workflowHeader$4("shebang")}${pre_push_default.replace("__HOLOCRON_SCRIPT__", holocronScript)}`;
|
|
3499
|
+
}
|
|
3500
|
+
//#endregion
|
|
3483
3501
|
//#region src/templates/configs/prepare-commit-msg/prepare-commit-msg
|
|
3484
3502
|
var prepare_commit_msg_default = "NAME=$(git config user.name)\nEMAIL=$(git config user.email)\n\nif [ -z \"$NAME\" ]; then\n echo \"empty git config user.name\"\n exit 1\nfi\n\nif [ -z \"$EMAIL\" ]; then\n echo \"empty git config user.email\"\n exit 1\nfi\n\ngit interpret-trailers --if-exists doNothing --trailer \\\n \"Signed-off-by: $NAME <$EMAIL>\" \\\n --in-place \"$1\"\n\nnpx devmoji -e\n";
|
|
3485
3503
|
//#endregion
|
|
@@ -4319,6 +4337,7 @@ async function runSetup(input) {
|
|
|
4319
4337
|
const steps = [];
|
|
4320
4338
|
const repo = config.repo;
|
|
4321
4339
|
const effectivePreset = repo?.protection;
|
|
4340
|
+
const hooksEnabled = input.hooks ?? (typeof config.hooks === "boolean" ? config.hooks : typeof config.hooks === "object" ? config.hooks.prePush !== false : effectivePreset === "strict");
|
|
4322
4341
|
print(style.header(`Holocron setup — ${config.name}${dryRun ? " (dry-run)" : ""}`));
|
|
4323
4342
|
print(style.dim(` config: ${input.loaded.filepath}`));
|
|
4324
4343
|
print("");
|
|
@@ -4352,15 +4371,12 @@ async function runSetup(input) {
|
|
|
4352
4371
|
await source.updateRepoSettings(BALANCED_REPO_SETTINGS);
|
|
4353
4372
|
}));
|
|
4354
4373
|
print(formatStep(steps[steps.length - 1]));
|
|
4355
|
-
const
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
}),
|
|
4362
|
-
...repo?.requiredChecks ?? []
|
|
4363
|
-
] : [];
|
|
4374
|
+
const tasksConfig = { tasks: config.tasks };
|
|
4375
|
+
if (config.extraRequiredChecks) tasksConfig.extraRequiredChecks = config.extraRequiredChecks;
|
|
4376
|
+
const requiredChecks = effectivePreset === "strict" ? ["DCO", ...createAstromech({
|
|
4377
|
+
cwd: input.context.repoRoot,
|
|
4378
|
+
config: tasksConfig
|
|
4379
|
+
}).requiredChecks()] : [];
|
|
4364
4380
|
steps.push(await upsertBranchProtection(source, dryRun, requiredChecks));
|
|
4365
4381
|
print(formatStep(steps[steps.length - 1]));
|
|
4366
4382
|
}
|
|
@@ -4457,21 +4473,42 @@ async function runSetup(input) {
|
|
|
4457
4473
|
}));
|
|
4458
4474
|
print(formatStep(steps[steps.length - 1]));
|
|
4459
4475
|
steps.push(await runStep("source", "write .editorconfig", dryRun, async () => {
|
|
4460
|
-
await source.writeRepoFile(".editorconfig", createConfig$
|
|
4476
|
+
await source.writeRepoFile(".editorconfig", createConfig$3());
|
|
4461
4477
|
}));
|
|
4462
4478
|
print(formatStep(steps[steps.length - 1]));
|
|
4463
4479
|
steps.push(await runStep("source", "write .editorconfig-checker.json", dryRun, async () => {
|
|
4464
|
-
await source.writeRepoFile(".editorconfig-checker.json", createConfig$
|
|
4480
|
+
await source.writeRepoFile(".editorconfig-checker.json", createConfig$2());
|
|
4465
4481
|
}));
|
|
4466
4482
|
print(formatStep(steps[steps.length - 1]));
|
|
4467
4483
|
steps.push(await runStep("source", "write devmoji.config.cjs", dryRun, async () => {
|
|
4468
|
-
await source.writeRepoFile("devmoji.config.cjs", createConfig$
|
|
4484
|
+
await source.writeRepoFile("devmoji.config.cjs", createConfig$4());
|
|
4469
4485
|
}));
|
|
4470
4486
|
print(formatStep(steps[steps.length - 1]));
|
|
4471
4487
|
steps.push(await runStep("source", "write .husky/prepare-commit-msg", dryRun, async () => {
|
|
4472
4488
|
await source.writeRepoFile(".husky/prepare-commit-msg", createConfig());
|
|
4473
4489
|
}));
|
|
4474
4490
|
print(formatStep(steps[steps.length - 1]));
|
|
4491
|
+
if (hooksEnabled) {
|
|
4492
|
+
steps.push(await runStep("source", "write .husky/pre-push", dryRun, async () => {
|
|
4493
|
+
await source.writeRepoFile(".husky/pre-push", createConfig$1(config.holocronScript));
|
|
4494
|
+
return "runs `holocron ci` before push — bypass with `git push --no-verify`";
|
|
4495
|
+
}));
|
|
4496
|
+
print(formatStep(steps[steps.length - 1]));
|
|
4497
|
+
if (config.syncScripts !== false) {
|
|
4498
|
+
steps.push(await runStep("source", "set package.json prepare script", dryRun, async () => {
|
|
4499
|
+
return await ensurePrepareScript(input.context.repoRoot) ? "prepare = \"husky\"" : "already set";
|
|
4500
|
+
}));
|
|
4501
|
+
print(formatStep(steps[steps.length - 1]));
|
|
4502
|
+
}
|
|
4503
|
+
} else {
|
|
4504
|
+
steps.push({
|
|
4505
|
+
capability: "source",
|
|
4506
|
+
step: "write .husky/pre-push",
|
|
4507
|
+
status: "skip",
|
|
4508
|
+
message: "git hooks disabled"
|
|
4509
|
+
});
|
|
4510
|
+
print(formatStep(steps[steps.length - 1]));
|
|
4511
|
+
}
|
|
4475
4512
|
{
|
|
4476
4513
|
const hasTestWorkflow = (config.tasks ?? []).map((e) => typeof e === "string" ? e : e.name).includes("test");
|
|
4477
4514
|
const packages = await readWorkspacePackages(input.context.repoRoot);
|
|
@@ -4483,7 +4520,7 @@ async function runSetup(input) {
|
|
|
4483
4520
|
message: "no test workflow configured"
|
|
4484
4521
|
});
|
|
4485
4522
|
else steps.push(await runStep("source", "write codecov.yml", dryRun, async () => {
|
|
4486
|
-
const content = existing != null ? mergeCodecovComponents(existing, packages) : createConfig$
|
|
4523
|
+
const content = existing != null ? mergeCodecovComponents(existing, packages) : createConfig$5(packages);
|
|
4487
4524
|
await source.writeRepoFile("codecov.yml", content);
|
|
4488
4525
|
return packages.length > 0 ? `${packages.length} components` : "no components";
|
|
4489
4526
|
}));
|
|
@@ -4857,6 +4894,27 @@ async function runSetup(input) {
|
|
|
4857
4894
|
summary
|
|
4858
4895
|
};
|
|
4859
4896
|
}
|
|
4897
|
+
/**
|
|
4898
|
+
* Ensure `package.json#scripts.prepare` is `"husky"` so git hooks register on
|
|
4899
|
+
* install. Merge-only: leaves every other script untouched. Returns `true` when
|
|
4900
|
+
* it wrote a change, `false` when already set or there is no `package.json`.
|
|
4901
|
+
*/
|
|
4902
|
+
async function ensurePrepareScript(repoRoot) {
|
|
4903
|
+
const pkgPath = join(repoRoot, "package.json");
|
|
4904
|
+
let content;
|
|
4905
|
+
try {
|
|
4906
|
+
content = await readFile(pkgPath, "utf8");
|
|
4907
|
+
} catch {
|
|
4908
|
+
return false;
|
|
4909
|
+
}
|
|
4910
|
+
const pkg = JSON.parse(content);
|
|
4911
|
+
const scripts = pkg.scripts ?? {};
|
|
4912
|
+
if (scripts.prepare === "husky") return false;
|
|
4913
|
+
scripts.prepare = "husky";
|
|
4914
|
+
pkg.scripts = scripts;
|
|
4915
|
+
await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
4916
|
+
return true;
|
|
4917
|
+
}
|
|
4860
4918
|
//#endregion
|
|
4861
4919
|
//#region src/commands/skills.ts
|
|
4862
4920
|
/**
|
|
@@ -6837,6 +6895,9 @@ try {
|
|
|
6837
6895
|
}).command("setup", "Apply infra setup actions across every configured capability", (y) => y.option("repo", {
|
|
6838
6896
|
type: "string",
|
|
6839
6897
|
describe: "Repo coords (\"owner/name\"). Defaults to plugin-specific resolution."
|
|
6898
|
+
}).option("hooks", {
|
|
6899
|
+
type: "boolean",
|
|
6900
|
+
describe: "Install git hooks (.husky/pre-push → holocron ci). Default: on for protection:'strict'. --no-hooks to skip."
|
|
6840
6901
|
}), async (argv) => {
|
|
6841
6902
|
const tokens = tokenContext(argv.token);
|
|
6842
6903
|
if (!tokens) return;
|
|
@@ -6850,7 +6911,8 @@ try {
|
|
|
6850
6911
|
...argv.repo ? { repo: argv.repo } : {},
|
|
6851
6912
|
...tokens,
|
|
6852
6913
|
org: resolveOrg(argv, loaded.resolved)
|
|
6853
|
-
}
|
|
6914
|
+
},
|
|
6915
|
+
...argv.hooks !== void 0 ? { hooks: argv.hooks } : {}
|
|
6854
6916
|
})).summary.fail > 0) process.exitCode = 1;
|
|
6855
6917
|
}).command("skills", "Manage agent skills from the @theholocron/skills registry", (y) => y.command("install", "Copy skills from @theholocron/skills into .agents/ with agent symlinks", () => {}, async (argv) => {
|
|
6856
6918
|
await runSkillsInstall({
|