@theholocron/cli 3.64.0 → 3.66.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/README.md +4 -2
- package/dist/cli.mjs +43 -67
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +3 -5
- package/dist/index.mjs +20 -69
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -209,13 +209,15 @@ all three. See the [telemetry guide](https://docs.theholocron.dev/holocron/telem
|
|
|
209
209
|
implement
|
|
210
210
|
- `src/config.ts` — config schema, `defineConfig`, `resolveConfig`,
|
|
211
211
|
`CapabilityConfigPackage`
|
|
212
|
-
- `src/load-config.ts` — `loadConfig` — reads
|
|
212
|
+
- `src/config/load-config.ts` — `loadConfig` — reads `holocron.config.*`
|
|
213
|
+
(file discovery via [`@theholocron/datapad`](../datapad))
|
|
213
214
|
- `src/define-config.ts` — `defineConfig` typed pass-through
|
|
214
215
|
- `src/logger.ts` — CLI-side `@theholocron/logger` wiring (`buildCliLogger`,
|
|
215
216
|
`resolveLogLevel`)
|
|
216
217
|
- `src/loader.ts` — `PluginLoader` — dynamic-imports plugins, resolves
|
|
217
218
|
capability config packages, builds the capability registry
|
|
218
|
-
- `src/cli.ts` — yargs entry, dispatches subcommands
|
|
219
|
+
- `src/cli.ts` — yargs entry, dispatches subcommands. `holocron run` is
|
|
220
|
+
delegated to [`@theholocron/astromech`](../astromech) (`createAstromech`).
|
|
219
221
|
- `src/commands/` — `setup`, `sync`, `doctor`, `deploy`, `secret set`,
|
|
220
222
|
`secrets sync`, `npm publish-initial`, `sync-github`, `upgrade node`,
|
|
221
223
|
`plugin create`, `auth`
|
package/dist/cli.mjs
CHANGED
|
@@ -3,6 +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 { createAstromech } from "@theholocron/astromech";
|
|
6
7
|
import yargs from "yargs";
|
|
7
8
|
import { hideBin } from "yargs/helpers";
|
|
8
9
|
import { AuthError, ProviderApiError, ProviderApiError as ProviderApiError$1, createRestClient } from "@theholocron/http-client";
|
|
@@ -22,6 +23,7 @@ import { createGitHubClient } from "@theholocron/github-client";
|
|
|
22
23
|
import * as Sentry from "@sentry/node";
|
|
23
24
|
import { PostHog } from "posthog-node";
|
|
24
25
|
import { promisify } from "node:util";
|
|
26
|
+
import { ConfigFileError, loadConfigFile } from "@theholocron/datapad";
|
|
25
27
|
//#region src/env.ts
|
|
26
28
|
/** Singleton env for simple global lookups throughout the CLI. */
|
|
27
29
|
const env = createEnvLookup();
|
|
@@ -6698,74 +6700,32 @@ async function runUpgradeNode(input) {
|
|
|
6698
6700
|
//#endregion
|
|
6699
6701
|
//#region src/config/load-config.ts
|
|
6700
6702
|
/**
|
|
6701
|
-
* `holocron.config.{
|
|
6703
|
+
* `holocron.config.{ts,js,mjs,cjs,json}` loader.
|
|
6702
6704
|
*
|
|
6703
|
-
*
|
|
6704
|
-
*
|
|
6705
|
-
*
|
|
6706
|
-
*
|
|
6705
|
+
* File discovery + module loading (typed configs via `tsx`, no build
|
|
6706
|
+
* step) is delegated to `@theholocron/datapad`. This module keeps the
|
|
6707
|
+
* holocron-specific parts: filling `name` / `repo.name` defaults and
|
|
6708
|
+
* running the config through `resolveConfig`.
|
|
6707
6709
|
*
|
|
6708
|
-
*
|
|
6709
|
-
*
|
|
6710
|
+
* Probe order is TS-first (`.ts` → `.js` → `.mjs` → `.cjs` → `.json`) —
|
|
6711
|
+
* see ADR-0010 / issue #75 / #81.
|
|
6710
6712
|
*/
|
|
6711
6713
|
const execFileAsync = promisify(execFile);
|
|
6712
|
-
const CANDIDATE_FILENAMES = [
|
|
6713
|
-
"holocron.config.json",
|
|
6714
|
-
"holocron.config.js",
|
|
6715
|
-
"holocron.config.ts"
|
|
6716
|
-
];
|
|
6717
|
-
var ConfigFileError = class extends Error {
|
|
6718
|
-
name = "ConfigFileError";
|
|
6719
|
-
};
|
|
6720
6714
|
/**
|
|
6721
6715
|
* Read + parse + resolve `holocron.config.*` from the given directory.
|
|
6722
|
-
*
|
|
6723
|
-
*
|
|
6716
|
+
* Throws {@link ConfigFileError} when nothing is found or a file cannot
|
|
6717
|
+
* be loaded, or `ConfigError` when the config is invalid.
|
|
6724
6718
|
*/
|
|
6725
6719
|
async function loadConfig(cwd) {
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
filepath: fullPath
|
|
6736
|
-
};
|
|
6737
|
-
return {
|
|
6738
|
-
resolved: await loadJs(fullPath),
|
|
6739
|
-
filepath: fullPath
|
|
6740
|
-
};
|
|
6741
|
-
}
|
|
6742
|
-
}
|
|
6743
|
-
throw new ConfigFileError(`no holocron.config.{json,js,ts} found in ${cwd}. Create one — see the README for the schema.`);
|
|
6744
|
-
}
|
|
6745
|
-
async function loadJson(filepath) {
|
|
6746
|
-
const raw = await readFile(filepath, "utf8");
|
|
6747
|
-
let parsed;
|
|
6748
|
-
try {
|
|
6749
|
-
parsed = JSON.parse(raw);
|
|
6750
|
-
} catch (err) {
|
|
6751
|
-
throw new ConfigError(`${filepath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
6752
|
-
}
|
|
6753
|
-
return resolveConfig(await deriveDefaults(dirname(filepath), parsed));
|
|
6754
|
-
}
|
|
6755
|
-
async function loadJs(filepath) {
|
|
6756
|
-
const mod = await import(pathToFileURL(filepath).href);
|
|
6757
|
-
return resolveConfig(await deriveDefaults(dirname(filepath), extractRaw(filepath, mod)));
|
|
6758
|
-
}
|
|
6759
|
-
async function loadTs(filepath) {
|
|
6760
|
-
const { tsImport } = await import("tsx/esm/api");
|
|
6761
|
-
const mod = await tsImport(pathToFileURL(filepath).href, import.meta.url);
|
|
6762
|
-
return resolveConfig(await deriveDefaults(dirname(filepath), extractRaw(filepath, mod)));
|
|
6763
|
-
}
|
|
6764
|
-
function extractRaw(filepath, mod) {
|
|
6765
|
-
const outer = mod.default;
|
|
6766
|
-
const raw = outer?.__esModule === true ? outer.default : outer;
|
|
6767
|
-
if (raw === void 0 || raw === null) throw new ConfigFileError(`${filepath} must have a default export (use \`export default defineConfig({…})\`)`);
|
|
6768
|
-
return raw;
|
|
6720
|
+
const found = await loadConfigFile({
|
|
6721
|
+
cwd,
|
|
6722
|
+
name: "holocron"
|
|
6723
|
+
});
|
|
6724
|
+
if (!found) throw new ConfigFileError(`no holocron.config.{ts,js,mjs,cjs,json} found in ${cwd}. Create one — see the README for the schema.`);
|
|
6725
|
+
return {
|
|
6726
|
+
resolved: resolveConfig(await deriveDefaults(dirname(found.filepath), found.config)),
|
|
6727
|
+
filepath: found.filepath
|
|
6728
|
+
};
|
|
6769
6729
|
}
|
|
6770
6730
|
async function deriveDefaults(configDir, raw) {
|
|
6771
6731
|
const result = { ...raw };
|
|
@@ -6806,13 +6766,6 @@ function parseGitRemoteUrl(url) {
|
|
|
6806
6766
|
const sshMatch = url.match(/github\.com:([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
6807
6767
|
if (sshMatch) return sshMatch[1];
|
|
6808
6768
|
}
|
|
6809
|
-
async function fileExists(path) {
|
|
6810
|
-
try {
|
|
6811
|
-
return (await stat(path)).isFile();
|
|
6812
|
-
} catch {
|
|
6813
|
-
return false;
|
|
6814
|
-
}
|
|
6815
|
-
}
|
|
6816
6769
|
//#endregion
|
|
6817
6770
|
//#region src/update-notifier.ts
|
|
6818
6771
|
const PACKAGE_NAME = "@theholocron/cli";
|
|
@@ -7276,6 +7229,29 @@ try {
|
|
|
7276
7229
|
},
|
|
7277
7230
|
...argv.steps && argv.steps.length > 0 ? { steps: argv.steps } : {}
|
|
7278
7231
|
})).summary.fail > 0) process.exitCode = 1;
|
|
7232
|
+
}).command("run <task> [passthrough..]", "Run a task locally (test, typecheck, lint, build) — figures out turbo / the tool / the package manager", (y) => y.positional("task", {
|
|
7233
|
+
type: "string",
|
|
7234
|
+
demandOption: true,
|
|
7235
|
+
describe: "Task name (test, typecheck, lint, build). See `holocron run --help`."
|
|
7236
|
+
}).positional("passthrough", {
|
|
7237
|
+
type: "string",
|
|
7238
|
+
array: true,
|
|
7239
|
+
describe: "Args forwarded to the tool — put them after `--`."
|
|
7240
|
+
}).option("required", {
|
|
7241
|
+
type: "boolean",
|
|
7242
|
+
default: false,
|
|
7243
|
+
describe: "Fail (exit 1) if this repo has no such task, instead of skipping."
|
|
7244
|
+
}), (argv) => {
|
|
7245
|
+
const { logger } = buildCliLogger(argv, { command: "run" });
|
|
7246
|
+
const report = createAstromech({
|
|
7247
|
+
cwd: argv.cwd,
|
|
7248
|
+
logger
|
|
7249
|
+
}).run(argv.task, {
|
|
7250
|
+
passthrough: argv.passthrough ?? [],
|
|
7251
|
+
dryRun: argv.dryRun,
|
|
7252
|
+
required: argv.required
|
|
7253
|
+
});
|
|
7254
|
+
if (report.status === "fail" || report.status === "unknown") process.exitCode = 1;
|
|
7279
7255
|
}).command("sync-github", "Sync workflow templates and composite actions to theholocron/.github", (y) => y.option("repo", {
|
|
7280
7256
|
type: "string",
|
|
7281
7257
|
default: "theholocron/.github",
|