@treeseed/cli 0.5.1 → 0.6.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.
|
@@ -73,7 +73,7 @@ function normalizedClusterKey(entry) {
|
|
|
73
73
|
return `cloudflare-${cluster}`;
|
|
74
74
|
}
|
|
75
75
|
if (provider === "railway") {
|
|
76
|
-
if (entry.id.includes("API_TOKEN")
|
|
76
|
+
if (entry.id.includes("API_TOKEN")) {
|
|
77
77
|
return "railway-access";
|
|
78
78
|
}
|
|
79
79
|
return `railway-${cluster}`;
|
|
@@ -110,9 +110,10 @@ function renderConfigResult(commandName, result) {
|
|
|
110
110
|
const configContext = payload.context;
|
|
111
111
|
const configReadiness = configContext?.configReadinessByScope?.local ?? {};
|
|
112
112
|
const readinessByScope = payload.result?.readinessByScope ?? {};
|
|
113
|
+
const resourceInventoryByScope = payload.result?.resourceInventoryByScope ?? payload.resourceInventoryByScope ?? {};
|
|
113
114
|
const secretSession = payload.secretSession;
|
|
114
115
|
const sharedStorageMigrations = payload.result?.sharedStorageMigrations;
|
|
115
|
-
const summary = payload.mode === "print-env-only" ? "Treeseed config environment report completed." : payload.mode === "rotate-machine-key" ? "Treeseed machine key rotated successfully." : payload.mode === "connect-market" ? "Knowledge Coop pairing completed successfully." : "Treeseed config completed successfully.";
|
|
116
|
+
const summary = payload.mode === "print-env-only" ? "Treeseed config environment report completed." : payload.mode === "rotate-machine-key" ? "Treeseed machine key rotated successfully." : payload.mode === "connect-market" ? "Knowledge Coop pairing completed successfully." : payload.mode === "bootstrap-preflight" ? "Treeseed bootstrap verification preflight completed." : payload.mode === "bootstrap" ? "Treeseed platform bootstrap completed successfully." : "Treeseed config completed successfully.";
|
|
116
117
|
const market = payload.market;
|
|
117
118
|
return guidedResult({
|
|
118
119
|
command: commandName,
|
|
@@ -124,11 +125,17 @@ function renderConfigResult(commandName, result) {
|
|
|
124
125
|
{ label: "Safe repairs", value: Array.isArray(payload.repairs) ? payload.repairs.length : 0 },
|
|
125
126
|
{ label: "Machine config", value: payload.configPath },
|
|
126
127
|
{ label: "Machine key", value: payload.keyPath },
|
|
128
|
+
{ label: "Passphrase env", value: payload.passphraseEnv?.configured ? "configured" : "unset" },
|
|
127
129
|
{ label: "Secrets session", value: describeSecretBootstrap(secretSession) },
|
|
128
130
|
{ label: "Shared consolidations", value: describeSharedStorageMigrations(sharedStorageMigrations) },
|
|
131
|
+
{ label: "Deployment key", value: resourceInventoryByScope.staging?.identity?.deploymentKey ?? resourceInventoryByScope.prod?.identity?.deploymentKey ?? "(unset)" },
|
|
132
|
+
{ label: "Team", value: resourceInventoryByScope.staging?.identity?.teamId ?? resourceInventoryByScope.prod?.identity?.teamId ?? "(unset)" },
|
|
133
|
+
{ label: "Project", value: resourceInventoryByScope.staging?.identity?.projectId ?? resourceInventoryByScope.prod?.identity?.projectId ?? "(unset)" },
|
|
129
134
|
{ label: "Local readiness", value: configReadinessLabel(readinessByScope.local) },
|
|
130
135
|
{ label: "Staging readiness", value: configReadinessLabel(readinessByScope.staging) },
|
|
131
136
|
{ label: "Prod readiness", value: configReadinessLabel(readinessByScope.prod) },
|
|
137
|
+
{ label: "Pages project", value: resourceInventoryByScope.staging?.resources?.pagesProject ?? resourceInventoryByScope.prod?.resources?.pagesProject ?? "(unset)" },
|
|
138
|
+
{ label: "R2 bucket", value: resourceInventoryByScope.staging?.resources?.contentBucket ?? resourceInventoryByScope.prod?.resources?.contentBucket ?? "(unset)" },
|
|
132
139
|
{ label: "GitHub token/config", value: configReadiness.github?.configured ? "configured" : "missing" },
|
|
133
140
|
{ label: "Cloudflare token/config", value: configReadiness.cloudflare?.configured ? "configured" : "missing" },
|
|
134
141
|
{ label: "Railway token/config", value: configReadiness.railway?.configured ? "configured" : "missing" },
|
|
@@ -147,7 +154,10 @@ function renderConfigResult(commandName, result) {
|
|
|
147
154
|
{ label: "Runtime ready", value: market.runtimeReady ? "yes" : "no" }
|
|
148
155
|
] : []
|
|
149
156
|
],
|
|
150
|
-
nextSteps:
|
|
157
|
+
nextSteps: [
|
|
158
|
+
...payload.passphraseEnv?.configured ? [] : [payload.passphraseEnv?.recommendedLaunch].filter(Boolean),
|
|
159
|
+
...renderWorkflowNextSteps(result)
|
|
160
|
+
],
|
|
151
161
|
report: payload
|
|
152
162
|
});
|
|
153
163
|
}
|
|
@@ -161,9 +171,9 @@ const handleConfig = async (invocation, context) => {
|
|
|
161
171
|
const sync = invocation.args.sync;
|
|
162
172
|
const interactive = context.outputFormat !== "json" && context.interactiveUi !== false && process.stdin.isTTY && process.stdout.isTTY;
|
|
163
173
|
const nonInteractive = invocation.args.nonInteractive === true || context.outputFormat === "json";
|
|
164
|
-
const operationalMode = invocation.args.printEnvOnly === true || invocation.args.rotateMachineKey === true || invocation.args.connectMarket === true;
|
|
174
|
+
const operationalMode = invocation.args.printEnvOnly === true || invocation.args.rotateMachineKey === true || invocation.args.connectMarket === true || invocation.args.bootstrap === true;
|
|
165
175
|
if (!interactive && !nonInteractive && !operationalMode) {
|
|
166
|
-
return fail("Treeseed config requires a TTY for the interactive editor. Re-run in a terminal, or use --non-interactive, --json, --print-env-only, --rotate-machine-key, or --connect-market.");
|
|
176
|
+
return fail("Treeseed config requires a TTY for the interactive editor. Re-run in a terminal, or use --non-interactive, --json, --bootstrap, --print-env-only, --rotate-machine-key, or --connect-market.");
|
|
167
177
|
}
|
|
168
178
|
if (interactive && !nonInteractive && !operationalMode) {
|
|
169
179
|
const tenantRoot = findNearestTreeseedRoot(context.cwd) ?? context.cwd;
|
|
@@ -247,6 +257,8 @@ const handleConfig = async (invocation, context) => {
|
|
|
247
257
|
const result = await workflow.config({
|
|
248
258
|
environment: invocation.args.environment,
|
|
249
259
|
sync,
|
|
260
|
+
bootstrap: invocation.args.bootstrap === true,
|
|
261
|
+
preflight: invocation.args.preflight === true,
|
|
250
262
|
printEnv: invocation.args.printEnv === true,
|
|
251
263
|
printEnvOnly: invocation.args.printEnvOnly === true,
|
|
252
264
|
showSecrets: invocation.args.showSecrets === true,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
inspectTreeseedKeyAgentStatus,
|
|
3
|
+
inspectTreeseedKeyAgentTransportDiagnostic,
|
|
4
|
+
inspectTreeseedPassphraseEnvDiagnostic,
|
|
3
5
|
lockTreeseedSecretSession,
|
|
4
6
|
migrateTreeseedMachineKeyToWrapped,
|
|
5
7
|
rotateTreeseedMachineKey,
|
|
@@ -11,8 +13,10 @@ import {
|
|
|
11
13
|
} from "@treeseed/sdk/workflow-support";
|
|
12
14
|
import { fail, guidedResult } from "./utils.js";
|
|
13
15
|
import { promptForNewPassphrase } from "./secret-prompts.js";
|
|
14
|
-
function renderStatus(command, tenantRoot) {
|
|
16
|
+
async function renderStatus(command, tenantRoot) {
|
|
15
17
|
const status = inspectTreeseedKeyAgentStatus(tenantRoot);
|
|
18
|
+
const passphraseEnv = inspectTreeseedPassphraseEnvDiagnostic();
|
|
19
|
+
const transport = await inspectTreeseedKeyAgentTransportDiagnostic();
|
|
16
20
|
return guidedResult({
|
|
17
21
|
command,
|
|
18
22
|
summary: status.unlocked ? "Treeseed secrets are unlocked." : "Treeseed secrets are locked.",
|
|
@@ -20,14 +24,24 @@ function renderStatus(command, tenantRoot) {
|
|
|
20
24
|
{ label: "Key agent", value: status.running ? "running" : "stopped" },
|
|
21
25
|
{ label: "Wrapped key", value: status.wrappedKeyPresent ? "present" : "missing" },
|
|
22
26
|
{ label: "Migration required", value: status.migrationRequired ? "yes" : "no" },
|
|
27
|
+
{ label: "Socket", value: transport.socketPresent ? "present" : "missing" },
|
|
28
|
+
{ label: "Socket connect", value: transport.socketConnectable ? "yes" : "no" },
|
|
29
|
+
{ label: "Socket health", value: transport.healthOk ? "ok" : "failed" },
|
|
23
30
|
{ label: "Idle timeout", value: `${Math.round(status.idleTimeoutMs / 1e3)}s` },
|
|
24
31
|
{ label: "Idle remaining", value: `${Math.round(status.idleRemainingMs / 1e3)}s` },
|
|
25
|
-
{ label: "Passphrase env", value:
|
|
26
|
-
{ label: "Key path", value: status.keyPath }
|
|
32
|
+
{ label: "Passphrase env", value: passphraseEnv.configured ? "configured" : "unset" },
|
|
33
|
+
{ label: "Key path", value: status.keyPath },
|
|
34
|
+
{ label: "Socket path", value: transport.socketPath }
|
|
27
35
|
],
|
|
28
36
|
report: {
|
|
29
|
-
status
|
|
30
|
-
|
|
37
|
+
status,
|
|
38
|
+
passphraseEnv,
|
|
39
|
+
transport
|
|
40
|
+
},
|
|
41
|
+
nextSteps: [
|
|
42
|
+
...passphraseEnv.configured ? [] : [passphraseEnv.recommendedLaunch],
|
|
43
|
+
...transport.lastError ? [`Key-agent transport error: ${transport.lastError}`] : []
|
|
44
|
+
]
|
|
31
45
|
});
|
|
32
46
|
}
|
|
33
47
|
function keyErrorResult(command, error) {
|
|
@@ -702,6 +702,8 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
702
702
|
{ name: "mouse", flags: "--mouse", description: "Opt into mouse capture for the config UI. Keyboard-first terminal behavior remains the default.", kind: "boolean" },
|
|
703
703
|
{ name: "environment", flags: "--environment <scope>", description: "Select all environments or limit configuration to local, staging, or prod. Defaults to all.", kind: "enum", repeatable: true, values: ["all", "local", "staging", "prod"] },
|
|
704
704
|
{ name: "sync", flags: "--sync <mode>", description: "Sync hosted secrets/variables to GitHub, Cloudflare, Railway, or all providers. Defaults to all.", kind: "enum", values: ["none", "github", "cloudflare", "railway", "all"] },
|
|
705
|
+
{ name: "bootstrap", flags: "--bootstrap", description: "Skip the editor and run platform reconciliation/bootstrap from the currently saved required values.", kind: "boolean" },
|
|
706
|
+
{ name: "preflight", flags: "--preflight", description: "Inspect bootstrap verification readiness and planned checks without mutating provider resources.", kind: "boolean" },
|
|
705
707
|
{ name: "nonInteractive", flags: "--non-interactive", description: "Apply resolved values without opening the interactive UI. Required for non-TTY automation unless using an operational mode such as --print-env-only.", kind: "boolean" },
|
|
706
708
|
{ name: "installMissingTooling", flags: "--install-missing-tooling", description: "Install missing config verification tooling such as `gh-act` during the run instead of only reporting it.", kind: "boolean" },
|
|
707
709
|
{ name: "printEnv", flags: "--print-env", description: "Print resolved environment values before remote initialization.", kind: "boolean" },
|
|
@@ -719,7 +721,7 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
719
721
|
{ name: "rotateRunnerToken", flags: "--rotate-runner-token", description: "Rotate the project runner credential while pairing the local hybrid repo.", kind: "boolean" },
|
|
720
722
|
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
721
723
|
],
|
|
722
|
-
examples: ["treeseed config", "treeseed config --full --mouse", "treeseed config --environment all", "treeseed config --environment local --sync none", "treeseed config --environment local --sync none --non-interactive", "treeseed config --environment staging --print-env-only --show-secrets", "treeseed config --rotate-machine-key", "treeseed config --connect-market --market-project-id kc_proj_123"],
|
|
724
|
+
examples: ["treeseed config", "treeseed config --full --mouse", "treeseed config --environment all", "treeseed config --environment staging --bootstrap", "treeseed config --environment staging --bootstrap --preflight", "treeseed config --environment local --sync none", "treeseed config --environment local --sync none --non-interactive", "treeseed config --environment staging --print-env-only --show-secrets", "treeseed config --rotate-machine-key", "treeseed config --connect-market --market-project-id kc_proj_123"],
|
|
723
725
|
notes: ["Does not create branch preview deployments. Use `treeseed switch <branch> --preview` for that."],
|
|
724
726
|
help: {
|
|
725
727
|
workflowPosition: "configure runtime",
|
|
@@ -745,6 +747,8 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
745
747
|
example("treeseed config", "Run the startup wizard", "Open the newcomer-friendly configuration wizard in human TTY mode."),
|
|
746
748
|
example("treeseed config --full", "Open the advanced editor directly", "Skip the startup wizard and go straight to the full configuration surface."),
|
|
747
749
|
example("treeseed config --full --mouse", "Opt into mouse capture for the editor", "Keep the keyboard-first defaults unless you explicitly want click and wheel interaction inside the config UI."),
|
|
750
|
+
example("treeseed config --environment staging --bootstrap", "Bootstrap infrastructure from saved config", "Skip the editor and run reconciliation/bootstrap when the required values are already configured."),
|
|
751
|
+
example("treeseed config --environment staging --bootstrap --preflight", "Inspect bootstrap verification readiness", "Show the resolved units, verification capabilities, and planned reconcile actions without mutating provider resources."),
|
|
748
752
|
example("treeseed config --environment local --sync none", "Edit local values without provider sync", "Limit the session to local values and avoid hosted synchronization while iterating locally."),
|
|
749
753
|
example("treeseed config --environment local --sync none --non-interactive", "Apply deterministic local config in automation", "Use the resolved current and suggested values without opening the interactive UI."),
|
|
750
754
|
example("treeseed config --environment staging --print-env-only --show-secrets", "Inspect a resolved environment report", "Print the resolved staging environment with full secret visibility and exit."),
|
|
@@ -756,6 +760,8 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
756
760
|
detail("--mouse", "Opt into terminal mouse capture for clicking, scrolling, and focus changes inside the config UI."),
|
|
757
761
|
detail("--environment <scope>", "Filter configuration to `all`, `local`, `staging`, or `prod`."),
|
|
758
762
|
detail("--sync <mode>", "Choose which provider surfaces should receive synchronized values after local updates are applied."),
|
|
763
|
+
detail("--bootstrap", "Skip the editor and run the reconcile/bootstrap path from the values already stored in machine config."),
|
|
764
|
+
detail("--preflight", "When combined with `--bootstrap`, inspect verification readiness and planned reconcile actions without mutating provider resources."),
|
|
759
765
|
detail("--non-interactive", "Apply resolved values without opening the interactive editor. Use this for automation when you do not want `--json` output."),
|
|
760
766
|
detail("--install-missing-tooling", "Allow config to install missing verification helpers such as the GitHub `gh-act` extension instead of only reporting them."),
|
|
761
767
|
detail("--print-env", "Print the resolved environment values before remote initialization continues."),
|
|
@@ -765,7 +771,7 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
765
771
|
],
|
|
766
772
|
automationNotes: [
|
|
767
773
|
"Use `--json` for machine-readable automation, or `--non-interactive` when you want deterministic application without interactive UI.",
|
|
768
|
-
"`--print-env-only`, `--rotate-machine-key`, and `--connect-market` are operational paths that bypass the interactive UI.",
|
|
774
|
+
"`--bootstrap`, `--bootstrap --preflight`, `--print-env-only`, `--rotate-machine-key`, and `--connect-market` are operational paths that bypass the interactive UI.",
|
|
769
775
|
"Config reports missing tooling by default. Use `--install-missing-tooling` when you want the command to attempt installation.",
|
|
770
776
|
"Shared versus scoped environment semantics are resolved inside the SDK; the CLI help should be treated as the operator-facing explanation layer."
|
|
771
777
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeseed/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Operator-facing Treeseed CLI package.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"release:publish": "node ./scripts/run-ts.mjs ./scripts/publish-package.ts"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@treeseed/sdk": "^0.
|
|
47
|
+
"@treeseed/sdk": "^0.6.0",
|
|
48
48
|
"ink": "^7.0.0",
|
|
49
49
|
"react": "^19.2.5"
|
|
50
50
|
},
|