@theholocron/cli 4.14.1 → 4.15.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 CHANGED
@@ -307,8 +307,8 @@ holocron auth list # show all stored providers
307
307
 
308
308
  ## Logging
309
309
 
310
- Operational output goes through [`@theholocron/logger`](../logger) — separate from
311
- the user-facing `print` surface. Global flags:
310
+ Operational output goes through `@theholocron/observability/logger` — separate
311
+ from the user-facing `print` surface. Global flags:
312
312
 
313
313
  ```sh
314
314
  holocron doctor --verbose # log level → debug (full structured output)
@@ -356,9 +356,11 @@ export default defineConfig({
356
356
  });
357
357
  ```
358
358
 
359
- Each SDK sits behind a Holocron-owned interface — `ErrorSink` (Sentry) /
360
- `AnalyticsSink` (PostHog) in `src/telemetry/sinks.ts`; `@sentry/node` and
361
- `posthog-node` are imported only from their adapter modules. See the
359
+ Each SDK sits behind an interface from `@theholocron/observability` —
360
+ `ErrorSink` (Sentry) / `AnalyticsSink` (PostHog); the adapters, and the only
361
+ `@sentry/node` / `posthog-node` imports, live in that package. `telemetry.ts`
362
+ holds the orchestration + the Holocron-specific credential resolution
363
+ (`telemetry/resolve.ts`). See the
362
364
  [telemetry guide](https://docs.theholocron.dev/holocron/telemetry/).
363
365
 
364
366
  ## What's in here
@@ -370,8 +372,8 @@ Each SDK sits behind a Holocron-owned interface — `ErrorSink` (Sentry) /
370
372
  - `src/config/load-config.ts` — `loadConfig` — reads `holocron.config.*`
371
373
  (file discovery via [`@theholocron/datapad`](../datapad))
372
374
  - `src/define-config.ts` — `defineConfig` typed pass-through
373
- - `src/logger.ts` — CLI-side `@theholocron/logger` wiring (`buildCliLogger`,
374
- `resolveLogLevel`)
375
+ - `src/logger.ts` — CLI-side `@theholocron/observability/logger` wiring
376
+ (`buildCliLogger`, `resolveLogLevel`)
375
377
  - `src/loader.ts` — `PluginLoader` — dynamic-imports plugins, resolves
376
378
  capability config packages, builds the capability registry
377
379
  - `src/cli.ts` — yargs entry, dispatches subcommands. `holocron run` / `ci` are
package/dist/cli.mjs CHANGED
@@ -11,7 +11,7 @@ import { AuthError, ProviderApiError, ProviderApiError as ProviderApiError$1, cr
11
11
  import { createEnvLookup } from "@theholocron/env-utils";
12
12
  import { Entry, findCredentials } from "@napi-rs/keyring";
13
13
  import { pathToFileURL } from "node:url";
14
- import { createLogger, parseLogLevel, resolveAxiomFromEnv } from "@theholocron/logger";
14
+ import { createLogger, parseLogLevel, resolveAxiomFromEnv } from "@theholocron/observability/logger";
15
15
  import ora from "ora";
16
16
  import chalk from "chalk";
17
17
  import { execFile, execFileSync, spawnSync } from "node:child_process";
@@ -21,8 +21,9 @@ import { createHash } from "node:crypto";
21
21
  import { generateReadme } from "@theholocron/components-doc/markdown";
22
22
  import { getClients, getConfigs, getDocs, getPlugins, getSkills, getThemes, getUtils } from "@theholocron/registry-doc";
23
23
  import { createGitHubClient } from "@theholocron/github-client";
24
- import { PostHog } from "posthog-node";
25
- import * as Sentry from "@sentry/node";
24
+ import { PostHogSink } from "@theholocron/observability/analytics";
25
+ import { NoopAnalyticsSink, NoopErrorSink, redactObject } from "@theholocron/observability/core";
26
+ import { SentrySink } from "@theholocron/observability/errors";
26
27
  import { promisify } from "node:util";
27
28
  import { ConfigFileError, loadConfigFile } from "@theholocron/datapad";
28
29
  //#region src/env.ts
@@ -299,13 +300,6 @@ function resolveConfig(raw) {
299
300
  //#endregion
300
301
  //#region src/logger.ts
301
302
  /**
302
- * CLI-side wiring for `@theholocron/logger`.
303
- *
304
- * `logger` is the operational-output channel — internal state, debug
305
- * traces, errors, structured context that routes to Axiom. It runs in
306
- * parallel to `print` (user-facing UX output) and does not replace it.
307
- */
308
- /**
309
303
  * Resolve the explicit level to hand to `createLogger`, in priority order:
310
304
  *
311
305
  * 1. `--verbose` → `"debug"` 2. `--quiet` → `"error"`
@@ -327,7 +321,7 @@ let rootCommand;
327
321
  let rootAxiomKey;
328
322
  /**
329
323
  * Resolve Axiom credentials for the CLI. Env vars win — same contract as
330
- * `@theholocron/logger`'s `resolveAxiomFromEnv`. Failing that, the CLI-only
324
+ * `@theholocron/observability`'s `resolveAxiomFromEnv`. Failing that, the CLI-only
331
325
  * bridge pairs the OS-keyring token (`axiom.<org>` then bare `axiom`) with a
332
326
  * dataset from `HOLOCRON_AXIOM_DATASET` / `AXIOM_DATASET` or
333
327
  * `holocron.config` `log.axiom.dataset`. Returns `undefined` unless both a
@@ -5821,58 +5815,6 @@ async function writeWorkflowFile(repoRoot, filename, content) {
5821
5815
  await writeFile(join(dir, filename), content, "utf8");
5822
5816
  }
5823
5817
  //#endregion
5824
- //#region src/telemetry/posthog-sink.ts
5825
- /**
5826
- * `PostHogSink` — the **only** `posthog-node` call site. A portable
5827
- * `AnalyticsSink` adapter: usage, adoption, retention. It reads no environment
5828
- * and ships no credentials — the constructor takes a resolved `key` + `host`;
5829
- * the caller (the CLI's `telemetry.ts`, via `telemetry/resolve.ts`) owns the
5830
- * env chain and the fallback. An empty `key` is the caller's signal to install
5831
- * a `NoopAnalyticsSink` instead — it is never passed here.
5832
- *
5833
- * Destined for `@theholocron/observability/analytics` (#635).
5834
- */
5835
- var PostHogSink = class {
5836
- #client;
5837
- constructor(config) {
5838
- this.#client = new PostHog(config.key, { host: config.host });
5839
- }
5840
- identify(distinctId, props) {
5841
- this.#client.identify({
5842
- distinctId,
5843
- properties: props
5844
- });
5845
- }
5846
- capture(distinctId, event, props) {
5847
- this.#client.capture({
5848
- distinctId,
5849
- event,
5850
- properties: props
5851
- });
5852
- }
5853
- async shutdown() {
5854
- await this.#client.shutdown();
5855
- }
5856
- };
5857
- //#endregion
5858
- //#region src/telemetry/redact.ts
5859
- /**
5860
- * Token-shape scrubbing for telemetry payloads — a raw token never leaves the
5861
- * process, even when a value is controlled. Regex-on-the-serialised-string
5862
- * (matches a token shape *anywhere*), distinct from `@theholocron/logger`'s
5863
- * field-path redaction. Shared by {@link scrubError} (Sentry `beforeSend`) and
5864
- * the PostHog `event()` path.
5865
- */
5866
- const TOKEN_RE = /\b(ghp_|ghs_|glpat-|xoxb-|xoxp-|npm_|sk-|[A-Z][A-Z0-9_]{2,}_TOKEN[=\s])[^\s"]*/g;
5867
- /** Replace token-shaped substrings in a string with `[REDACTED]`. */
5868
- function redact(raw) {
5869
- return raw.replace(TOKEN_RE, "[REDACTED]");
5870
- }
5871
- /** Deep-scrub every string in an object by round-tripping through {@link redact}. */
5872
- function redactObject(value) {
5873
- return JSON.parse(redact(JSON.stringify(value)));
5874
- }
5875
- //#endregion
5876
5818
  //#region src/telemetry/resolve.ts
5877
5819
  /**
5878
5820
  * Holocron-specific credential resolution for the telemetry sinks — the env
@@ -5908,76 +5850,16 @@ function resolvePostHogHost() {
5908
5850
  return env.get("HOLOCRON_POSTHOG_HOST") ?? env.get("POSTHOG_HOST") ?? DEFAULT_POSTHOG_HOST;
5909
5851
  }
5910
5852
  //#endregion
5911
- //#region src/telemetry/sentry-sink.ts
5912
- /** `beforeSend` — token-shaped strings never leave the process. */
5913
- function scrubError(event, _hint) {
5914
- return redactObject(event);
5915
- }
5916
- var SentrySink = class {
5917
- init(ctx) {
5918
- Sentry.init({
5919
- dsn: ctx.dsn,
5920
- release: ctx.release,
5921
- environment: ctx.environment,
5922
- tracesSampleRate: 1,
5923
- beforeSend: scrubError
5924
- });
5925
- Sentry.startSession();
5926
- for (const [key, value] of Object.entries(ctx.tags)) Sentry.setTag(key, value);
5927
- }
5928
- startSpan(name) {
5929
- Sentry.setTag("command", name);
5930
- const span = Sentry.startInactiveSpan({
5931
- name,
5932
- op: "holocron.command",
5933
- forceTransaction: true
5934
- });
5935
- return {
5936
- setStatus: (ok) => span.setStatus({ code: ok ? 1 : 2 }),
5937
- end: () => span.end()
5938
- };
5939
- }
5940
- captureException(err) {
5941
- Sentry.captureException(err);
5942
- }
5943
- endSession() {
5944
- Sentry.endSession();
5945
- }
5946
- async flush() {
5947
- await Sentry.close(2e3);
5948
- }
5949
- };
5950
- //#endregion
5951
- //#region src/telemetry/sinks.ts
5952
- /**
5953
- * The disabled path made explicit — one shared no-op instead of a scatter of
5954
- * `if (!enabled) return` guards. Used when telemetry is opted out
5955
- * (`HOLOCRON_TELEMETRY=false`, `config.telemetry.enabled: false`) or no
5956
- * credentials resolve.
5957
- */
5958
- var NoopErrorSink = class {
5959
- init() {}
5960
- startSpan() {}
5961
- captureException() {}
5962
- endSession() {}
5963
- async flush() {}
5964
- };
5965
- /** @see NoopErrorSink */
5966
- var NoopAnalyticsSink = class {
5967
- identify() {}
5968
- capture() {}
5969
- async shutdown() {}
5970
- };
5971
- //#endregion
5972
5853
  //#region src/telemetry.ts
5973
5854
  /**
5974
5855
  * CLI self-telemetry orchestration — errors (Sentry), usage analytics (PostHog).
5975
5856
  *
5976
- * This module holds *no* vendor SDK import. Each concern sits behind a
5977
- * Holocron-owned interface ({@link ErrorSink} / {@link AnalyticsSink}); the
5978
- * concrete `SentrySink` / `PostHogSink` are the only `@sentry/node` /
5979
- * `posthog-node` call sites, and a `Noop*Sink` is installed when telemetry is
5980
- * off. Same seam `@theholocron/logger` uses for Pino.
5857
+ * This module holds *no* vendor SDK import. Each concern sits behind an
5858
+ * interface from `@theholocron/observability` ({@link ErrorSink} /
5859
+ * {@link AnalyticsSink}); the `SentrySink` / `PostHogSink` adapters there are
5860
+ * the only `@sentry/node` / `posthog-node` call sites, and a `Noop*Sink` is
5861
+ * installed when telemetry is off. Same seam the package's `Logger` uses for
5862
+ * Pino.
5981
5863
  *
5982
5864
  * Activation is env-var + shipped-fallback, resolved here (`telemetry/resolve.ts`)
5983
5865
  * and passed to the sink — the adapters read no environment. The single kill