@treeseed/cli 0.1.1 → 0.4.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.
Files changed (200) hide show
  1. package/README.md +27 -26
  2. package/dist/cli/handlers/auth-login.d.ts +2 -0
  3. package/dist/cli/handlers/auth-login.js +67 -0
  4. package/dist/cli/handlers/auth-logout.d.ts +2 -0
  5. package/dist/cli/handlers/auth-logout.js +20 -0
  6. package/dist/cli/handlers/auth-whoami.d.ts +2 -0
  7. package/dist/cli/handlers/auth-whoami.js +24 -0
  8. package/dist/cli/handlers/close.js +19 -53
  9. package/dist/cli/handlers/config.js +33 -53
  10. package/dist/cli/handlers/destroy.js +34 -79
  11. package/dist/{src/cli/handlers/ship.d.ts → cli/handlers/dev.d.ts} +1 -1
  12. package/dist/cli/handlers/dev.js +19 -0
  13. package/dist/cli/handlers/doctor.js +13 -6
  14. package/dist/cli/handlers/init.js +32 -8
  15. package/dist/cli/handlers/release.js +21 -53
  16. package/dist/cli/handlers/rollback.js +8 -8
  17. package/dist/cli/handlers/save.js +21 -79
  18. package/dist/cli/handlers/stage.d.ts +2 -0
  19. package/dist/cli/handlers/stage.js +28 -0
  20. package/dist/cli/handlers/status.js +35 -26
  21. package/dist/{src/cli/handlers/deploy.d.ts → cli/handlers/switch.d.ts} +1 -1
  22. package/dist/cli/handlers/switch.js +29 -0
  23. package/dist/{src/cli/handlers/next.d.ts → cli/handlers/sync.d.ts} +1 -1
  24. package/dist/cli/handlers/sync.js +26 -0
  25. package/dist/cli/handlers/tasks.d.ts +2 -0
  26. package/dist/cli/handlers/tasks.js +31 -0
  27. package/dist/cli/handlers/template.d.ts +2 -0
  28. package/dist/cli/handlers/template.js +27 -0
  29. package/dist/cli/handlers/workflow.d.ts +6 -0
  30. package/dist/cli/handlers/workflow.js +71 -0
  31. package/dist/{src/cli → cli}/help.d.ts +2 -2
  32. package/dist/cli/help.js +36 -24
  33. package/dist/cli/main.d.ts +6 -0
  34. package/dist/cli/main.js +14 -19
  35. package/dist/cli/operations-help.d.ts +1 -0
  36. package/dist/cli/operations-help.js +1 -0
  37. package/dist/cli/operations-parser.d.ts +1 -0
  38. package/dist/cli/operations-parser.js +1 -0
  39. package/dist/cli/operations-registry.d.ts +5 -0
  40. package/dist/cli/operations-registry.js +260 -0
  41. package/dist/cli/operations-types.d.ts +72 -0
  42. package/dist/cli/parser.d.ts +3 -0
  43. package/dist/cli/parser.js +1 -6
  44. package/dist/cli/registry.d.ts +25 -0
  45. package/dist/cli/registry.js +28 -416
  46. package/dist/cli/repair.js +6 -4
  47. package/dist/cli/runtime.d.ts +31 -0
  48. package/dist/cli/runtime.js +240 -111
  49. package/dist/cli/types.d.ts +1 -0
  50. package/dist/{src/cli → cli}/workflow-state.d.ts +9 -0
  51. package/dist/cli/workflow-state.js +45 -21
  52. package/package.json +13 -13
  53. package/dist/cli/handlers/continue.js +0 -23
  54. package/dist/cli/handlers/deploy.js +0 -139
  55. package/dist/cli/handlers/next.js +0 -27
  56. package/dist/cli/handlers/prepare.js +0 -8
  57. package/dist/cli/handlers/promote.js +0 -8
  58. package/dist/cli/handlers/publish.js +0 -8
  59. package/dist/cli/handlers/setup.js +0 -48
  60. package/dist/cli/handlers/ship.js +0 -49
  61. package/dist/cli/handlers/start.js +0 -97
  62. package/dist/cli/handlers/teardown.js +0 -50
  63. package/dist/cli/handlers/work.js +0 -85
  64. package/dist/scripts/aggregate-book.d.ts +0 -1
  65. package/dist/scripts/aggregate-book.js +0 -121
  66. package/dist/scripts/assert-release-tag-version.d.ts +0 -1
  67. package/dist/scripts/assert-release-tag-version.js +0 -21
  68. package/dist/scripts/build-dist.d.ts +0 -1
  69. package/dist/scripts/build-dist.js +0 -108
  70. package/dist/scripts/build-tenant-worker.d.ts +0 -1
  71. package/dist/scripts/build-tenant-worker.js +0 -36
  72. package/dist/scripts/cleanup-markdown.d.ts +0 -2
  73. package/dist/scripts/cleanup-markdown.js +0 -373
  74. package/dist/scripts/config-runtime-lib.d.ts +0 -122
  75. package/dist/scripts/config-runtime-lib.js +0 -505
  76. package/dist/scripts/config-treeseed.d.ts +0 -2
  77. package/dist/scripts/config-treeseed.js +0 -81
  78. package/dist/scripts/d1-migration-lib.d.ts +0 -6
  79. package/dist/scripts/d1-migration-lib.js +0 -90
  80. package/dist/scripts/deploy-lib.d.ts +0 -127
  81. package/dist/scripts/deploy-lib.js +0 -841
  82. package/dist/scripts/ensure-mailpit.d.ts +0 -1
  83. package/dist/scripts/ensure-mailpit.js +0 -29
  84. package/dist/scripts/git-workflow-lib.d.ts +0 -25
  85. package/dist/scripts/git-workflow-lib.js +0 -136
  86. package/dist/scripts/github-automation-lib.d.ts +0 -156
  87. package/dist/scripts/github-automation-lib.js +0 -242
  88. package/dist/scripts/local-dev-lib.d.ts +0 -9
  89. package/dist/scripts/local-dev-lib.js +0 -84
  90. package/dist/scripts/local-dev.d.ts +0 -1
  91. package/dist/scripts/local-dev.js +0 -129
  92. package/dist/scripts/logs-mailpit.d.ts +0 -1
  93. package/dist/scripts/logs-mailpit.js +0 -2
  94. package/dist/scripts/mailpit-runtime.d.ts +0 -4
  95. package/dist/scripts/mailpit-runtime.js +0 -57
  96. package/dist/scripts/package-tools.d.ts +0 -22
  97. package/dist/scripts/package-tools.js +0 -255
  98. package/dist/scripts/patch-starlight-content-path.d.ts +0 -1
  99. package/dist/scripts/patch-starlight-content-path.js +0 -172
  100. package/dist/scripts/paths.d.ts +0 -17
  101. package/dist/scripts/paths.js +0 -26
  102. package/dist/scripts/publish-package.d.ts +0 -1
  103. package/dist/scripts/publish-package.js +0 -19
  104. package/dist/scripts/release-verify.d.ts +0 -1
  105. package/dist/scripts/release-verify.js +0 -136
  106. package/dist/scripts/run-fixture-astro-command.d.ts +0 -1
  107. package/dist/scripts/run-fixture-astro-command.js +0 -18
  108. package/dist/scripts/save-deploy-preflight-lib.d.ts +0 -34
  109. package/dist/scripts/save-deploy-preflight-lib.js +0 -69
  110. package/dist/scripts/scaffold-site.d.ts +0 -2
  111. package/dist/scripts/scaffold-site.js +0 -92
  112. package/dist/scripts/stop-mailpit.d.ts +0 -1
  113. package/dist/scripts/stop-mailpit.js +0 -5
  114. package/dist/scripts/sync-dev-vars.d.ts +0 -1
  115. package/dist/scripts/sync-dev-vars.js +0 -6
  116. package/dist/scripts/template-registry-lib.d.ts +0 -47
  117. package/dist/scripts/template-registry-lib.js +0 -137
  118. package/dist/scripts/tenant-astro-command.d.ts +0 -1
  119. package/dist/scripts/tenant-astro-command.js +0 -3
  120. package/dist/scripts/tenant-build.d.ts +0 -1
  121. package/dist/scripts/tenant-build.js +0 -16
  122. package/dist/scripts/tenant-check.d.ts +0 -1
  123. package/dist/scripts/tenant-check.js +0 -7
  124. package/dist/scripts/tenant-d1-migrate-local.d.ts +0 -1
  125. package/dist/scripts/tenant-d1-migrate-local.js +0 -11
  126. package/dist/scripts/tenant-deploy.d.ts +0 -2
  127. package/dist/scripts/tenant-deploy.js +0 -180
  128. package/dist/scripts/tenant-destroy.d.ts +0 -2
  129. package/dist/scripts/tenant-destroy.js +0 -104
  130. package/dist/scripts/tenant-dev.d.ts +0 -1
  131. package/dist/scripts/tenant-dev.js +0 -171
  132. package/dist/scripts/tenant-lint.d.ts +0 -1
  133. package/dist/scripts/tenant-lint.js +0 -4
  134. package/dist/scripts/tenant-test.d.ts +0 -1
  135. package/dist/scripts/tenant-test.js +0 -4
  136. package/dist/scripts/test-cloudflare-local.d.ts +0 -1
  137. package/dist/scripts/test-cloudflare-local.js +0 -212
  138. package/dist/scripts/test-scaffold.d.ts +0 -2
  139. package/dist/scripts/test-scaffold.js +0 -297
  140. package/dist/scripts/treeseed.d.ts +0 -2
  141. package/dist/scripts/treeseed.js +0 -4
  142. package/dist/scripts/validate-templates.d.ts +0 -2
  143. package/dist/scripts/validate-templates.js +0 -4
  144. package/dist/scripts/watch-dev-lib.d.ts +0 -21
  145. package/dist/scripts/watch-dev-lib.js +0 -277
  146. package/dist/scripts/workspace-close.d.ts +0 -2
  147. package/dist/scripts/workspace-close.js +0 -24
  148. package/dist/scripts/workspace-command-e2e.d.ts +0 -2
  149. package/dist/scripts/workspace-command-e2e.js +0 -718
  150. package/dist/scripts/workspace-lint.d.ts +0 -1
  151. package/dist/scripts/workspace-lint.js +0 -9
  152. package/dist/scripts/workspace-preflight-lib.d.ts +0 -36
  153. package/dist/scripts/workspace-preflight-lib.js +0 -179
  154. package/dist/scripts/workspace-preflight.d.ts +0 -2
  155. package/dist/scripts/workspace-preflight.js +0 -22
  156. package/dist/scripts/workspace-publish-changed-packages.d.ts +0 -1
  157. package/dist/scripts/workspace-publish-changed-packages.js +0 -16
  158. package/dist/scripts/workspace-release-verify.d.ts +0 -1
  159. package/dist/scripts/workspace-release-verify.js +0 -81
  160. package/dist/scripts/workspace-release.d.ts +0 -2
  161. package/dist/scripts/workspace-release.js +0 -42
  162. package/dist/scripts/workspace-save-lib.d.ts +0 -42
  163. package/dist/scripts/workspace-save-lib.js +0 -220
  164. package/dist/scripts/workspace-save.d.ts +0 -2
  165. package/dist/scripts/workspace-save.js +0 -124
  166. package/dist/scripts/workspace-start-warning.js +0 -3
  167. package/dist/scripts/workspace-start.d.ts +0 -2
  168. package/dist/scripts/workspace-start.js +0 -71
  169. package/dist/scripts/workspace-test-unit.d.ts +0 -1
  170. package/dist/scripts/workspace-test-unit.js +0 -4
  171. package/dist/scripts/workspace-test.d.ts +0 -1
  172. package/dist/scripts/workspace-test.js +0 -11
  173. package/dist/scripts/workspace-tools.d.ts +0 -13
  174. package/dist/scripts/workspace-tools.js +0 -226
  175. package/dist/src/cli/handlers/continue.d.ts +0 -2
  176. package/dist/src/cli/handlers/prepare.d.ts +0 -2
  177. package/dist/src/cli/handlers/promote.d.ts +0 -2
  178. package/dist/src/cli/handlers/publish.d.ts +0 -2
  179. package/dist/src/cli/handlers/setup.d.ts +0 -2
  180. package/dist/src/cli/handlers/start.d.ts +0 -3
  181. package/dist/src/cli/handlers/teardown.d.ts +0 -2
  182. package/dist/src/cli/handlers/work.d.ts +0 -2
  183. package/dist/src/cli/main.d.ts +0 -6
  184. package/dist/src/cli/parser.d.ts +0 -3
  185. package/dist/src/cli/registry.d.ts +0 -27
  186. package/dist/src/cli/runtime.d.ts +0 -4
  187. package/dist/src/cli/types.d.ts +0 -71
  188. /package/dist/{src/cli → cli}/handlers/close.d.ts +0 -0
  189. /package/dist/{src/cli → cli}/handlers/config.d.ts +0 -0
  190. /package/dist/{src/cli → cli}/handlers/destroy.d.ts +0 -0
  191. /package/dist/{src/cli → cli}/handlers/doctor.d.ts +0 -0
  192. /package/dist/{src/cli → cli}/handlers/init.d.ts +0 -0
  193. /package/dist/{src/cli → cli}/handlers/release.d.ts +0 -0
  194. /package/dist/{src/cli → cli}/handlers/rollback.d.ts +0 -0
  195. /package/dist/{src/cli → cli}/handlers/save.d.ts +0 -0
  196. /package/dist/{src/cli → cli}/handlers/status.d.ts +0 -0
  197. /package/dist/{src/cli → cli}/handlers/utils.d.ts +0 -0
  198. /package/dist/{scripts/workspace-start-warning.d.ts → cli/operations-types.js} +0 -0
  199. /package/dist/{src/cli → cli}/repair.d.ts +0 -0
  200. /package/dist/{src/index.d.ts → index.d.ts} +0 -0
