@theholocron/cli 5.0.0-alpha.20 → 5.0.0-alpha.200

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/index.mjs CHANGED
@@ -1,14 +1,16 @@
1
1
  import { CARDINALITY, ProviderApiError, REQUIRED_CAPABILITIES, WebhookVerificationError, isMulti } from "./plugin/capabilities.mjs";
2
2
  import { AuthError, createResolveToken as createResolveToken$1, createRestClient } from "@theholocron/http-client";
3
- import { createEnvLookup } from "@theholocron/env-utils";
3
+ import { createEnvLookup, withEnvPrefix } from "@theholocron/env-utils";
4
4
  import { Entry, findCredentials } from "@napi-rs/keyring";
5
- import { readFile } from "node:fs/promises";
6
5
  import { basename, dirname, join } from "node:path";
7
- import { execFile } from "node:child_process";
8
- import { promisify } from "node:util";
6
+ import { readPackageJson } from "@theholocron/pkg-utils";
9
7
  import { loadTasksConfig } from "@theholocron/astromech/config";
10
8
  import { ConfigFileError, ConfigFileError as ConfigFileError$1, loadConfigFile } from "@theholocron/datapad";
11
- createEnvLookup();
9
+ import { readGitRemote } from "@theholocron/git-utils";
10
+ //#region src/env/env.ts
11
+ /** Singleton env for simple global lookups throughout the CLI. */
12
+ const env = createEnvLookup();
13
+ withEnvPrefix(env, "HOLOCRON");
12
14
  /**
13
15
  * Create an injectable env for commands that accept a fake env in tests.
14
16
  * Pass `input.env` when available, falls back to `process.env`.
@@ -17,7 +19,7 @@ function makeEnv(source) {
17
19
  return createEnvLookup(source);
18
20
  }
19
21
  //#endregion
20
- //#region src/auth/keyring.ts
22
+ //#region src/auth/keyring/keyring.ts
21
23
  /**
22
24
  * Keyring-backed bootstrap credential store.
23
25
  *
@@ -87,7 +89,7 @@ function listStoredProviders() {
87
89
  }
88
90
  }
89
91
  //#endregion
90
- //#region src/auth/auth-resolver.ts
92
+ //#region src/auth/auth-resolver/auth-resolver.ts
91
93
  /** Wraps `createResolveToken` from `@theholocron/http` and injects the
92
94
  * system keyring so plugins stay at a one-liner call site. */
93
95
  function createResolveToken(config) {
@@ -113,7 +115,7 @@ function createFeatureResolver(config) {
113
115
  };
114
116
  }
115
117
  //#endregion
116
- //#region src/commands/setup/derived-properties.ts
118
+ //#region src/commands/setup/derived-properties/derived-properties.ts
117
119
  /**
118
120
  * Repo archetype, in priority order:
119
121
  * 1. `*-template` repo name → `template` (independent of package shape).
@@ -184,7 +186,7 @@ function deriveCapabilities(providers) {
184
186
  return Object.keys(providers ?? {}).sort();
185
187
  }
186
188
  /**
187
- * `source` + `ci` are the minimal baseline every repo `holocron setup`
189
+ * `source` + `ci` are the minimal baseline every repo `holocron repo setup`
188
190
  * touches wires — every `holocron.config.ts` in this org already satisfies
189
191
  * this, so `non-compliant` here means drift (a provider manually removed
190
192
  * after setup), not an unmet aspirational policy. Deliberately not a richer
@@ -213,14 +215,14 @@ function missingCapabilities(capabilities) {
213
215
  */
214
216
  async function readWorkspacePackageJsons(repoRoot, workspacePackages) {
215
217
  const results = [];
216
- for (const { slug, dir = "packages" } of workspacePackages) try {
217
- const raw = await readFile(join(repoRoot, dir, slug, "package.json"), "utf8");
218
- results.push(JSON.parse(raw));
219
- } catch {}
218
+ for (const { slug, dir = "packages" } of workspacePackages) {
219
+ const pkg = await readPackageJson(join(repoRoot, dir, slug));
220
+ if (pkg) results.push(pkg);
221
+ }
220
222
  return results;
221
223
  }
222
224
  //#endregion
223
- //#region src/config/config.ts
225
+ //#region src/config/config/config.ts
224
226
  var ConfigError = class extends Error {
225
227
  name = "ConfigError";
226
228
  };
@@ -324,11 +326,12 @@ function resolveConfig(raw) {
324
326
  docs,
325
327
  env: raw.env,
326
328
  log: raw.log,
327
- telemetry: raw.telemetry
329
+ telemetry: raw.telemetry,
330
+ eslint: raw.eslint
328
331
  };
329
332
  }
330
333
  //#endregion
331
- //#region src/config/compose.ts
334
+ //#region src/config/compose/compose.ts
332
335
  function taskName(e) {
333
336
  return typeof e === "string" ? e : e.name;
334
337
  }
@@ -416,12 +419,12 @@ function compose(...args) {
416
419
  };
417
420
  }
418
421
  //#endregion
