@theholocron/cli 2.0.0-alpha.42 → 2.0.0-alpha.44
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 +1 -1
- package/dist/capabilities/index.d.mts +10 -0
- package/dist/cli.mjs +48 -8
- package/dist/index.d.mts +33 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,5 +109,5 @@ export default acmeConfig;
|
|
|
109
109
|
**`v2.0.0-alpha.0`** — published on npm under the `alpha` dist-tag.
|
|
110
110
|
[Release notes](https://github.com/theholocron/holocron/releases/tag/v2.0.0-alpha.0).
|
|
111
111
|
Design in
|
|
112
|
-
[`.notes/tech-architecture.spec.md`](../../.notes/tech-architecture.spec.md).
|
|
112
|
+
[`.notes/tech-architecture.spec.md`](../../.notes/archive/tech-architecture.spec.md).
|
|
113
113
|
APIs may still shift before stable v2.0.0.
|
|
@@ -127,6 +127,16 @@ interface Source extends ProviderIdentity {
|
|
|
127
127
|
* Optional — providers that have no label concept omit this.
|
|
128
128
|
*/
|
|
129
129
|
syncLabels?(canonical: ReadonlyArray<LabelDef>, stale: ReadonlyArray<string>): Promise<string>;
|
|
130
|
+
/**
|
|
131
|
+
* Set org-level custom property values on the repo.
|
|
132
|
+
* Optional — providers that don't support custom properties omit this.
|
|
133
|
+
*/
|
|
134
|
+
syncProperties?(values: Record<string, string>): Promise<string>;
|
|
135
|
+
/**
|
|
136
|
+
* Replace the repo's topic set with the supplied list.
|
|
137
|
+
* Optional — providers that don't support topics omit this.
|
|
138
|
+
*/
|
|
139
|
+
syncTopics?(topics: string[]): Promise<string>;
|
|
130
140
|
}
|
|
131
141
|
type CiRunStatus = "queued" | "in_progress" | "completed" | "cancelled" | "failure" | "success" | "skipped";
|
|
132
142
|
interface CiRun {
|
package/dist/cli.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { ProviderApiError } from "@theholocron/http-client";
|
|
|
7
7
|
import { Entry, findCredentials } from "@napi-rs/keyring";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { spawnSync } from "node:child_process";
|
|
10
|
-
import { readFile, stat } from "node:fs/promises";
|
|
10
|
+
import { access, readFile, stat } from "node:fs/promises";
|
|
11
11
|
import { pathToFileURL } from "node:url";
|
|
12
12
|
//#region src/capabilities/index.ts
|
|
13
13
|
const CARDINALITY = {
|
|
@@ -464,7 +464,8 @@ var PluginLoader = class {
|
|
|
464
464
|
*/
|
|
465
465
|
projectDefaults() {
|
|
466
466
|
const defaults = {};
|
|
467
|
-
|
|
467
|
+
const repo = this.config.project.repo;
|
|
468
|
+
if (repo) defaults.repo = typeof repo === "string" ? repo : repo.name;
|
|
468
469
|
return defaults;
|
|
469
470
|
}
|
|
470
471
|
};
|
|
@@ -957,6 +958,7 @@ jobs:
|
|
|
957
958
|
name: Add Labels to PRs
|
|
958
959
|
permissions:
|
|
959
960
|
contents: read
|
|
961
|
+
issues: write
|
|
960
962
|
pull-requests: write
|
|
961
963
|
runs-on: ubuntu-latest
|
|
962
964
|
timeout-minutes: 5
|
|
@@ -1902,6 +1904,7 @@ on: # yamllint disable-line rule:truthy
|
|
|
1902
1904
|
|
|
1903
1905
|
permissions:
|
|
1904
1906
|
contents: read
|
|
1907
|
+
issues: write
|
|
1905
1908
|
pull-requests: write
|
|
1906
1909
|
|
|
1907
1910
|
jobs:
|
|
@@ -3680,6 +3683,25 @@ function vaultProviderName(loader) {
|
|
|
3680
3683
|
}
|
|
3681
3684
|
//#endregion
|
|
3682
3685
|
//#region src/commands/setup.ts
|
|
3686
|
+
/**
|
|
3687
|
+
* `holocron setup` — orchestrates per-capability setup actions across
|
|
3688
|
+
* every plugin loaded from `holocron.config.json`.
|
|
3689
|
+
*
|
|
3690
|
+
* Per CLAUDE.md soft-skip: each step is wrapped in a try/catch and
|
|
3691
|
+
* failures don't abort subsequent capabilities. The summary at the end
|
|
3692
|
+
* reports counts so the operator can see what worked + what didn't.
|
|
3693
|
+
*
|
|
3694
|
+
* Per the Standards: when `ctx.dryRun` is true, mutating calls are
|
|
3695
|
+
* replaced with "would" log lines. Read-only probes (e.g.,
|
|
3696
|
+
* `vault.list`) still run so the operator sees real state.
|
|
3697
|
+
*
|
|
3698
|
+
* The orchestrator knows about specific capability methods by name
|
|
3699
|
+
* (e.g., `source.enableVulnerabilityAlerts`). This deliberate coupling
|
|
3700
|
+
* makes the "what does setup do" contract explicit and concrete —
|
|
3701
|
+
* decoupling via a per-capability `setupSteps()` method would be more
|
|
3702
|
+
* extensible but pushes the same knowledge into N plugins instead of
|
|
3703
|
+
* one central place.
|
|
3704
|
+
*/
|
|
3683
3705
|
function editorconfigContent() {
|
|
3684
3706
|
return [
|
|
3685
3707
|
`# AUTO-GENERATED — do not edit directly.`,
|
|
@@ -4036,6 +4058,8 @@ async function runSetup(input) {
|
|
|
4036
4058
|
const config = input.loaded.resolved;
|
|
4037
4059
|
const dryRun = input.context.dryRun ?? false;
|
|
4038
4060
|
const steps = [];
|
|
4061
|
+
const repo = config.project.repo;
|
|
4062
|
+
const effectivePreset = repo?.protection ?? config.project.repoPolicy?.preset;
|
|
4039
4063
|
print(`Holocron setup — ${config.project.name}${dryRun ? " (dry-run)" : ""}`);
|
|
4040
4064
|
print(` config: ${input.loaded.filepath}`);
|
|
4041
4065
|
print("");
|
|
@@ -4060,21 +4084,19 @@ async function runSetup(input) {
|
|
|
4060
4084
|
else return await source.enableCodeScanning();
|
|
4061
4085
|
}));
|
|
4062
4086
|
print(formatStep(steps[steps.length - 1]));
|
|
4063
|
-
|
|
4064
|
-
if (policy && policy.preset !== "none") {
|
|
4065
|
-
const preset = policy.preset ?? "balanced";
|
|
4087
|
+
if (effectivePreset && effectivePreset !== "none") {
|
|
4066
4088
|
steps.push(await runStep("source", "updateRepoSettings", dryRun, async () => {
|
|
4067
4089
|
await source.updateRepoSettings(BALANCED_REPO_SETTINGS);
|
|
4068
4090
|
}));
|
|
4069
4091
|
print(formatStep(steps[steps.length - 1]));
|
|
4070
4092
|
const configuredWorkflowNames = (config.project.workflows ?? []).map((entry) => typeof entry === "string" ? entry : entry.name);
|
|
4071
|
-
const requiredChecks =
|
|
4093
|
+
const requiredChecks = effectivePreset === "strict" ? [
|
|
4072
4094
|
"DCO",
|
|
4073
4095
|
...configuredWorkflowNames.flatMap((name) => {
|
|
4074
4096
|
const ctx = WORKFLOW_CHECK_CONTEXTS[name];
|
|
4075
4097
|
return ctx ? [ctx] : [];
|
|
4076
4098
|
}),
|
|
4077
|
-
...
|
|
4099
|
+
...repo?.requiredChecks ?? config.project.repoPolicy?.requiredChecks ?? []
|
|
4078
4100
|
] : [];
|
|
4079
4101
|
steps.push(await upsertBranchProtection(source, dryRun, requiredChecks));
|
|
4080
4102
|
print(formatStep(steps[steps.length - 1]));
|
|
@@ -4110,7 +4132,7 @@ async function runSetup(input) {
|
|
|
4110
4132
|
}));
|
|
4111
4133
|
print(formatStep(steps[steps.length - 1]));
|
|
4112
4134
|
}
|
|
4113
|
-
if (loader.has("source") &&
|
|
4135
|
+
if (loader.has("source") && effectivePreset !== "none") {
|
|
4114
4136
|
const source = loader.get("source");
|
|
4115
4137
|
steps.push(await runStep("source", "write .github/dependabot.yml", dryRun, async () => {
|
|
4116
4138
|
await source.writeRepoFile(".github/dependabot.yml", DEPENDABOT_CONFIG);
|
|
@@ -4137,6 +4159,24 @@ async function runSetup(input) {
|
|
|
4137
4159
|
}));
|
|
4138
4160
|
print(formatStep(steps[steps.length - 1]));
|
|
4139
4161
|
}
|
|
4162
|
+
const properties = {};
|
|
4163
|
+
if (effectivePreset && effectivePreset !== "none") properties["branch_protection_level"] = effectivePreset;
|
|
4164
|
+
const isMonorepo = await access(join(input.context.repoRoot, "pnpm-workspace.yaml")).then(() => true).catch(() => false);
|
|
4165
|
+
properties["monorepo"] = String(isMonorepo);
|
|
4166
|
+
const manual = repo?.properties ?? {};
|
|
4167
|
+
if (manual.lifecycle) properties["lifecycle"] = manual.lifecycle;
|
|
4168
|
+
if (manual.open_source !== void 0) properties["open_source"] = String(manual.open_source);
|
|
4169
|
+
if (manual.runtime_environment) properties["runtime_environment"] = manual.runtime_environment;
|
|
4170
|
+
if (manual.uses_external_packages !== void 0) properties["uses_external_packages"] = String(manual.uses_external_packages);
|
|
4171
|
+
if (source.syncProperties) {
|
|
4172
|
+
steps.push(await runStep("source", "sync properties", dryRun, () => source.syncProperties(properties)));
|
|
4173
|
+
print(formatStep(steps[steps.length - 1]));
|
|
4174
|
+
}
|
|
4175
|
+
const topics = repo?.topics ?? [];
|
|
4176
|
+
if (topics.length > 0 && source.syncTopics) {
|
|
4177
|
+
steps.push(await runStep("source", "sync topics", dryRun, () => source.syncTopics(topics)));
|
|
4178
|
+
print(formatStep(steps[steps.length - 1]));
|
|
4179
|
+
}
|
|
4140
4180
|
}
|
|
4141
4181
|
if (loader.has("environments")) {
|
|
4142
4182
|
const envs = loader.get("environments");
|
package/dist/index.d.mts
CHANGED
|
@@ -41,10 +41,36 @@ interface RepoPolicyConfig {
|
|
|
41
41
|
* "none" — skips repo settings + ruleset entirely.
|
|
42
42
|
*
|
|
43
43
|
* @default "balanced"
|
|
44
|
+
* @deprecated Use `project.repo.protection` instead.
|
|
44
45
|
*/
|
|
45
46
|
preset?: "balanced" | "strict" | "none";
|
|
46
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* CI check context names required on the default branch (used by "strict").
|
|
49
|
+
* @deprecated Use `project.repo.requiredChecks` instead.
|
|
50
|
+
*/
|
|
51
|
+
requiredChecks?: string[];
|
|
52
|
+
}
|
|
53
|
+
type RepoProtection = "balanced" | "strict" | "none";
|
|
54
|
+
interface RepoProperties {
|
|
55
|
+
lifecycle?: "active" | "experimental" | "deprecated";
|
|
56
|
+
open_source?: boolean;
|
|
57
|
+
runtime_environment?: "node" | "browser" | "universal" | "none";
|
|
58
|
+
uses_external_packages?: boolean;
|
|
59
|
+
}
|
|
60
|
+
interface RepoConfig {
|
|
61
|
+
/** "owner/name" — the GitHub repository coordinate. */
|
|
62
|
+
name: string;
|
|
63
|
+
/**
|
|
64
|
+
* Branch protection preset applied by `holocron setup`. When omitted,
|
|
65
|
+
* no protection is applied and no `branch_protection_level` property is set.
|
|
66
|
+
*/
|
|
67
|
+
protection?: RepoProtection;
|
|
68
|
+
/** CI check context names required on the default branch (only used when `protection` is "strict"). */
|
|
47
69
|
requiredChecks?: string[];
|
|
70
|
+
/** GitHub topics set on the repository. */
|
|
71
|
+
topics?: string[];
|
|
72
|
+
/** GitHub custom properties synced to the org dashboard. */
|
|
73
|
+
properties?: RepoProperties;
|
|
48
74
|
}
|
|
49
75
|
interface AppConfig {
|
|
50
76
|
name: string;
|
|
@@ -59,12 +85,12 @@ interface HolocronConfig {
|
|
|
59
85
|
name: string;
|
|
60
86
|
description?: string;
|
|
61
87
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* need a repo (github, etc.) don't require `--repo` on every
|
|
65
|
-
*
|
|
88
|
+
* Repository identity and metadata. When set, `PluginLoader` injects
|
|
89
|
+
* `repo.name` into every plugin's `RuntimeContext.repo` so plugins that
|
|
90
|
+
* need a repo (github, etc.) don't require `--repo` on every invocation.
|
|
91
|
+
* `--repo` on the command line still overrides.
|
|
66
92
|
*/
|
|
67
|
-
repo?:
|
|
93
|
+
repo?: RepoConfig;
|
|
68
94
|
/**
|
|
69
95
|
* Repo-level policy applied by `holocron setup`. Defines merge
|
|
70
96
|
* strategy, branch protection rulesets, and security defaults.
|
|
@@ -190,4 +216,4 @@ interface LoadedConfig {
|
|
|
190
216
|
*/
|
|
191
217
|
declare function loadConfig(cwd: string): Promise<LoadedConfig>;
|
|
192
218
|
//#endregion
|
|
193
|
-
export { Analytics, AppConfig, Auth, AuthDescription, AuthError, AuthEvent, AuthEventType, AuthIdentity, AuthUser, CARDINALITY, CapabilityConfigPackage, CapabilityImpls, CapabilityKey, Cardinality, CardinalityFor, Ci, CiRun, CiRunFilter, CiRunStatus, ConfigError, ConfigFileError, ConnectionStringOptions, CreateAuthUserInput, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, Dns, DnsRecord, DnsRecordType, DoctorConfig, EnsureResult, Environment, EnvironmentReviewer, Environments, HolocronConfig, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, LoadedConfig, MultiEntry, NormalizedAuthUser, Notifications, Observability, ParseWebhookInput, ProviderApiError, ProviderIdentity, ProviderOptions, REQUIRED_CAPABILITIES, RawProviderEntry, RawProvidersConfig, RepoPolicyConfig, RepoRef, RepoSettings, type RequestOptions, ResolveTokenConfig, type ResolveTokenInput, ResolvedCapability, ResolvedHolocronConfig, ResolvedProviderEntry, ResolvedProvidersConfig, ResolvedTuple, type RestClient, type RestClientConfig, Ruleset, SecretScope, Secrets, SingleEntry, Source, StatusCategory, Storage, StorageBranch, Tooling, ToolingDoctorReport, TrackerDoctorReport, TrackerUser, Vault, WebhookDashboardInfo, WebhookVerificationError, createResolveToken, createRestClient, defineConfig, deleteToken, getToken, isMulti, listStoredProviders, loadConfig, resolveConfig, resolveEntry, resolvePluginPackage, setToken };
|
|
219
|
+
export { Analytics, AppConfig, Auth, AuthDescription, AuthError, AuthEvent, AuthEventType, AuthIdentity, AuthUser, CARDINALITY, CapabilityConfigPackage, CapabilityImpls, CapabilityKey, Cardinality, CardinalityFor, Ci, CiRun, CiRunFilter, CiRunStatus, ConfigError, ConfigFileError, ConnectionStringOptions, CreateAuthUserInput, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, Dns, DnsRecord, DnsRecordType, DoctorConfig, EnsureResult, Environment, EnvironmentReviewer, Environments, HolocronConfig, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, LoadedConfig, MultiEntry, NormalizedAuthUser, Notifications, Observability, ParseWebhookInput, ProviderApiError, ProviderIdentity, ProviderOptions, REQUIRED_CAPABILITIES, RawProviderEntry, RawProvidersConfig, RepoConfig, RepoPolicyConfig, RepoProperties, RepoProtection, RepoRef, RepoSettings, type RequestOptions, ResolveTokenConfig, type ResolveTokenInput, ResolvedCapability, ResolvedHolocronConfig, ResolvedProviderEntry, ResolvedProvidersConfig, ResolvedTuple, type RestClient, type RestClientConfig, Ruleset, SecretScope, Secrets, SingleEntry, Source, StatusCategory, Storage, StorageBranch, Tooling, ToolingDoctorReport, TrackerDoctorReport, TrackerUser, Vault, WebhookDashboardInfo, WebhookVerificationError, createResolveToken, createRestClient, defineConfig, deleteToken, getToken, isMulti, listStoredProviders, loadConfig, resolveConfig, resolveEntry, resolvePluginPackage, setToken };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/cli",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.44",
|
|
4
4
|
"description": "The Holocron CLI — a pluggable, capability-based orchestrator for spinning up and operating software projects.",
|
|
5
5
|
"homepage": "https://github.com/theholocron/holocron/tree/main/packages/cli#readme",
|
|
6
6
|
"bugs": "https://github.com/theholocron/holocron/issues",
|