package/README.md CHANGED
@@ -2,22 +2,22 @@
2
2
 
3
3
  Operator-facing Treeseed CLI package.
4
4
 
5
- This package publishes the `treeseed` binary. It provides the unified TypeScript command interface for Treeseed workspace setup, branch workflow, deployment, validation, and release automation.
5
+ This package publishes the `treeseed` binary. `@treeseed/sdk` owns the reusable workflow and runtime capabilities; `@treeseed/cli` owns argv parsing, command help, terminal formatting, command handlers, and the installable executable surface.
6
6
 
7
7
  ## Requirements
8
8
 
9
- - Node `>=20`
9
+ - Node `>=22`
10
10
  - npm as the canonical package manager for install, CI, and release flows
11
11
 
12
12
  ## Install
13
13
 
14
- Install the CLI alongside the Treeseed runtime package:
14
+ Install the CLI with its runtime dependencies:
15
15
 
16
16
  ```bash
17
- npm install @treeseed/cli @treeseed/core
17
+ npm install @treeseed/cli @treeseed/sdk @treeseed/agent
18
18
  ```
19
19
 
20
- `@treeseed/cli` depends on `@treeseed/core`, `@treeseed/sdk`, and `@treeseed/agent` at package runtime. In normal consumer installs, npm resolves those package dependencies automatically.
20
+ `@treeseed/cli` is a thin installable wrapper over `@treeseed/sdk` workflow and operations interfaces plus the `@treeseed/agent` command namespace. In normal consumer installs, npm resolves the runtime dependencies automatically.
21
21
 
