seamless-cli 0.2.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 (100) hide show
  1. package/LICENSE +79 -0
  2. package/LICENSE.md +26 -0
  3. package/README.md +238 -0
  4. package/dist/commands/bootstrapAdmin.js +96 -0
  5. package/dist/commands/bootstrapAdmin.js.map +1 -0
  6. package/dist/commands/check.js +92 -0
  7. package/dist/commands/check.js.map +1 -0
  8. package/dist/commands/contribute.js +121 -0
  9. package/dist/commands/contribute.js.map +1 -0
  10. package/dist/commands/deploy.js +190 -0
  11. package/dist/commands/deploy.js.map +1 -0
  12. package/dist/commands/destroy.js +122 -0
  13. package/dist/commands/destroy.js.map +1 -0
  14. package/dist/commands/help.js +103 -0
  15. package/dist/commands/help.js.map +1 -0
  16. package/dist/commands/init.js +73 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/contributor/catalog.js +129 -0
  19. package/dist/contributor/catalog.js.map +1 -0
  20. package/dist/contributor/workspace.js +551 -0
  21. package/dist/contributor/workspace.js.map +1 -0
  22. package/dist/core/acm.js +24 -0
  23. package/dist/core/acm.js.map +1 -0
  24. package/dist/core/aws.js +374 -0
  25. package/dist/core/aws.js.map +1 -0
  26. package/dist/core/bootstrapSecret.js +31 -0
  27. package/dist/core/bootstrapSecret.js.map +1 -0
  28. package/dist/core/buildPush.js +91 -0
  29. package/dist/core/buildPush.js.map +1 -0
  30. package/dist/core/configure.js +25 -0
  31. package/dist/core/configure.js.map +1 -0
  32. package/dist/core/deployConfig.js +66 -0
  33. package/dist/core/deployConfig.js.map +1 -0
  34. package/dist/core/deployManifest.js +163 -0
  35. package/dist/core/deployManifest.js.map +1 -0
  36. package/dist/core/deploySecrets.js +31 -0
  37. package/dist/core/deploySecrets.js.map +1 -0
  38. package/dist/core/destroy.js +38 -0
  39. package/dist/core/destroy.js.map +1 -0
  40. package/dist/core/env.js +35 -0
  41. package/dist/core/env.js.map +1 -0
  42. package/dist/core/envDiscovery.js +153 -0
  43. package/dist/core/envDiscovery.js.map +1 -0
  44. package/dist/core/envRegistry.js +76 -0
  45. package/dist/core/envRegistry.js.map +1 -0
  46. package/dist/core/exec.js +17 -0
  47. package/dist/core/exec.js.map +1 -0
  48. package/dist/core/fetch.js +9 -0
  49. package/dist/core/fetch.js.map +1 -0
  50. package/dist/core/health.js +11 -0
  51. package/dist/core/health.js.map +1 -0
  52. package/dist/core/help.js +75 -0
  53. package/dist/core/help.js.map +1 -0
  54. package/dist/core/inspect.js +15 -0
  55. package/dist/core/inspect.js.map +1 -0
  56. package/dist/core/jwks.js +19 -0
  57. package/dist/core/jwks.js.map +1 -0
  58. package/dist/core/output.js +94 -0
  59. package/dist/core/output.js.map +1 -0
  60. package/dist/core/packageManager.js +10 -0
  61. package/dist/core/packageManager.js.map +1 -0
  62. package/dist/core/paths.js +7 -0
  63. package/dist/core/paths.js.map +1 -0
  64. package/dist/core/preReqs.js +14 -0
  65. package/dist/core/preReqs.js.map +1 -0
  66. package/dist/core/secrets.js +8 -0
  67. package/dist/core/secrets.js.map +1 -0
  68. package/dist/core/terraform.js +34 -0
  69. package/dist/core/terraform.js.map +1 -0
  70. package/dist/core/tfVars.js +69 -0
  71. package/dist/core/tfVars.js.map +1 -0
  72. package/dist/generators/admin/admin.js +2 -0
  73. package/dist/generators/admin/admin.js.map +1 -0
  74. package/dist/generators/auth/auth.js +47 -0
  75. package/dist/generators/auth/auth.js.map +1 -0
  76. package/dist/generators/backend/express.js +13 -0
  77. package/dist/generators/backend/express.js.map +1 -0
  78. package/dist/generators/config/config.js +43 -0
  79. package/dist/generators/config/config.js.map +1 -0
  80. package/dist/generators/deploy/aws/dev/files.js +36 -0
  81. package/dist/generators/deploy/aws/dev/files.js.map +1 -0
  82. package/dist/generators/deploy/aws/dev/template.js +1240 -0
  83. package/dist/generators/deploy/aws/dev/template.js.map +1 -0
  84. package/dist/generators/docker/docker.js +263 -0
  85. package/dist/generators/docker/docker.js.map +1 -0
  86. package/dist/generators/frontend/react.js +13 -0
  87. package/dist/generators/frontend/react.js.map +1 -0
  88. package/dist/index.js +43 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/prompts/contributeSetup.js +39 -0
  91. package/dist/prompts/contributeSetup.js.map +1 -0
  92. package/dist/prompts/deploySetup.js +244 -0
  93. package/dist/prompts/deploySetup.js.map +1 -0
  94. package/dist/prompts/projectSetup.js +73 -0
  95. package/dist/prompts/projectSetup.js.map +1 -0
  96. package/dist/utils/repoUtils.js +23 -0
  97. package/dist/utils/repoUtils.js.map +1 -0
  98. package/dist/utils/writeEnv.js +9 -0
  99. package/dist/utils/writeEnv.js.map +1 -0
  100. package/package.json +43 -0
