@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 +9 -7
- package/dist/cli.mjs +11 -129
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/package.json +8 -5
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
|
|
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
|
|
360
|
-
`AnalyticsSink` (PostHog)
|
|
361
|
-
`posthog-node`
|
|
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
|
|
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 {
|
|
25
|
-
import
|
|
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/
|
|
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
|
|
5977
|
-
*
|
|
5978
|
-
*
|
|
5979
|
-
* `posthog-node` call sites, and a `Noop*Sink` is
|
|
5980
|
-
* off. Same seam
|
|
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
|