22
22
  After installation, the published binary is available as:
23
23
 
@@ -29,36 +29,37 @@ treeseed --help
29
29
 
30
30
  The main workflow commands exposed by the current CLI are:
31
31
 
32
- - `treeseed setup`
33
- - `treeseed work <branch-name> [--preview]`
34
- - `treeseed ship "<commit message>"`
35
- - `treeseed publish --environment <local|staging|prod>`
36
- - `treeseed promote --major|--minor|--patch`
37
- - `treeseed rollback <staging|prod> [--to <deploy-id|commit>]`
38
- - `treeseed teardown [--environment <local|staging|prod>]`
39
32
  - `treeseed status [--json]`
40
- - `treeseed next [--json]`
41
- - `treeseed continue [--json]`
42
- - `treeseed doctor [--fix] [--json]`
43
-
44
- The CLI also keeps compatibility commands such as `init`, `config`, `start`, `deploy`, `save`, `release`, `close`, and `destroy`.
33
+ - `treeseed config`
34
+ - `treeseed tasks [--json]`
35
+ - `treeseed switch <branch-name> [--preview]`
36
+ - `treeseed dev`
37
+ - `treeseed save "<commit message>"`
38
+ - `treeseed stage "<resolution message>"`
39
+ - `treeseed close "<close reason>"`
40
+ - `treeseed release --major|--minor|--patch`
41
+ - `treeseed destroy --environment <local|staging|prod>`
42
+
43
+ Support utilities such as `treeseed rollback`, `treeseed doctor`, `treeseed auth:*`, `treeseed template`, `treeseed sync`, `treeseed lint`, `treeseed test`, `treeseed build`, service helpers, and `treeseed agents ...` remain available.
45
44
 