package/LICENSE ADDED
@@ -0,0 +1,79 @@
1
+ GNU AFFERO GENERAL PUBLIC LICENSE
2
+ Version 3, 19 November 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc.
5
+ <https://fsf.org/>
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ This license is identical to the GNU General Public License, except that it also
10
+ ensures that software running as a network service makes its source code
11
+ available to users.
12
+
13
+ ---
14
+
15
+ TERMS AND CONDITIONS
16
+
17
+ 0. Definitions.
18
+
19
+ “This License” refers to version 3 of the GNU Affero General Public License.
20
+
21
+ “Copyright” also means copyright-like laws that apply to other kinds of works,
22
+ such as semiconductor masks.
23
+
24
+ The “Program” refers to any copyrightable work licensed under this License.
25
+ Each licensee is addressed as “you”.
26
+
27
+ To “modify” a work means to copy from or adapt all or part of the work in a
28
+ fashion requiring copyright permission, other than the making of an exact copy.
29
+
30
+ To “propagate” a work means to do anything with it that, without permission,
31
+ would make you directly or secondarily liable for infringement under applicable
32
+ copyright law, except executing it on a computer or modifying a private copy.
33
+
34
+ To “convey” a work means any kind of propagation that enables other parties to
35
+ make or receive copies.
36
+
37
+ An interactive user interface displays “Appropriate Legal Notices” to the extent
38
+ that it includes a convenient and prominently visible feature that displays an
39
+ appropriate copyright notice, and tells the user that there is no warranty for
40
+ the work (except to the extent that warranties are provided), that licensees may
41
+ convey the work under this License, and how to view a copy of this License.
42
+
43
+ ---
44
+
45
+ 13. Remote Network Interaction; Use with the GNU General Public License.
46
+
47
+ Notwithstanding any other provision of this License, if you modify the Program,
48
+ your modified version must prominently offer all users interacting with it
49
+ remotely through a computer network an opportunity to receive the Corresponding
50
+ Source of your version by providing access to the Corresponding Source from a
51
+ network server at no charge, through some standard or customary means of
52
+ facilitating copying of software.
53
+
54
+ ---
55
+
56
+ 15. Disclaimer of Warranty.
57
+
58
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
59
+ EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
60
+ PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
61
+ EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
62
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
63
+
64
+ ---
65
+
66
+ 16. Limitation of Liability.
67
+
68
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
69
+ COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
70
+ PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
71
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
72
+ THE PROGRAM.
73
+
74
+ ---
75
+
76
+ END OF TERMS AND CONDITIONS
77
+
78
+ You should have received a copy of the GNU Affero General Public License along
79
+ with this program. If not, see <https://www.gnu.org/licenses/>.
package/LICENSE.md ADDED
@@ -0,0 +1,26 @@
1
+ # License
2
+
3
+ Seamless CLI ("seamless-cli") is licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0-only)**.
4
+
5
+ - SPDX: `AGPL-3.0-only`
6
+
7
+ ## What this means (high level)
8
+
9
+ - You are free to **use**, **modify**, and **self-host** this software.
10
+ - If you **modify** this software and **run it as a network service** (for example, hosting it for others to use), you must **make the complete corresponding source code of your modified version available** to users of that service, under the AGPL.
11
+
12
+ This summary is not legal advice and does not replace the license text.
13
+
14
+ ## Full license text
15
+
16
+ The full license text is available here:
17
+
18
+ - https://www.gnu.org/licenses/agpl-3.0.html
19
+
20
+ You should include a copy of the AGPLv3 license in your distribution. If this repository does not contain the full license text yet, add it as `LICENSE` or `LICENSE.txt` (recommended), and keep this `LICENSE.md` as the human-friendly summary.
21
+
22
+ ## Commercial licensing
23
+
24
+ If you would like to embed Seamless Auth API into a proprietary product, redistribute it under different terms, or offer it as a managed service without AGPL obligations, commercial licensing may be available.
25
+
26
+ Contact: support@seamlessauth.com
package/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # Seamless CLI
2
+
3
+ [![License: AGPL-3.0-only](https://img.shields.io/badge/License-AGPL3-yellow.svg)](LICENSE)
4
+ [![npm version](https://img.shields.io/npm/v/seamless-cli.svg?style=flat)](https://www.npmjs.com/package/seamless-cli)
5
+
6
+ Seamless CLI is a command-line tool for bootstrapping applications with Seamless Auth, an open source, passwordless authentication system.
7
+
8
+ It guides you through creating a fully working authentication stack with a web app, API, and auth server that are already connected and ready to run.
9
+
10
+ ---
11
+
12
+ ## Getting started
13
+
14
+ Run the CLI with `npx`:
15
+
16
+ ```bash
17
+ npx seamless-cli init my-app
18
+ ```
19
+
20
+ Or run it in your current directory:
21
+
22
+ ```bash
23
+ npx seamless-cli init
24
+ ```
25
+
26
+ You’ll be guided through a short setup process where you can choose:
27
+
28
+ - Whether to create a web application
29
+ - Whether to create an API server
30
+ - How to run the auth server (local or Docker)
31
+ - Whether to run everything with Docker
32
+
33
+ ---
34
+
35
+ ## What gets created
36
+
37
+ Depending on your selections, the CLI generates a project like this:
38
+
39
+ ```text
40
+ my-app/
41
+ ├─ auth/ # Seamless Auth server (optional)
42
+ ├─ web/ # React web application (optional)
43
+ ├─ api/ # Express API server (optional)
44
+ ├─ docker-compose.yml (optional)
45
+ └─ README.md
46
+ ```
47
+
48
+ All services are preconfigured to work together.
49
+
50
+ - Web calls the API
51
+ - API communicates with the auth server
52
+ - Auth manages sessions and tokens
53
+
54
+ No manual wiring is required.
55
+
56
+ ---
57
+
58
+ ## Running your project
59
+
60
+ ### Option 1: Docker
61
+
62
+ If you choose Docker during setup:
63
+
64
+ ```bash
65
+ docker compose up
66
+ ```
67
+
68
+ This starts:
69
+
70
+ - PostgreSQL
71
+ - Auth server
72
+ - API server
73
+ - Web app
74
+
75
+ All services are configured to communicate correctly inside the container network.
76
+
77
+ ---
78
+
79
+ ### Option 2: Local development
80
+
81
+ If you choose to run locally:
82
+
83
+ #### 1. Start PostgreSQL
84
+
85
+ Make sure you have a local PostgreSQL instance running on port `5432`.
86
+
87
+ ---
88
+
89
+ #### 2. Start the auth server
90
+
91
+ ```bash
92
+ cd auth
93
+ npm install
94
+
95
+ npm run db:create
96
+ npm run db:migrate
97
+
98
+ npm run dev
99
+ ```
100
+
101
+ ---
102
+
103
+ #### 3. Start the API
104
+
105
+ ```bash
106
+ cd api
107
+ npm install
108
+ npm run dev
109
+ ```
110
+
111
+ ---
112
+
113
+ #### 4. Start the web app
114
+
115
+ ```bash
116
+ cd web
117
+ npm install
118
+ npm run dev
119
+ ```
120
+
121
+ ---
122
+
123
+ ## What is configured for you
124
+
125
+ Seamless CLI handles the parts that are usually difficult to get right:
126
+
127
+ - Shared API service tokens
128
+ - JWT signing configuration
129
+ - JWKS key generation for production mode
130
+ - Cross-service environment variables
131
+ - CORS and cookie-based session handling
132
+
133
+ Everything is aligned across services so the system works immediately after setup.
134
+
135
+ ---
136
+
137
+ ## Included projects
138
+
139
+ Seamless CLI pulls from the following repositories:
140
+
141
+ - Seamless Auth API
142
+ [https://github.com/fells-code/seamless-auth-api](https://github.com/fells-code/seamless-auth-api)
143
+
144
+ - Seamless Auth React Starter
145
+ [https://github.com/fells-code/seamless-auth-starter-react](https://github.com/fells-code/seamless-auth-starter-react)
146
+
147
+ - Seamless Auth API Starter
148
+ [https://github.com/fells-code/seamless-auth-starter-express](https://github.com/fells-code/seamless-auth-starter-express)
149
+
150
+ Each project can be used independently, but the CLI connects them into a working system.
151
+
152
+ ---
153
+
154
+ ## Documentation
155
+
156
+ Full documentation is available at:
157
+
158
+ [https://docs.seamlessauth.com](https://docs.seamlessauth.com)
159
+
160
+ ---
161
+
162
+ ## Philosophy
163
+
164
+ Seamless Auth is built around a few principles:
165
+
166
+ - Passwordless authentication only
167
+ - No redirects or third-party auth providers
168
+ - Self-hosted by default
169
+ - Production-shaped local development
170
+ - Explicit configuration over hidden behavior
171
+
172
+ Seamless CLI exists to make this setup fast and repeatable.
173
+
174
+ ---
175
+
176
+ ## Requirements
177
+
178
+ - Node.js 18 or newer
179
+ - npm or pnpm
180
+ - Docker (optional)
181
+
182
+ ---
183
+
184
+ ## Testing local CLI changes
185
+
186
+ From the repository root, build the CLI and link the local package:
187
+
188
+ ```bash
189
+ npm install
190
+ npm run build
191
+ npm link
192
+ ```
193
+
194
+ Then run the linked command:
195
+
196
+ ```bash
197
+ seamless --version
198
+ seamless --help
199
+ ```
200
+
201
+ When you are done testing, remove the global link:
202
+
203
+ ```bash
204
+ npm unlink -g seamless-cli
205
+ ```
206
+
207
+ To smoke test the package artifact before publishing:
208
+
209
+ ```bash
210
+ npm run build
211
+ TARBALL=$(npm pack --pack-destination /tmp)
212
+ TEST_DIR=$(mktemp -d)
213
+
214
+ cd "$TEST_DIR"
215
+ npm install "/tmp/$TARBALL"
216
+ npm exec -- seamless --version
217
+ npm exec -- seamless --help
218
+ ```
219
+
220
+ If npm cache permissions block local testing, use a writable temporary cache:
221
+
222
+ ```bash
223
+ npm --cache /tmp/npm-cache exec -- seamless --version
224
+ ```
225
+
226
+ ---
227
+
228
+ ## License
229
+
230
+ AGPL-3.0-only © 2026 Fells Code LLC
231
+
232
+ This license ensures:
233
+
234
+ - transparency of security-critical code
235
+ - freedom to self-host and modify
236
+ - sustainability of the managed service offering
237
+
238
+ See `LICENSE` for details.
@@ -0,0 +1,96 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { intro, outro, text, confirm, spinner } from "@clack/prompts";
4
+ import kleur from "kleur";
5
+ import { resolveBootstrapSecret } from "../core/bootstrapSecret.js";
6
+ function loadConfig() {
7
+ const configPath = path.join(process.cwd(), "seamless.config.json");
8
+ if (!fs.existsSync(configPath)) {
9
+ throw new Error("No seamless.config.json found. Run init first.");
10
+ }
11
+ return JSON.parse(fs.readFileSync(configPath, "utf-8"));
12
+ }
13
+ export async function runBootstrapAdmin(emailArg) {
14
+ intro("Seamless Auth Bootstrap");
15
+ const config = loadConfig();
16
+ let email = emailArg;
17
+ if (!email) {
18
+ email = (await text({
19
+ message: "Admin email address",
20
+ placeholder: "admin@example.com",
21
+ validate: (value) => {
22
+ if (!value || !value.includes("@")) {
23
+ return "Enter a valid email address";
24
+ }
25
+ },
26
+ }));
27
+ }
28
+ const proceed = await confirm({
29
+ message: "Create bootstrap admin invite?",
30
+ initialValue: true,
31
+ });
32
+ if (!proceed) {
33
+ outro("Cancelled.");
34
+ return;
35
+ }
36
+ let apiUrl = process.env.SEAMLESS_API_URL;
37
+ if (!apiUrl) {
38
+ apiUrl = "http://localhost:3000";
39
+ }
40
+ let secret = resolveBootstrapSecret();
41
+ if (secret) {
42
+ console.log(kleur.gray("Using bootstrap secret from local environment"));
43
+ }
44
+ else {
45
+ console.log("");
46
+ console.log(kleur.yellow("No bootstrap secret detected automatically."));
47
+ console.log("This may happen if the project is not initialized locally or running in production.");
48
+ secret = (await text({
49
+ message: "Bootstrap secret",
50
+ placeholder: "Enter your bootstrap secret",
51
+ validate: (value) => {
52
+ if (!value)
53
+ return "Bootstrap secret is required";
54
+ },
55
+ }));
56
+ }
57
+ const s = spinner();
58
+ s.start("Creating bootstrap invite...");
59
+ try {
60
+ const res = await fetch(`${apiUrl}/auth/internal/bootstrap/admin-invite`, {
61
+ method: "POST",
62
+ headers: {
63
+ "Content-Type": "application/json",
64
+ Authorization: `Bearer ${secret}`,
65
+ },
66
+ body: JSON.stringify({ email }),
67
+ });
68
+ const data = await res.json();
69
+ if (!res.ok) {
70
+ s.stop("Failed");
71
+ console.error(kleur.red("Error creating bootstrap invite"));
72
+ console.error(data);
73
+ process.exit(1);
74
+ }
75
+ s.stop("Done");
76
+ console.log("");
77
+ if (data?.data?.url) {
78
+ console.log(kleur.bold("Registration URL"));
79
+ console.log(kleur.cyan(data.data.url));
80
+ }
81
+ else {
82
+ console.log(kleur.green(`Invite sent to ${email}`));
83
+ }
84
+ console.log("");
85
+ console.log("Next step:");
86
+ console.log("The invited user must complete registration to receive admin access.");
87
+ outro("Bootstrap complete.");
88
+ }
89
+ catch (err) {
90
+ s.stop("Failed");
91
+ console.error(kleur.red("Unexpected error"));
92
+ console.error(err.message);
93
+ process.exit(1);
94
+ }
95
+ }
96
+ //# sourceMappingURL=bootstrapAdmin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrapAdmin.js","sourceRoot":"","sources":["../../src/commands/bootstrapAdmin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { execSync } from "child_process";
4
+ export async function runCheck() {
5
+ console.log("\nSeamless Check\n");
6
+ const root = process.cwd();
7
+ const configPath = path.join(root, "seamless.config.json");
8
+ if (!fs.existsSync(configPath)) {
9
+ console.log("✖ seamless.config.json not found");
10
+ console.log("→ Run: seamless init\n");
11
+ return;
12
+ }
13
+ console.log("✔ Config file found");
14
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
15
+ checkStructure(root, config);
16
+ checkDocker();
17
+ checkCompose(root, config);
18
+ checkContainers();
19
+ await checkHealth();
20
+ console.log("\nCheck complete.\n");
21
+ }
22
+ function checkStructure(root, config) {
23
+ const services = config.services;
24
+ if (fs.existsSync(path.join(root, services.web.path))) {
25
+ console.log("✔ Web project detected");
26
+ }
27
+ else {
28
+ console.log("✖ Web project missing");
29
+ }
30
+ if (fs.existsSync(path.join(root, services.api.path))) {
31
+ console.log("✔ API project detected");
32
+ }
33
+ else {
34
+ console.log("✖ API project missing");
35
+ }
36
+ }
37
+ function checkDocker() {
38
+ try {
39
+ execSync("docker --version", { stdio: "ignore" });
40
+ console.log("✔ Docker is installed");
41
+ }
42
+ catch {
43
+ console.log("✖ Docker not found");
44
+ console.log("→ Install Docker: https://docs.docker.com/get-docker/");
45
+ }
46
+ }
47
+ function checkCompose(root, config) {
48
+ const composePath = path.join(root, config.docker.composeFile);
49
+ if (fs.existsSync(composePath)) {
50
+ console.log("✔ Docker Compose file found");
51
+ }
52
+ else {
53
+ console.log("✖ docker-compose.yml missing");
54
+ }
55
+ }
56
+ function checkContainers() {
57
+ try {
58
+ const output = execSync("docker ps --format '{{.Names}}'").toString();
59
+ if (!output.includes("api")) {
60
+ console.log("✖ API container not running");
61
+ console.log("→ Run: docker compose up\n");
62
+ }
63
+ else {
64
+ console.log("✔ Containers running");
65
+ }
66
+ }
67
+ catch {
68
+ console.log("✖ Failed to check containers");
69
+ }
70
+ }
71
+ async function checkHealth() {
72
+ const checks = [
73
+ { name: "API", url: "http://localhost:3000/" },
74
+ { name: "Auth", url: "http://localhost:5312/health/status" },
75
+ { name: "Admin", url: "http://localhost:5174" },
76
+ ];
77
+ for (const check of checks) {
78
+ try {
79
+ const res = await fetch(check.url);
80
+ if (res.ok) {
81
+ console.log(`✔ ${check.name} is healthy`);
82
+ }
83
+ else {
84
+ console.log(`✖ ${check.name} returned ${res.status}`);
85
+ }
86
+ }
87
+ catch {
88
+ console.log(`✖ ${check.name} not reachable`);
89
+ }
90
+ }
91
+ }
92
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import kleur from "kleur";
4
+ import * as p from "@clack/prompts";
5
+ import { CONTRIBUTOR_COMPONENTS, formatPublicRef, resolveCloneSource, resolveWorkspaceDir, } from "../contributor/catalog.js";
6
+ import { configureContributorWorkspace } from "../contributor/workspace.js";
7
+ import { runContributorSetupPrompts } from "../prompts/contributeSetup.js";
8
+ import { cloneRepo } from "../utils/repoUtils.js";
9
+ import { runCommand } from "../core/exec.js";
10
+ const WORKSPACE_MANIFEST = "seamless.workspace.json";
11
+ export async function runContributeCommand(args) {
12
+ const subcommand = args[0] ?? "setup";
13
+ if (subcommand === "setup") {
14
+ await runContributorSetup(args[1]);
15
+ return;
16
+ }
17
+ if (subcommand === "start") {
18
+ await runContributorStart();
19
+ return;
20
+ }
21
+ throw new Error(`Unknown contribute subcommand: ${subcommand}`);
22
+ }
23
+ async function runContributorSetup(initialWorkspaceName) {
24
+ p.intro(kleur.cyan("Seamless Contributor Setup"));
25
+ const answers = await runContributorSetupPrompts(initialWorkspaceName);
26
+ const workspaceRoot = path.resolve(process.cwd(), answers.workspaceName);
27
+ ensureWorkspaceRoot(workspaceRoot);
28
+ const manifest = {
29
+ version: 1,
30
+ createdAt: new Date().toISOString(),
31
+ packageManager: "npm",
32
+ workspaceRoot,
33
+ components: [],
34
+ };
35
+ for (const component of CONTRIBUTOR_COMPONENTS) {
36
+ const mode = answers.localComponents.includes(component.id)
37
+ ? "local"
38
+ : "public";
39
+ const workspaceDir = resolveWorkspaceDir(component, mode);
40
+ const localPath = mode === "local" || component.publicSurface === "github-repo"
41
+ ? path.join(workspaceRoot, workspaceDir)
42
+ : undefined;
43
+ if (localPath) {
44
+ const cloneSource = resolveCloneSource(component);
45
+ await cloneRepo(cloneSource, localPath);
46
+ }
47
+ manifest.components.push({
48
+ id: component.id,
49
+ mode,
50
+ publicSurface: component.publicSurface,
51
+ publicRef: component.publicRef,
52
+ gitUrl: component.gitUrl,
53
+ localPath,
54
+ localPackages: component.localPackages,
55
+ });
56
+ }
57
+ const configuredManifest = configureContributorWorkspace(workspaceRoot, manifest);
58
+ fs.mkdirSync(workspaceRoot, { recursive: true });
59
+ fs.writeFileSync(path.join(workspaceRoot, WORKSPACE_MANIFEST), JSON.stringify(configuredManifest, null, 2) + "\n");
60
+ printContributorSetupOutput(workspaceRoot, configuredManifest);
61
+ p.outro(kleur.green("Contributor workspace provisioned"));
62
+ }
63
+ async function runContributorStart() {
64
+ const workspaceRoot = process.cwd();
65
+ const manifestPath = path.join(workspaceRoot, WORKSPACE_MANIFEST);
66
+ if (!fs.existsSync(manifestPath)) {
67
+ throw new Error(`Contributor manifest not found in current directory: ${WORKSPACE_MANIFEST}`);
68
+ }
69
+ await runCommand("docker", ["compose", "up", "--build"], workspaceRoot);
70
+ }
71
+ function ensureWorkspaceRoot(workspaceRoot) {
72
+ if (!fs.existsSync(workspaceRoot)) {
73
+ return;
74
+ }
75
+ const contents = fs.readdirSync(workspaceRoot);
76
+ if (contents.length > 0) {
77
+ throw new Error(`Workspace directory is not empty: ${workspaceRoot}`);
78
+ }
79
+ }
80
+ function printContributorSetupOutput(workspaceRoot, manifest) {
81
+ console.log("");
82
+ console.log(kleur.bold("Workspace"));
83
+ console.log(` ${kleur.white("Directory:")} ${workspaceRoot}`);
84
+ console.log(` ${kleur.white("Manifest:")} ${WORKSPACE_MANIFEST}`);
85
+ console.log(` ${kleur.white("Package manager:")} npm`);
86
+ console.log(` ${kleur.white("Docker Compose:")} ${manifest.docker?.composeFile ?? "docker-compose.yml"}`);
87
+ console.log("");
88
+ console.log(kleur.bold("Component plan"));
89
+ for (const component of manifest.components) {
90
+ const modeLabel = component.mode === "local"
91
+ ? kleur.green("local source")
92
+ : kleur.cyan(`public ${component.publicSurface}`);
93
+ console.log(` • ${component.id} ${kleur.dim(`(${modeLabel})`)}`);
94
+ if (component.localPath) {
95
+ const relativePath = path.relative(workspaceRoot, component.localPath);
96
+ console.log(` path: ${relativePath || "."}`);
97
+ }
98
+ else {
99
+ console.log(` source: ${formatPublicRef(component.publicRef)}`);
100
+ }
101
+ }
102
+ if (manifest.packageLinks && manifest.packageLinks.length > 0) {
103
+ console.log("");
104
+ console.log(kleur.bold("Local package links"));
105
+ for (const link of manifest.packageLinks) {
106
+ console.log(` • ${link.consumerComponentId} uses ${link.packageName} from ${link.targetPath}`);
107
+ }
108
+ }
109
+ if (manifest.warnings && manifest.warnings.length > 0) {
110
+ console.log("");
111
+ console.log(kleur.bold("Warnings"));
112
+ for (const warning of manifest.warnings) {
113
+ console.log(` • ${kleur.yellow(warning)}`);
114
+ }
115
+ }
116
+ console.log("");
117
+ console.log(kleur.bold("Next step"));
118
+ console.log(` cd ${workspaceRoot}`);
119
+ console.log(" docker compose up --build");
120
+ }
121
+ //# sourceMappingURL=contribute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contribute.js","sourceRoot":"","sources":["../../src/commands/contribute.ts"],"names":[],"mappings":"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"}