419
- //#region src/config/define-config.ts
422
+ //#region src/config/define-config/define-config.ts
420
423
  function defineConfig(config) {
421
424
  return config;
422
425
  }
423
426
  //#endregion
424
- //#region src/config/load-config.ts
427
+ //#region src/config/load-config/load-config.ts
425
428
  /**
426
429
  * `holocron.config.{ts,js,mjs,cjs,json}` loader.
427
430
  *
@@ -433,34 +436,39 @@ function defineConfig(config) {
433
436
  * Probe order is TS-first (`.ts` → `.js` → `.mjs` → `.cjs` → `.json`) —
434
437
  * see ADR-0010 / issue #75 / #81.
435
438
  */
436
- const execFileAsync = promisify(execFile);
437
439
  /**
438
- * Read + parse + resolve `holocron.config.*` from the given directory.
440
+ * Read + parse + resolve `holocron.config.*` starting from the given
441
+ * directory, walking up through ancestors to the nearest `.git` boundary
442
+ * when `cwd` itself has no match — every command is usable from any
443
+ * subdirectory of a repo, not only its exact root (see
444
+ * `@theholocron/datapad`'s own doc comment for the stop conditions).
439
445
  * Throws {@link ConfigFileError} when nothing is found or a file cannot
440
- * be loaded, or `ConfigError` when the config is invalid.
446
+ * be loaded, or `ConfigError` when the config fails schema checks.
441
447
  */
442
448
  async function loadConfig(cwd) {
443
449
  const found = await loadConfigFile({
444
450
  cwd,
445
- name: "holocron"
451
+ name: "holocron",
452
+ walkUp: true
446
453
  });
447
454
  if (!found) throw new ConfigFileError$1(`no holocron.config.{ts,js,mjs,cjs,json} found in ${cwd}. Create one — see the README for the schema.`);
448
455
  return {
449
- resolved: resolveConfig(await deriveDefaults(dirname(found.filepath), found.config)),
456
+ resolved: resolveConfig(await deriveDefaults(found)),
450
457
  filepath: found.filepath
451
458
  };
452
459
  }
453
- async function deriveDefaults(configDir, raw) {
454
- const result = { ...raw };
460
+ async function deriveDefaults(found) {
461
+ const configDir = dirname(found.filepath);
462
+ const result = { ...found.config };
455
463
  if (!result.name) result.name = await readPackageJsonName(configDir) ?? basename(configDir);
456
464
  if (result.repo && !result.repo.name) {
457
- const repoName = await readGitRemote(configDir);
458
- if (repoName) result.repo = {
465
+ const remote = await readGitRemote(configDir);
466
+ if (remote?.host === "github.com") result.repo = {
459
467
  ...result.repo,
460
- name: repoName
468
+ name: remote.slug
461
469
  };
462
470
  }
463
- const manifest = await loadTasksConfig(configDir);
471
+ const manifest = await loadTasksConfig(configDir, { holocron: found });
464
472
  if (manifest.tasks) result.tasks = manifest.tasks;
465
473
  if (manifest.syncScripts !== void 0) result.syncScripts = manifest.syncScripts;
466
474
  if (manifest.holocronScript !== void 0) result.holocronScript = manifest.holocronScript;
@@ -469,31 +477,8 @@ async function deriveDefaults(configDir, raw) {
469
477
  return result;
470
478
  }
471
479
  async function readPackageJsonName(dir) {
472
- try {
473
- const content = await readFile(join(dir, "package.json"), "utf8");
474
- const pkg = JSON.parse(content);
475
- return typeof pkg.name === "string" ? pkg.name.replace(/^@[^/]+\//, "") : void 0;
476
- } catch {
477
- return;
478
- }
479
- }
480
- async function readGitRemote(dir) {
481
- try {
482
- const { stdout } = await execFileAsync("git", [
483
- "remote",
484
- "get-url",
485
- "origin"
486
- ], { cwd: dir });
487
- return parseGitRemoteUrl(stdout.trim());
488
- } catch {
489
- return;
490
- }
491
- }
492
- function parseGitRemoteUrl(url) {
493
- const httpsMatch = url.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?$/);
494
- if (httpsMatch) return httpsMatch[1];
495
- const sshMatch = url.match(/github\.com:([^/]+\/[^/]+?)(?:\.git)?$/);
496
- if (sshMatch) return sshMatch[1];
480
+ const name = (await readPackageJson(dir))?.name;
481
+ return name === void 0 ? void 0 : name.replace(/^@[^/]+\//, "");
497
482
  }
498
483
  //#endregion
499
484
  export { AuthError, CARDINALITY, ConfigError, ConfigFileError, ProviderApiError, REQUIRED_CAPABILITIES, WebhookVerificationError, compose, createFeatureResolver, createResolveToken, createRestClient, defineConfig, deleteToken, deriveCapabilities, deriveCompliance, deriveProfile, deriveStack, getToken, isMulti, listStoredProviders, loadConfig, missingCapabilities, readWorkspacePackageJsons, resolveConfig, resolveEntry, resolvePluginPackage, setToken };