46
45
  Use `treeseed help` for the full command list and `treeseed help <command>` for command-specific usage, options, and examples.
47
46
 
48
47
  ## Common Commands
49
48
 
50
49
  ```bash
51
- treeseed setup
52
- treeseed work feature/search-improvements --preview
53
- treeseed ship "feat: add search filters"
54
- treeseed publish --environment staging
55
- treeseed promote --patch
50
+ treeseed status
51
+ treeseed config
52
+ treeseed switch feature/search-improvements --preview
53
+ treeseed dev
54
+ treeseed save "feat: add search filters"
55
+ treeseed stage "feat: add search filters"
56
+ treeseed release --patch
56
57
  treeseed status --json
57
58
  ```
58
59
 
59
60
  ## Maintainer Workflow
60
61
 
61
- All package maintenance commands are npm-based and run from the `cli/` package root.
62
+ All package maintenance commands are npm-based and run from the `cli/` package root. This package verifies the published command surface, parser/help behavior, and packaged artifact shape.
62
63
 
63
64
  Install dependencies:
64
65
 
@@ -88,8 +89,8 @@ The release verification flow is intentionally stricter than a normal test run:
88
89
 
89
90
  1. Build `dist`
90
91
  2. Validate publishable output for forbidden workspace references
91
- 3. Run the CLI test suite
92
- 4. Run scaffold verification
92
+ 3. Assert the published artifact only contains the thin wrapper entrypoints
93
+ 4. Run the CLI wrapper test suite
93
94
  5. Pack the CLI tarball
94
95
  6. Smoke-test the packed install by running `treeseed --help` from the packed artifact
95
96
 
@@ -112,4 +113,4 @@ For example, package version `0.1.0` publishes from tag `0.1.0`.
112
113
  ## Notes
113
114
 
114
115
  - `package-lock.json` should be committed and kept current so `npm ci` remains reproducible in CI and release jobs.
115
- - The README intentionally documents the command surface at a high level. The canonical source of command usage and options is the CLI help output generated from `src/cli/registry.ts`.
116
+ - The README intentionally documents the command surface at a high level. The canonical source of operation identity and semantics is `@treeseed/sdk`, while `@treeseed/cli` owns argv parsing, help rendering, and terminal formatting.
@@ -0,0 +1,2 @@
1
+ import type { TreeseedCommandHandler } from '../types.js';
2
+ export declare const handleAuthLogin: TreeseedCommandHandler;
@@ -0,0 +1,67 @@
1
+ import { RemoteTreeseedAuthClient, RemoteTreeseedClient } from "@treeseed/sdk/remote";
2
+ import {
3
+ resolveTreeseedRemoteConfig,
4
+ setTreeseedRemoteSession
5
+ } from "@treeseed/sdk/workflow-support";
6
+ import { guidedResult } from "./utils.js";
7
+ function sleep(ms) {
8
+ return new Promise((resolve) => setTimeout(resolve, ms));
9
+ }
10
+ const handleAuthLogin = async (invocation, context) => {
11
+ const tenantRoot = context.cwd;
12
+ const remoteConfig = resolveTreeseedRemoteConfig(tenantRoot, context.env);
13
+ const hostId = typeof invocation.args.host === "string" ? invocation.args.host : remoteConfig.activeHostId;
14
+ const client = new RemoteTreeseedAuthClient(new RemoteTreeseedClient({
15
+ ...remoteConfig,
16
+ activeHostId: hostId
17
+ }));
18
+ const started = await client.startDeviceFlow({
19
+ clientName: "treeseed-cli",
20
+ scopes: ["auth:me", "sdk", "operations"]
21
+ });
22
+ if (context.outputFormat !== "json") {
23
+ context.write(`Open ${started.verificationUriComplete}`, "stdout");
24
+ context.write(`User code: ${started.userCode}`, "stdout");
25
+ context.write("Waiting for approval...", "stdout");
26
+ }
27
+ const deadline = Date.parse(started.expiresAt);
28
+ while (Date.now() < deadline) {
29
+ const response = await client.pollDeviceFlow({ deviceCode: started.deviceCode });
30
+ if (response.ok && response.status === "approved") {
31
+ setTreeseedRemoteSession(tenantRoot, {
32
+ hostId,
33
+ accessToken: response.accessToken,
34
+ refreshToken: response.refreshToken,
35
+ expiresAt: response.expiresAt,
36
+ principal: response.principal
37
+ });
38
+ return guidedResult({
39
+ command: "auth:login",
40
+ summary: "Treeseed API login completed successfully.",
41
+ facts: [
42
+ { label: "Host", value: hostId },
43
+ { label: "Principal", value: response.principal.displayName ?? response.principal.id },
44
+ { label: "Scopes", value: response.principal.scopes.join(", ") }
45
+ ],
46
+ report: {
47
+ hostId,
48
+ principal: response.principal
49
+ }
50
+ });
51
+ }
52
+ if (!response.ok && response.status !== "already_used") {
53
+ return {
54
+ exitCode: 1,
55
+ stderr: [response.error]
56
+ };
57
+ }
58
+ await sleep(started.intervalSeconds * 1e3);
59
+ }
60
+ return {
61
+ exitCode: 1,
62
+ stderr: ["Treeseed API login expired before approval completed."]
63
+ };
64
+ };
65
+ export {
66
+ handleAuthLogin
67
+ };
@@ -0,0 +1,2 @@
1
+ import type { TreeseedCommandHandler } from '../types.js';
2
+ export declare const handleAuthLogout: TreeseedCommandHandler;
@@ -0,0 +1,20 @@
1
+ import {
2
+ clearTreeseedRemoteSession,
3
+ resolveTreeseedRemoteConfig
4
+ } from "@treeseed/sdk/workflow-support";
5
+ import { guidedResult } from "./utils.js";
6
+ const handleAuthLogout = async (invocation, context) => {
7
+ const tenantRoot = context.cwd;
8
+ const remoteConfig = resolveTreeseedRemoteConfig(tenantRoot, context.env);
9
+ const hostId = typeof invocation.args.host === "string" ? invocation.args.host : remoteConfig.activeHostId;
10
+ clearTreeseedRemoteSession(tenantRoot, hostId);
11
+ return guidedResult({
12
+ command: "auth:logout",
13
+ summary: "Cleared the local Treeseed API session.",
14
+ facts: [{ label: "Host", value: hostId }],
15
+ report: { hostId }
16
+ });
17
+ };
18
+ export {
19
+ handleAuthLogout
20
+ };
@@ -0,0 +1,2 @@
1
+ import type { TreeseedCommandHandler } from '../types.js';
2
+ export declare const handleAuthWhoAmI: TreeseedCommandHandler;
@@ -0,0 +1,24 @@
1
+ import { RemoteTreeseedAuthClient, RemoteTreeseedClient } from "@treeseed/sdk/remote";
2
+ import { resolveTreeseedRemoteConfig } from "@treeseed/sdk/workflow-support";
3
+ import { guidedResult } from "./utils.js";
4
+ const handleAuthWhoAmI = async (_invocation, context) => {
5
+ const remoteConfig = resolveTreeseedRemoteConfig(context.cwd, context.env);
6
+ const client = new RemoteTreeseedAuthClient(new RemoteTreeseedClient(remoteConfig));
7
+ const response = await client.whoAmI();
8
+ return guidedResult({
9
+ command: "auth:whoami",
10
+ summary: "Treeseed API identity",
11
+ facts: [
12
+ { label: "Host", value: remoteConfig.activeHostId },
13
+ { label: "Principal", value: response.payload.displayName ?? response.payload.id },
14
+ { label: "Scopes", value: response.payload.scopes.join(", ") }
15
+ ],
16
+ report: {
17
+ hostId: remoteConfig.activeHostId,
18
+ principal: response.payload
19
+ }
20
+ });
21
+ };
22
+ export {
23
+ handleAuthWhoAmI
24
+ };
@@ -1,59 +1,25 @@
1
- import { applyTreeseedEnvironmentToProcess } from "../../scripts/config-runtime-lib.js";
2
- import {
3
- cleanupDestroyedState,
4
- createBranchPreviewDeployTarget,
5
- destroyCloudflareResources,
6
- loadDeployState,
7
- printDestroySummary,
8
- validateDestroyPrerequisites
9
- } from "../../scripts/deploy-lib.js";
10
- import {
11
- assertFeatureBranch,
12
- deleteLocalBranch,
13
- deleteRemoteBranch,
14
- mergeCurrentBranchIntoStaging
15
- } from "../../scripts/git-workflow-lib.js";
16
- import { loadCliDeployConfig } from "../../scripts/package-tools.js";
17
- import { runWorkspaceSavePreflight } from "../../scripts/save-deploy-preflight-lib.js";
18
1
  import { guidedResult } from "./utils.js";
19
- const handleClose = (_invocation, context) => {
20
- const commandName = _invocation.commandName || "close";
21
- const tenantRoot = context.cwd;
22
- const featureBranch = assertFeatureBranch(tenantRoot);
23
- const previewTarget = createBranchPreviewDeployTarget(featureBranch);
24
- const deployConfig = loadCliDeployConfig(tenantRoot);
25
- const previewState = loadDeployState(tenantRoot, deployConfig, { target: previewTarget });
26
- runWorkspaceSavePreflight({ cwd: tenantRoot });
27
- const repoDir = mergeCurrentBranchIntoStaging(tenantRoot, featureBranch);
28
- if (previewState.readiness?.initialized) {
29
- applyTreeseedEnvironmentToProcess({ tenantRoot, scope: "staging" });
30
- validateDestroyPrerequisites(tenantRoot, { requireRemote: true });
31
- const result = destroyCloudflareResources(tenantRoot, { target: previewTarget });
32
- printDestroySummary(result);
33
- }
34
- cleanupDestroyedState(tenantRoot, { target: previewTarget });
35
- deleteRemoteBranch(repoDir, featureBranch);
36
- deleteLocalBranch(repoDir, featureBranch);
37
- return {
38
- ...guidedResult({
39
- command: commandName,
40
- summary: `Treeseed ${commandName} completed successfully.`,
2
+ import { createWorkflowSdk, renderWorkflowNextSteps, workflowErrorResult } from "./workflow.js";
3
+ const handleClose = async (invocation, context) => {
4
+ try {
5
+ const result = await createWorkflowSdk(context).close({
6
+ message: invocation.positionals.join(" ").trim()
7
+ });
8
+ const payload = result.payload;
9
+ return guidedResult({
10
+ command: invocation.commandName || "close",
11
+ summary: "Treeseed close completed successfully.",
41
12
  facts: [
42
- { label: "Merged branch", value: featureBranch },
43
- { label: "Merge target", value: "staging" },
44
- { label: "Preview cleanup", value: previewState.readiness?.initialized ? "performed" : "not needed" }
45
- ],
46
- nextSteps: [
47
- "treeseed deploy --environment staging",
48
- "treeseed release --patch"
13
+ { label: "Closed branch", value: payload.branchName },
14
+ { label: "Deprecated tag", value: payload.deprecatedTag.tagName },
15
+ { label: "Preview cleanup", value: payload.previewCleanup.performed ? "performed" : "not needed" }
49
16
  ],
50
- report: {
51
- branchName: featureBranch,
52
- mergeTarget: "staging",
53
- previewCleanup: previewState.readiness?.initialized === true
54
- }
55
- })
56
- };
17
+ nextSteps: renderWorkflowNextSteps(result),
18
+ report: payload
19
+ });
20
+ } catch (error) {
21
+ return workflowErrorResult(error);
22
+ }
57
23
  };
58
24
  export {
59
25
  handleClose
@@ -1,72 +1,52 @@
1
1
  import readline from "node:readline/promises";
2
2
  import { stdin as input, stdout as output } from "node:process";
3
- import { collectCliPreflight } from "../../scripts/workspace-preflight-lib.js";
4
- import {
5
- applyTreeseedEnvironmentToProcess,
6
- ensureTreeseedGitignoreEntries,
7
- getTreeseedMachineConfigPaths,
8
- runTreeseedConfigWizard,
9
- writeTreeseedLocalEnvironmentFiles
10
- } from "../../scripts/config-runtime-lib.js";
11
3
  import { guidedResult } from "./utils.js";
4
+ import { createWorkflowSdk, renderWorkflowNextSteps, workflowErrorResult } from "./workflow.js";
12
5
  const handleConfig = async (invocation, context) => {
13
- const commandName = invocation.commandName || "config";
14
- const tenantRoot = context.cwd;
15
- const scopes = Array.isArray(invocation.args.environment) ? invocation.args.environment : invocation.args.environment ? [invocation.args.environment] : ["local", "staging", "prod"];
16
- const sync = typeof invocation.args.sync === "string" ? invocation.args.sync : "none";
17
- ensureTreeseedGitignoreEntries(tenantRoot);
18
- const preflight = collectCliPreflight({ cwd: tenantRoot, requireAuth: false });
19
6
  const rl = readline.createInterface({ input, output });
20
7
  try {
21
- if (context.outputFormat !== "json") {
22
- context.write("Treeseed configuration wizard", "stdout");
23
- context.write("This command writes a local machine config, generates .env.local and .dev.vars, and can sync GitHub or Cloudflare settings.", "stdout");
24
- context.write('Enter a value to set it, press Enter to keep the current/default value, or enter "-" to clear a value.\n', "stdout");
25
- }
26
- const result = await runTreeseedConfigWizard({
27
- tenantRoot,
28
- scopes,
29
- sync,
30
- authStatus: preflight.checks.auth,
31
- write: context.outputFormat === "json" ? () => {
32
- } : ((line) => context.write(line, "stdout")),
8
+ const workflow = createWorkflowSdk(context, {
9
+ write: context.outputFormat === "json" ? (() => {
10
+ }) : context.write,
33
11
  prompt: async (message) => {
34
12
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
35
13
  return "";
36
14
  }
37
- try {
38
- return await rl.question(message);
39
- } catch {
40
- return "";
41
- }
15
+ return rl.question(message);
42
16
  }
43
17
  });
44
- writeTreeseedLocalEnvironmentFiles(tenantRoot);
45
- applyTreeseedEnvironmentToProcess({ tenantRoot, scope: "local" });
46
- const { configPath, keyPath } = getTreeseedMachineConfigPaths(tenantRoot);
18
+ const result = await workflow.config({
19
+ environment: invocation.args.environment,
20
+ sync: invocation.args.sync,
21
+ printEnv: invocation.args.printEnv === true,
22
+ printEnvOnly: invocation.args.printEnvOnly === true,
23
+ showSecrets: invocation.args.showSecrets === true,
24
+ rotateMachineKey: invocation.args.rotateMachineKey === true,
25
+ nonInteractive: context.outputFormat === "json"
26
+ });
27
+ const payload = result.payload;
28
+ const toolHealth = payload.toolHealth;
29
+ const summary = payload.mode === "print-env-only" ? "Treeseed config environment report completed." : payload.mode === "rotate-machine-key" ? "Treeseed machine key rotated successfully." : "Treeseed config completed successfully.";
47
30
  return guidedResult({
48
- command: commandName,
49
- summary: `Treeseed ${commandName} completed successfully.`,
31
+ command: invocation.commandName || "config",
32
+ summary,
50
33
  facts: [
51
- { label: "Machine config", value: configPath },
52
- { label: "Machine key", value: keyPath },
53
- { label: "Updated values", value: result.updated.length },
54
- { label: "Initialized environments", value: result.initialized.map((entry) => entry.scope).join(", ") || "(none)" },
55
- { label: "GitHub sync", value: result.synced.github ? `${result.synced.github.secrets.length} secrets, ${result.synced.github.variables.length} variables` : "not run" },
56
- { label: "Cloudflare sync", value: result.synced.cloudflare ? `${result.synced.cloudflare.secrets.length} secrets, ${result.synced.cloudflare.varsManagedByWranglerConfig.length} vars` : "not run" }
34
+ { label: "Mode", value: payload.mode },
35
+ { label: "Scopes", value: Array.isArray(payload.scopes) ? payload.scopes.join(", ") : "(none)" },
36
+ { label: "Sync", value: payload.sync ?? "all" },
37
+ { label: "Safe repairs", value: Array.isArray(payload.repairs) ? payload.repairs.length : 0 },
38
+ { label: "Machine config", value: payload.configPath },
39
+ { label: "Machine key", value: payload.keyPath },
40
+ { label: "GitHub CLI", value: toolHealth?.githubCli?.available ? "ready" : "missing" },
41
+ { label: "gh act", value: toolHealth?.ghActExtension?.available ? "ready" : "missing" },
42
+ { label: "Docker", value: toolHealth?.dockerDaemon?.available ? "ready" : "missing" },
43
+ { label: "ACT verify", value: toolHealth?.actVerificationReady ? "ready" : "not ready" }
57
44
  ],
58
- nextSteps: [
59
- ...scopes.includes("local") ? ["treeseed dev"] : [],
60
- ...scopes.includes("staging") ? ["treeseed deploy --environment staging"] : [],
61
- ...scopes.includes("prod") ? ["treeseed deploy --environment prod"] : []
62
- ],
63
- report: {
64
- scopes,
65
- sync,
66
- result,
67
- preflight
68
- }
45
+ nextSteps: renderWorkflowNextSteps(result),
46
+ report: payload
69
47
  });
48
+ } catch (error) {
49
+ return workflowErrorResult(error);
70
50
  } finally {
71
51
  rl.close();
72
52
  }
@@ -1,93 +1,48 @@
1
1
  import readline from "node:readline/promises";
2
2
  import { stdin as input, stdout as output } from "node:process";
3
- import { applyTreeseedEnvironmentToProcess, assertTreeseedCommandEnvironment } from "../../scripts/config-runtime-lib.js";
4
- import {
5
- cleanupDestroyedState,
6
- createPersistentDeployTarget,
7
- destroyCloudflareResources,
8
- loadDeployState,
9
- printDestroySummary,
10
- validateDestroyPrerequisites
11
- } from "../../scripts/deploy-lib.js";
12
3
  import { guidedResult } from "./utils.js";
13
- function printDangerMessage(context, deployConfig, state, expectedConfirmation) {
14
- context.write("DANGER: treeseed destroy will permanently delete this site and its Cloudflare resources.", "stderr");
15
- context.write(` Site: ${deployConfig.name}`, "stderr");
16
- context.write(` Slug: ${deployConfig.slug}`, "stderr");
17
- context.write(` Worker: ${state.workerName}`, "stderr");
18
- context.write(` D1: ${state.d1Databases.SITE_DATA_DB.databaseName}`, "stderr");
19
- context.write(` KV FORM_GUARD_KV: ${state.kvNamespaces.FORM_GUARD_KV.name}`, "stderr");
20
- context.write(` KV SESSION: ${state.kvNamespaces.SESSION.name}`, "stderr");
21
- context.write(" This action is irreversible.", "stderr");
22
- context.write(` To continue, type exactly: ${expectedConfirmation}`, "stderr");
4
+ import { createWorkflowSdk, renderWorkflowNextSteps, workflowErrorResult } from "./workflow.js";
5
+ async function promptForConfirmation(expected) {
6
+ const rl = readline.createInterface({ input, output });
7
+ try {
8
+ return (await rl.question("Confirmation: ")).trim();
9
+ } finally {
10
+ rl.close();
11
+ }
23
12
  }
24
13
  const handleDestroy = async (invocation, context) => {
25
- const commandName = invocation.commandName || "destroy";
26
- const tenantRoot = context.cwd;
27
- const scope = String(invocation.args.environment);
28
- const target = createPersistentDeployTarget(scope);
29
- const dryRun = invocation.args.dryRun === true;
30
- const force = invocation.args.force === true;
31
- const skipConfirmation = invocation.args.skipConfirmation === true;
32
- const confirm = typeof invocation.args.confirm === "string" ? invocation.args.confirm : null;
33
- const removeBuildArtifacts = invocation.args.removeBuildArtifacts === true;
34
- applyTreeseedEnvironmentToProcess({ tenantRoot, scope });
35
- assertTreeseedCommandEnvironment({ tenantRoot, scope, purpose: "destroy" });
36
- const deployConfig = validateDestroyPrerequisites(tenantRoot, { requireRemote: !dryRun });
37
- const state = loadDeployState(tenantRoot, deployConfig, { target });
38
- const expectedConfirmation = deployConfig.slug;
39
- if (!skipConfirmation) {
40
- printDangerMessage(context, deployConfig, state, expectedConfirmation);
41
- const confirmed = confirm !== null ? confirm === expectedConfirmation : await (async () => {
42
- const rl = readline.createInterface({ input, output });
43
- try {
44
- return (await rl.question("Confirmation: ")).trim() === expectedConfirmation;
45
- } finally {
46
- rl.close();
14
+ try {
15
+ const result = await createWorkflowSdk(context, {
16
+ confirm: async (_message, expected) => {
17
+ if (typeof invocation.args.confirm === "string") {
18
+ return invocation.args.confirm === expected;
19
+ }
20
+ if (invocation.args.skipConfirmation === true || context.outputFormat === "json" || !process.stdin.isTTY || !process.stdout.isTTY) {
21
+ return false;
22
+ }
23
+ return await promptForConfirmation(expected) === expected;
47
24
  }
48
- })();
49
- if (!confirmed) {
50
- return { exitCode: 1, stderr: ["Destroy aborted: confirmation text did not match."] };
51
- }
52
- }
53
- const result = destroyCloudflareResources(tenantRoot, { dryRun, force, target });
54
- printDestroySummary(result);
55
- if (dryRun) {
25
+ }).destroy({
26
+ environment: String(invocation.args.environment),
27
+ dryRun: invocation.args.dryRun === true,
28
+ force: invocation.args.force === true,
29
+ removeBuildArtifacts: invocation.args.removeBuildArtifacts === true
30
+ });
31
+ const payload = result.payload;
56
32
  return guidedResult({
57
- command: commandName,
58
- summary: `Treeseed ${commandName} dry run completed.`,
33
+ command: invocation.commandName || "destroy",
34
+ summary: payload.dryRun ? "Treeseed destroy dry run completed." : "Treeseed destroy completed successfully.",
59
35
  facts: [
60
- { label: "Environment", value: scope },
61
- { label: "Remote deletion", value: "skipped" }
36
+ { label: "Environment", value: payload.scope },
37
+ { label: "Dry run", value: payload.dryRun ? "yes" : "no" },
38
+ { label: "Removed build artifacts", value: payload.removeBuildArtifacts ? "yes" : "no" }
62
39
  ],
63
- nextSteps: ["treeseed status"],
64
- report: {
65
- scope,
66
- dryRun: true,
67
- force,
68
- removeBuildArtifacts
69
- }
40
+ nextSteps: renderWorkflowNextSteps(result),
41
+ report: payload
70
42
  });
43
+ } catch (error) {
44
+ return workflowErrorResult(error);
71
45
  }
72
- cleanupDestroyedState(tenantRoot, { target, removeBuildArtifacts });
73
- return guidedResult({
74
- command: commandName,
75
- summary: `Treeseed ${commandName} completed and local deployment state was removed.`,
76
- facts: [
77
- { label: "Environment", value: scope },
78
- { label: "Removed build artifacts", value: removeBuildArtifacts ? "yes" : "no" }
79
- ],
80
- nextSteps: [
81
- `treeseed config --environment ${scope}`,
82
- "treeseed status"
83
- ],
84
- report: {
85
- scope,
86
- dryRun: false,
87
- force,
88
- removeBuildArtifacts
89
- }
90
- });
91
46
  };
92
47
  export {
93
48
  handleDestroy
@@ -1,2 +1,2 @@
1
1
  import type { TreeseedCommandHandler } from '../types.js';
2
- export declare const handleShip: TreeseedCommandHandler;
2
+ export declare const handleDev: TreeseedCommandHandler;
@@ -0,0 +1,19 @@
1
+ import { createWorkflowSdk, workflowErrorResult } from "./workflow.js";
2
+ const handleDev = async (invocation, context) => {
3
+ try {
4
+ const result = await createWorkflowSdk(context).dev({
5
+ watch: invocation.commandName === "dev:watch" || invocation.args.watch === true,
6
+ background: false,
7
+ stdio: "inherit"
8
+ });
9
+ return {
10
+ exitCode: result.ok ? 0 : 1,
11
+ report: result.payload
12
+ };
13
+ } catch (error) {
14
+ return workflowErrorResult(error);
15
+ }
16
+ };
17
+ export {
18
+ handleDev
19
+ };
@@ -1,4 +1,4 @@
1
- import { collectCliPreflight } from "../../scripts/workspace-preflight-lib.js";
1
+ import { collectCliPreflight } from "@treeseed/sdk/workflow-support";
2
2
  import { guidedResult } from "./utils.js";
3
3
  import { resolveTreeseedWorkflowState } from "../workflow-state.js";
4
4
  import { applyTreeseedSafeRepairs } from "../repair.js";
@@ -6,19 +6,26 @@ const handleDoctor = (invocation, context) => {
6
6
  const performedFixes = invocation.args.fix === true && resolveTreeseedWorkflowState(context.cwd).deployConfigPresent ? applyTreeseedSafeRepairs(context.cwd) : [];
7
7
  const state = resolveTreeseedWorkflowState(context.cwd);
8
8
  const preflight = collectCliPreflight({ cwd: context.cwd, requireAuth: false });
9
+ const railwayManagedServicesEnabled = Object.values(state.managedServices).some((service) => service.enabled);
9
10
  const mustFixNow = [];
10
11
  const optional = [];
11
- if (!state.workspaceRoot) mustFixNow.push("Run Treeseed from the workspace root so package commands and workflow state resolve correctly.");
12
- if (!state.repoRoot) mustFixNow.push("Initialize or clone the git repository before using save, close, deploy, or release flows.");
12
+ if (!state.workspaceRoot) mustFixNow.push("Run Treeseed inside a Treeseed workspace so package commands and workflow state can resolve correctly.");
13
+ if (!state.repoRoot) mustFixNow.push("Initialize or clone the git repository before using save, close, stage, or release flows.");
13
14
  if (!state.deployConfigPresent) mustFixNow.push("Create or restore treeseed.site.yaml so the tenant contract can be loaded.");
14
15
  if (preflight.missingCommands.includes("git")) mustFixNow.push("Install Git.");
15
16
  if (preflight.missingCommands.includes("npm")) mustFixNow.push("Install npm 10 or newer.");
16
17
  if (!state.files.machineConfig) mustFixNow.push("Run `treeseed config --environment local` to create the local machine config.");
17
18
  if (!state.files.envLocal) optional.push("Create `.env.local` or run `treeseed config --environment local` to generate it.");
18
19
  if (!state.files.devVars) optional.push("Generate `.dev.vars` by running `treeseed config --environment local`.");
19
- if (!state.auth.gh) optional.push("Authenticate `gh` if you want GitHub-backed save or release automation.");
20
- if (!state.auth.wrangler) optional.push("Authenticate `wrangler` before staging, preview, or production deployment work.");
21
- if (!state.auth.copilot) optional.push("Configure Copilot CLI only if you rely on local Copilot-assisted workflows.");
20
+ if (!state.auth.gh) optional.push("Configure `GH_TOKEN` for GitHub CLI automation and Copilot-backed workflows.");
21
+ if (!state.auth.wrangler) optional.push("Configure `CLOUDFLARE_API_TOKEN` before staging, preview, or production deployment work.");
22
+ if (!state.auth.railway && railwayManagedServicesEnabled) {
23
+ optional.push("Configure `RAILWAY_API_TOKEN` before deploying the managed Railway services.");
24
+ }
25
+ if (!state.auth.remoteApi && state.managedServices.api.enabled) {
26
+ optional.push("Run `treeseed auth:login` so the CLI can use the configured remote API.");
27
+ }
28
+ if (!state.auth.copilot) optional.push("Configure `GH_TOKEN` if you rely on local Copilot-assisted workflows.");
22
29
  return guidedResult({
23
30
  command: "doctor",
24
31
  summary: mustFixNow.length === 0 ? "Treeseed doctor found no blocking issues." : "Treeseed doctor found issues that need attention.",