hatchkit 0.1.1

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 (149) hide show
  1. package/dist/config.d.ts +131 -0
  2. package/dist/config.d.ts.map +1 -0
  3. package/dist/config.js +629 -0
  4. package/dist/config.js.map +1 -0
  5. package/dist/deploy/coolify.d.ts +4 -0
  6. package/dist/deploy/coolify.d.ts.map +1 -0
  7. package/dist/deploy/coolify.js +20 -0
  8. package/dist/deploy/coolify.js.map +1 -0
  9. package/dist/deploy/github.d.ts +4 -0
  10. package/dist/deploy/github.d.ts.map +1 -0
  11. package/dist/deploy/github.js +39 -0
  12. package/dist/deploy/github.js.map +1 -0
  13. package/dist/deploy/gpu.d.ts +4 -0
  14. package/dist/deploy/gpu.d.ts.map +1 -0
  15. package/dist/deploy/gpu.js +97 -0
  16. package/dist/deploy/gpu.js.map +1 -0
  17. package/dist/deploy/keys.d.ts +9 -0
  18. package/dist/deploy/keys.d.ts.map +1 -0
  19. package/dist/deploy/keys.js +73 -0
  20. package/dist/deploy/keys.js.map +1 -0
  21. package/dist/deploy/terraform.d.ts +4 -0
  22. package/dist/deploy/terraform.d.ts.map +1 -0
  23. package/dist/deploy/terraform.js +55 -0
  24. package/dist/deploy/terraform.js.map +1 -0
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +599 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/prompts.d.ts +52 -0
  30. package/dist/prompts.d.ts.map +1 -0
  31. package/dist/prompts.js +313 -0
  32. package/dist/prompts.js.map +1 -0
  33. package/dist/provision/glitchtip.d.ts +6 -0
  34. package/dist/provision/glitchtip.d.ts.map +1 -0
  35. package/dist/provision/glitchtip.js +46 -0
  36. package/dist/provision/glitchtip.js.map +1 -0
  37. package/dist/provision/index.d.ts +9 -0
  38. package/dist/provision/index.d.ts.map +1 -0
  39. package/dist/provision/index.js +108 -0
  40. package/dist/provision/index.js.map +1 -0
  41. package/dist/provision/openpanel.d.ts +8 -0
  42. package/dist/provision/openpanel.d.ts.map +1 -0
  43. package/dist/provision/openpanel.js +66 -0
  44. package/dist/provision/openpanel.js.map +1 -0
  45. package/dist/provision/resend.d.ts +16 -0
  46. package/dist/provision/resend.d.ts.map +1 -0
  47. package/dist/provision/resend.js +43 -0
  48. package/dist/provision/resend.js.map +1 -0
  49. package/dist/scaffold/app.d.ts +13 -0
  50. package/dist/scaffold/app.d.ts.map +1 -0
  51. package/dist/scaffold/app.js +340 -0
  52. package/dist/scaffold/app.js.map +1 -0
  53. package/dist/scaffold/dotenvx.d.ts +30 -0
  54. package/dist/scaffold/dotenvx.d.ts.map +1 -0
  55. package/dist/scaffold/dotenvx.js +142 -0
  56. package/dist/scaffold/dotenvx.js.map +1 -0
  57. package/dist/scaffold/infra.d.ts +17 -0
  58. package/dist/scaffold/infra.d.ts.map +1 -0
  59. package/dist/scaffold/infra.js +200 -0
  60. package/dist/scaffold/infra.js.map +1 -0
  61. package/dist/scaffold/manifest.d.ts +50 -0
  62. package/dist/scaffold/manifest.d.ts.map +1 -0
  63. package/dist/scaffold/manifest.js +83 -0
  64. package/dist/scaffold/manifest.js.map +1 -0
  65. package/dist/scaffold/ml-client.d.ts +20 -0
  66. package/dist/scaffold/ml-client.d.ts.map +1 -0
  67. package/dist/scaffold/ml-client.js +38 -0
  68. package/dist/scaffold/ml-client.js.map +1 -0
  69. package/dist/scaffold/pkg-json.d.ts +20 -0
  70. package/dist/scaffold/pkg-json.d.ts.map +1 -0
  71. package/dist/scaffold/pkg-json.js +113 -0
  72. package/dist/scaffold/pkg-json.js.map +1 -0
  73. package/dist/scaffold/starter-files.d.ts +40 -0
  74. package/dist/scaffold/starter-files.d.ts.map +1 -0
  75. package/dist/scaffold/starter-files.js +197 -0
  76. package/dist/scaffold/starter-files.js.map +1 -0
  77. package/dist/scaffold/update.d.ts +8 -0
  78. package/dist/scaffold/update.d.ts.map +1 -0
  79. package/dist/scaffold/update.js +255 -0
  80. package/dist/scaffold/update.js.map +1 -0
  81. package/dist/templates/addons/analytics/middleware.ts.hbs +13 -0
  82. package/dist/templates/addons/analytics/sentry.ts.hbs +16 -0
  83. package/dist/templates/addons/storage/s3.ts.hbs +40 -0
  84. package/dist/templates/addons/storage/upload.ts.hbs +23 -0
  85. package/dist/templates/addons/stripe/checkout.ts.hbs +27 -0
  86. package/dist/templates/addons/stripe/client.ts.hbs +6 -0
  87. package/dist/templates/addons/stripe/webhook.ts.hbs +39 -0
  88. package/dist/templates/addons/websocket/redis.ts.hbs +25 -0
  89. package/dist/templates/addons/websocket/ws.ts.hbs +32 -0
  90. package/dist/templates/base/.dockerignore.hbs +7 -0
  91. package/dist/templates/base/Dockerfile.hbs +18 -0
  92. package/dist/templates/base/env.example.hbs +60 -0
  93. package/dist/templates/base/github-actions.yml.hbs +35 -0
  94. package/dist/templates/base/gitignore.hbs +5 -0
  95. package/dist/templates/base/package.json.hbs +36 -0
  96. package/dist/templates/base/src/auth/auth.ts.hbs +13 -0
  97. package/dist/templates/base/src/auth/routes.ts.hbs +19 -0
  98. package/dist/templates/base/src/config.ts.hbs +36 -0
  99. package/dist/templates/base/src/db.ts.hbs +12 -0
  100. package/dist/templates/base/src/index.ts.hbs +80 -0
  101. package/dist/templates/base/src/routes/health.ts.hbs +12 -0
  102. package/dist/templates/base/tsconfig.json.hbs +18 -0
  103. package/dist/templates/ml-clients/3d-extraction.ts.hbs +20 -0
  104. package/dist/templates/ml-clients/background-removal.ts.hbs +17 -0
  105. package/dist/templates/ml-clients/custom-hf.ts.hbs +20 -0
  106. package/dist/templates/ml-clients/image-recognition.ts.hbs +22 -0
  107. package/dist/templates/ml-clients/subtitles.ts.hbs +26 -0
  108. package/dist/utils/coolify-api.d.ts +45 -0
  109. package/dist/utils/coolify-api.d.ts.map +1 -0
  110. package/dist/utils/coolify-api.js +72 -0
  111. package/dist/utils/coolify-api.js.map +1 -0
  112. package/dist/utils/errors.d.ts +2 -0
  113. package/dist/utils/errors.d.ts.map +1 -0
  114. package/dist/utils/errors.js +31 -0
  115. package/dist/utils/errors.js.map +1 -0
  116. package/dist/utils/exec.d.ts +23 -0
  117. package/dist/utils/exec.d.ts.map +1 -0
  118. package/dist/utils/exec.js +47 -0
  119. package/dist/utils/exec.js.map +1 -0
  120. package/dist/utils/flags.d.ts +17 -0
  121. package/dist/utils/flags.d.ts.map +1 -0
  122. package/dist/utils/flags.js +116 -0
  123. package/dist/utils/flags.js.map +1 -0
  124. package/dist/utils/hf-api.d.ts +13 -0
  125. package/dist/utils/hf-api.d.ts.map +1 -0
  126. package/dist/utils/hf-api.js +30 -0
  127. package/dist/utils/hf-api.js.map +1 -0
  128. package/dist/utils/ports.d.ts +29 -0
  129. package/dist/utils/ports.d.ts.map +1 -0
  130. package/dist/utils/ports.js +86 -0
  131. package/dist/utils/ports.js.map +1 -0
  132. package/dist/utils/secrets.d.ts +25 -0
  133. package/dist/utils/secrets.d.ts.map +1 -0
  134. package/dist/utils/secrets.js +51 -0
  135. package/dist/utils/secrets.js.map +1 -0
  136. package/dist/utils/template.d.ts +7 -0
  137. package/dist/utils/template.d.ts.map +1 -0
  138. package/dist/utils/template.js +35 -0
  139. package/dist/utils/template.js.map +1 -0
  140. package/dist/utils/validate.d.ts +16 -0
  141. package/dist/utils/validate.d.ts.map +1 -0
  142. package/dist/utils/validate.js +60 -0
  143. package/dist/utils/validate.js.map +1 -0
  144. package/dist/utils/version.d.ts +2 -0
  145. package/dist/utils/version.d.ts.map +1 -0
  146. package/dist/utils/version.js +21 -0
  147. package/dist/utils/version.js.map +1 -0
  148. package/package.json +48 -0
  149. package/scripts/copy-templates.mjs +20 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Client for custom HuggingFace model: {{customHfModelId}}
3
+ * Deployed to: {{gpuPlatform}}
4
+ */
5
+
6
+ const ENDPOINT = process.env.ML_CUSTOM_HF_ENDPOINT || "";
7
+
8
+ export async function predict(input: unknown): Promise<unknown> {
9
+ const res = await fetch(ENDPOINT, {
10
+ method: "POST",
11
+ headers: { "Content-Type": "application/json" },
12
+ body: JSON.stringify({ input }),
13
+ });
14
+
15
+ if (!res.ok) {
16
+ throw new Error(`ML prediction failed: ${res.status} ${res.statusText}`);
17
+ }
18
+
19
+ return res.json();
20
+ }
@@ -0,0 +1,22 @@
1
+ import { config } from "../config.js";
2
+
3
+ export interface RecognitionResult {
4
+ label: string;
5
+ score: number;
6
+ }
7
+
8
+ export async function recognizeImage(imageBuffer: Buffer): Promise<RecognitionResult[]> {
9
+ const formData = new FormData();
10
+ formData.append("file", new Blob([imageBuffer]));
11
+
12
+ const res = await fetch(config.ML_IMAGE_RECOGNITION_ENDPOINT, {
13
+ method: "POST",
14
+ body: formData,
15
+ });
16
+
17
+ if (!res.ok) {
18
+ throw new Error(`Image recognition failed: ${res.status} ${res.statusText}`);
19
+ }
20
+
21
+ return res.json() as Promise<RecognitionResult[]>;
22
+ }
@@ -0,0 +1,26 @@
1
+ import { config } from "../config.js";
2
+
3
+ export interface SubtitleSegment {
4
+ start: number;
5
+ end: number;
6
+ text: string;
7
+ }
8
+
9
+ export async function generateSubtitles(audioBuffer: Buffer): Promise<{
10
+ segments: SubtitleSegment[];
11
+ srt: string;
12
+ }> {
13
+ const formData = new FormData();
14
+ formData.append("file", new Blob([audioBuffer]));
15
+
16
+ const res = await fetch(config.ML_SUBTITLES_ENDPOINT, {
17
+ method: "POST",
18
+ body: formData,
19
+ });
20
+
21
+ if (!res.ok) {
22
+ throw new Error(`Subtitle generation failed: ${res.status} ${res.statusText}`);
23
+ }
24
+
25
+ return res.json() as Promise<{ segments: SubtitleSegment[]; srt: string }>;
26
+ }
@@ -0,0 +1,45 @@
1
+ export interface CoolifyServer {
2
+ id: number;
3
+ name: string;
4
+ ip: string;
5
+ description?: string;
6
+ }
7
+ export interface CoolifyApiOptions {
8
+ url: string;
9
+ token: string;
10
+ }
11
+ /** Coolify REST API client. */
12
+ export declare class CoolifyApi {
13
+ private url;
14
+ private token;
15
+ constructor(options: CoolifyApiOptions);
16
+ private request;
17
+ /** Test connection and get Coolify version. */
18
+ getVersion(): Promise<string>;
19
+ /** List all servers. */
20
+ listServers(): Promise<CoolifyServer[]>;
21
+ /** List all projects. */
22
+ listProjects(): Promise<Array<{
23
+ id: number;
24
+ name: string;
25
+ }>>;
26
+ /** Create a new project. */
27
+ createProject(name: string): Promise<{
28
+ id: number;
29
+ name: string;
30
+ }>;
31
+ /** List Coolify apps/services so callers can resolve a UUID by name. */
32
+ listApplications(): Promise<Array<{
33
+ uuid: string;
34
+ name: string;
35
+ description?: string;
36
+ }>>;
37
+ /** Upsert an env variable on a Coolify application. The Coolify API
38
+ * accepts multiple envs in one call so this is idempotent. */
39
+ setAppEnv(appUuid: string, envs: Record<string, string>, options?: {
40
+ isPreview?: boolean;
41
+ }): Promise<void>;
42
+ }
43
+ /** Verify Coolify connection. Returns version string or throws. */
44
+ export declare function verifyCoolify(url: string, token: string): Promise<string>;
45
+ //# sourceMappingURL=coolify-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coolify-api.d.ts","sourceRoot":"","sources":["../../src/utils/coolify-api.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+BAA+B;AAC/B,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,KAAK,CAAS;gBAEV,OAAO,EAAE,iBAAiB;YAKxB,OAAO;IAqBrB,+CAA+C;IACzC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAKnC,wBAAwB;IAClB,WAAW,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAkB7C,yBAAyB;IACnB,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAIlE,4BAA4B;IACtB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAIxE,wEAAwE;IAClE,gBAAgB,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAI9F;mEAC+D;IACzD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO,GACpC,OAAO,CAAC,IAAI,CAAC;CAYjB;AAED,mEAAmE;AACnE,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/E"}
@@ -0,0 +1,72 @@
1
+ /** Coolify REST API client. */
2
+ export class CoolifyApi {
3
+ url;
4
+ token;
5
+ constructor(options) {
6
+ this.url = options.url.replace(/\/$/, "");
7
+ this.token = options.token;
8
+ }
9
+ async request(method, path, body) {
10
+ const res = await fetch(`${this.url}/api/v1${path}`, {
11
+ method,
12
+ headers: {
13
+ Authorization: `Bearer ${this.token}`,
14
+ "Content-Type": "application/json",
15
+ Accept: "application/json",
16
+ },
17
+ body: body ? JSON.stringify(body) : undefined,
18
+ });
19
+ if (!res.ok) {
20
+ const text = await res.text().catch(() => "");
21
+ throw new Error(`Coolify API ${method} ${path} failed: ${res.status} ${res.statusText}${text ? ` — ${text}` : ""}`);
22
+ }
23
+ return res.json();
24
+ }
25
+ /** Test connection and get Coolify version. */
26
+ async getVersion() {
27
+ const data = await this.request("GET", "/version");
28
+ return data.version;
29
+ }
30
+ /** List all servers. */
31
+ async listServers() {
32
+ const data = await this.request("GET", "/servers");
33
+ return data.map((s) => ({
34
+ id: s.id,
35
+ name: s.name,
36
+ ip: s.ip,
37
+ description: s.description,
38
+ }));
39
+ }
40
+ /** List all projects. */
41
+ async listProjects() {
42
+ return this.request("GET", "/projects");
43
+ }
44
+ /** Create a new project. */
45
+ async createProject(name) {
46
+ return this.request("POST", "/projects", { name });
47
+ }
48
+ /** List Coolify apps/services so callers can resolve a UUID by name. */
49
+ async listApplications() {
50
+ return this.request("GET", "/applications");
51
+ }
52
+ /** Upsert an env variable on a Coolify application. The Coolify API
53
+ * accepts multiple envs in one call so this is idempotent. */
54
+ async setAppEnv(appUuid, envs, options = {}) {
55
+ const body = {
56
+ data: Object.entries(envs).map(([key, value]) => ({
57
+ key,
58
+ value,
59
+ is_preview: options.isPreview ?? false,
60
+ is_build_time: false,
61
+ is_literal: true,
62
+ })),
63
+ };
64
+ await this.request("PATCH", `/applications/${appUuid}/envs/bulk`, body);
65
+ }
66
+ }
67
+ /** Verify Coolify connection. Returns version string or throws. */
68
+ export async function verifyCoolify(url, token) {
69
+ const api = new CoolifyApi({ url, token });
70
+ return api.getVersion();
71
+ }
72
+ //# sourceMappingURL=coolify-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coolify-api.js","sourceRoot":"","sources":["../../src/utils/coolify-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function explainFsError(err: unknown, context: string): string;
2
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAeA,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAsBpE"}
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Error-message helpers.
3
+ *
4
+ * `explainFsError` maps common Node I/O error codes to actionable
5
+ * recovery hints. The returned string is safe to display to users
6
+ * (no internal paths beyond what the error already contains).
7
+ */
8
+ export function explainFsError(err, context) {
9
+ const e = err;
10
+ const path = e.path ? ` at ${e.path}` : "";
11
+ switch (e.code) {
12
+ case "EACCES":
13
+ return `${context}: permission denied${path}. Fix: check the parent directory's write permissions, or run with sufficient privileges.`;
14
+ case "EPERM":
15
+ return `${context}: operation not permitted${path}. Fix: the file may be locked or owned by another user; check ownership.`;
16
+ case "ENOSPC":
17
+ return `${context}: out of disk space${path}. Fix: free up space and retry.`;
18
+ case "ENOENT":
19
+ return `${context}: file not found${path}. Fix: make sure the starter submodule is initialized (\`git submodule update --init\` in the monorepo root).`;
20
+ case "EEXIST":
21
+ return `${context}: file already exists${path}. Fix: move or remove it, then retry.`;
22
+ case "EROFS":
23
+ return `${context}: filesystem is read-only${path}. Fix: scaffold into a writable location.`;
24
+ case "EMFILE":
25
+ case "ENFILE":
26
+ return `${context}: too many open files. Fix: close other processes or raise \`ulimit -n\`.`;
27
+ default:
28
+ return `${context}: ${e.message ?? String(err)}`;
29
+ }
30
+ }
31
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,OAAe;IAC1D,MAAM,CAAC,GAAG,GAAiB,CAAC;IAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,GAAG,OAAO,sBAAsB,IAAI,2FAA2F,CAAC;QACzI,KAAK,OAAO;YACV,OAAO,GAAG,OAAO,4BAA4B,IAAI,0EAA0E,CAAC;QAC9H,KAAK,QAAQ;YACX,OAAO,GAAG,OAAO,sBAAsB,IAAI,iCAAiC,CAAC;QAC/E,KAAK,QAAQ;YACX,OAAO,GAAG,OAAO,mBAAmB,IAAI,+GAA+G,CAAC;QAC1J,KAAK,QAAQ;YACX,OAAO,GAAG,OAAO,wBAAwB,IAAI,uCAAuC,CAAC;QACvF,KAAK,OAAO;YACV,OAAO,GAAG,OAAO,4BAA4B,IAAI,2CAA2C,CAAC;QAC/F,KAAK,QAAQ,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,GAAG,OAAO,2EAA2E,CAAC;QAC/F;YACE,OAAO,GAAG,OAAO,KAAK,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACrD,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface ExecResult {
2
+ stdout: string;
3
+ stderr: string;
4
+ exitCode: number;
5
+ }
6
+ /** Run a shell command with a spinner. */
7
+ export declare function exec(command: string, args: string[], options?: {
8
+ cwd?: string;
9
+ env?: Record<string, string>;
10
+ spinner?: string;
11
+ silent?: boolean;
12
+ }): Promise<ExecResult>;
13
+ /** Run a shell command and return true if exit code is 0. */
14
+ export declare function execOk(command: string, args: string[], options?: {
15
+ cwd?: string;
16
+ env?: Record<string, string>;
17
+ }): Promise<boolean>;
18
+ /** Run a shell command, stream output to terminal. */
19
+ export declare function execStream(command: string, args: string[], options?: {
20
+ cwd?: string;
21
+ env?: Record<string, string>;
22
+ }): Promise<number>;
23
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,0CAA0C;AAC1C,wBAAsB,IAAI,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IACR,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GACA,OAAO,CAAC,UAAU,CAAC,CA4BrB;AAED,6DAA6D;AAC7D,wBAAsB,MAAM,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACvD,OAAO,CAAC,OAAO,CAAC,CAGlB;AAED,sDAAsD;AACtD,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACvD,OAAO,CAAC,MAAM,CAAC,CAQjB"}
@@ -0,0 +1,47 @@
1
+ import { execa } from "execa";
2
+ import ora from "ora";
3
+ /** Run a shell command with a spinner. */
4
+ export async function exec(command, args, options) {
5
+ const spinner = options?.spinner ? ora(options.spinner).start() : null;
6
+ try {
7
+ const result = await execa(command, args, {
8
+ cwd: options?.cwd,
9
+ env: { ...process.env, ...options?.env },
10
+ reject: false,
11
+ });
12
+ if (result.exitCode !== 0) {
13
+ spinner?.fail();
14
+ if (!options?.silent) {
15
+ console.error(result.stderr || result.stdout);
16
+ }
17
+ }
18
+ else {
19
+ spinner?.succeed();
20
+ }
21
+ return {
22
+ stdout: result.stdout,
23
+ stderr: result.stderr,
24
+ exitCode: result.exitCode ?? 1,
25
+ };
26
+ }
27
+ catch (error) {
28
+ spinner?.fail();
29
+ throw error;
30
+ }
31
+ }
32
+ /** Run a shell command and return true if exit code is 0. */
33
+ export async function execOk(command, args, options) {
34
+ const result = await exec(command, args, { ...options, silent: true });
35
+ return result.exitCode === 0;
36
+ }
37
+ /** Run a shell command, stream output to terminal. */
38
+ export async function execStream(command, args, options) {
39
+ const result = await execa(command, args, {
40
+ cwd: options?.cwd,
41
+ env: { ...process.env, ...options?.env },
42
+ stdio: "inherit",
43
+ reject: false,
44
+ });
45
+ return result.exitCode ?? 1;
46
+ }
47
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,GAAG,MAAM,KAAK,CAAC;AAQtB,0CAA0C;AAC1C,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,OAAe,EACf,IAAc,EACd,OAKC;IAED,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAEvE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACxC,GAAG,EAAE,OAAO,EAAE,GAAG;YACjB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE;YACxC,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;gBACrB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,OAAO,EAAE,CAAC;QACrB,CAAC;QAED,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC;SAC/B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,EAAE,CAAC;QAChB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,OAAe,EACf,IAAc,EACd,OAAwD;IAExD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,OAAO,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAe,EACf,IAAc,EACd,OAAwD;IAExD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;QACxC,GAAG,EAAE,OAAO,EAAE,GAAG;QACjB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE;QACxC,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { ProjectConfig } from "../prompts.js";
2
+ export interface ParsedCreateFlags {
3
+ /** Non-interactive: accept defaults, fail if a required value with
4
+ * no default is missing rather than prompting. */
5
+ yes: boolean;
6
+ /** --dry-run — already handled in index.ts but re-parsed here so
7
+ * one place knows the full set of supported flags. */
8
+ dryRun: boolean;
9
+ /** Preset values parsed from individual flags + --config file. */
10
+ presets: Partial<ProjectConfig>;
11
+ /** --no-github / --no-deploy hard-disable those steps regardless of
12
+ * what the preset / prompts would say. */
13
+ forceNoGithub: boolean;
14
+ forceNoDeploy: boolean;
15
+ }
16
+ export declare function parseCreateFlags(argv: string[]): ParsedCreateFlags;
17
+ //# sourceMappingURL=flags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../../src/utils/flags.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,eAAe,CAAC;AAEvE,MAAM,WAAW,iBAAiB;IAChC;uDACmD;IACnD,GAAG,EAAE,OAAO,CAAC;IACb;2DACuD;IACvD,MAAM,EAAE,OAAO,CAAC;IAChB,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC;+CAC2C;IAC3C,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACxB;AAkBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,CA6FlE"}
@@ -0,0 +1,116 @@
1
+ /*
2
+ * Command-line flag parsing for `hatchkit create`.
3
+ *
4
+ * Keeps the flag surface deliberately small — a few common flags plus
5
+ * a `--config <path>` escape hatch that reads a JSON file matching
6
+ * Partial<ProjectConfig>. Flags win over config file; config file
7
+ * wins over prompt defaults.
8
+ *
9
+ * Design choice: don't try to expose every ProjectConfig field as a
10
+ * flag. The combinatorial space is big and awkward to document. For
11
+ * anything beyond the common case, point users at `--config <path>`.
12
+ */
13
+ import { existsSync, readFileSync } from "node:fs";
14
+ import { resolve } from "node:path";
15
+ const KNOWN_FEATURES = [
16
+ "websocket",
17
+ "stripe",
18
+ "analytics",
19
+ "s3",
20
+ "desktop",
21
+ "mobile",
22
+ ];
23
+ const KNOWN_ML_SERVICES = [
24
+ "3d-extraction",
25
+ "subtitles",
26
+ "image-recognition",
27
+ "background-removal",
28
+ "custom-hf",
29
+ ];
30
+ export function parseCreateFlags(argv) {
31
+ const get = (name) => {
32
+ // Accept both `--name value` and `--name=value`.
33
+ const equalsIdx = argv.findIndex((a) => a.startsWith(`--${name}=`));
34
+ if (equalsIdx !== -1)
35
+ return argv[equalsIdx].slice(name.length + 3);
36
+ const idx = argv.indexOf(`--${name}`);
37
+ if (idx === -1 || idx === argv.length - 1)
38
+ return undefined;
39
+ const next = argv[idx + 1];
40
+ return next.startsWith("--") ? undefined : next;
41
+ };
42
+ const has = (name) => argv.includes(`--${name}`) || argv.some((a) => a.startsWith(`--${name}=`));
43
+ const yes = argv.includes("--yes") || argv.includes("-y");
44
+ const dryRun = argv.includes("--dry-run");
45
+ const forceNoGithub = argv.includes("--no-github");
46
+ const forceNoDeploy = argv.includes("--no-deploy");
47
+ // Start from --config <path> if present, then layer individual flags on top.
48
+ const presets = {};
49
+ const configPath = get("config");
50
+ if (configPath) {
51
+ const absPath = resolve(configPath);
52
+ if (!existsSync(absPath)) {
53
+ throw new Error(`--config file not found: ${absPath}`);
54
+ }
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(readFileSync(absPath, "utf-8"));
58
+ }
59
+ catch (err) {
60
+ throw new Error(`--config file is not valid JSON: ${absPath} (${err.message})`);
61
+ }
62
+ if (!parsed || typeof parsed !== "object") {
63
+ throw new Error(`--config file must be a JSON object: ${absPath}`);
64
+ }
65
+ Object.assign(presets, parsed);
66
+ }
67
+ const name = get("name");
68
+ if (name)
69
+ presets.name = name;
70
+ const domain = get("domain");
71
+ if (domain)
72
+ presets.domain = domain;
73
+ const features = get("features");
74
+ if (features !== undefined) {
75
+ const list = features
76
+ .split(",")
77
+ .map((s) => s.trim())
78
+ .filter(Boolean);
79
+ const invalid = list.filter((f) => !KNOWN_FEATURES.includes(f));
80
+ if (invalid.length > 0) {
81
+ throw new Error(`Unknown --features values: ${invalid.join(", ")}. Valid: ${KNOWN_FEATURES.join(", ")}`);
82
+ }
83
+ presets.features = list;
84
+ }
85
+ const mlServices = get("ml-services");
86
+ if (mlServices !== undefined) {
87
+ const list = mlServices
88
+ .split(",")
89
+ .map((s) => s.trim())
90
+ .filter(Boolean);
91
+ const invalid = list.filter((f) => !KNOWN_ML_SERVICES.includes(f));
92
+ if (invalid.length > 0) {
93
+ throw new Error(`Unknown --ml-services values: ${invalid.join(", ")}. Valid: ${KNOWN_ML_SERVICES.join(", ")}`);
94
+ }
95
+ presets.mlServices = list;
96
+ }
97
+ const deployTarget = get("deploy-target");
98
+ if (deployTarget === "existing" || deployTarget === "new") {
99
+ presets.deployTarget = deployTarget;
100
+ }
101
+ else if (deployTarget !== undefined) {
102
+ throw new Error(`--deploy-target must be 'existing' or 'new' (got '${deployTarget}')`);
103
+ }
104
+ if (forceNoGithub)
105
+ presets.createGithubRepo = false;
106
+ if (forceNoDeploy)
107
+ presets.runDeployment = false;
108
+ // Validate that presets-provided values look right before we pass
109
+ // them on (the prompt layer would also catch these, but failing
110
+ // early in non-interactive mode gives a cleaner error).
111
+ if (has("config") && typeof presets.name !== "string" && yes) {
112
+ // fine — may still come from --name flag or default
113
+ }
114
+ return { yes, dryRun, presets, forceNoGithub, forceNoDeploy };
115
+ }
116
+ //# sourceMappingURL=flags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/utils/flags.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type ModelPipelineTag = "text-generation" | "text-classification" | "token-classification" | "image-classification" | "object-detection" | "image-segmentation" | "text-to-image" | "image-to-text" | "automatic-speech-recognition" | "translation" | "summarization" | "feature-extraction" | "other";
2
+ export interface HfModelInfo {
3
+ modelId: string;
4
+ pipelineTag: ModelPipelineTag;
5
+ library: string;
6
+ tags: string[];
7
+ private: boolean;
8
+ }
9
+ /** Query the HuggingFace Hub API to get model info. */
10
+ export declare function getModelInfo(modelId: string): Promise<HfModelInfo>;
11
+ /** Suggest GPU type based on model pipeline and tags. */
12
+ export declare function suggestGpu(info: HfModelInfo): string;
13
+ //# sourceMappingURL=hf-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hf-api.d.ts","sourceRoot":"","sources":["../../src/utils/hf-api.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACxB,iBAAiB,GACjB,qBAAqB,GACrB,sBAAsB,GACtB,sBAAsB,GACtB,kBAAkB,GAClB,oBAAoB,GACpB,eAAe,GACf,eAAe,GACf,8BAA8B,GAC9B,aAAa,GACb,eAAe,GACf,oBAAoB,GACpB,OAAO,CAAC;AAEZ,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,uDAAuD;AACvD,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAyBxE;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAWpD"}
@@ -0,0 +1,30 @@
1
+ /** Query the HuggingFace Hub API to get model info. */
2
+ export async function getModelInfo(modelId) {
3
+ const res = await fetch(`https://huggingface.co/api/models/${modelId}`);
4
+ if (!res.ok) {
5
+ if (res.status === 404) {
6
+ throw new Error(`Model not found: ${modelId}`);
7
+ }
8
+ throw new Error(`HuggingFace API error: ${res.status} ${res.statusText}`);
9
+ }
10
+ const data = (await res.json());
11
+ return {
12
+ modelId: data.id,
13
+ pipelineTag: data.pipeline_tag || "other",
14
+ library: data.library_name || "unknown",
15
+ tags: data.tags || [],
16
+ private: data.private || false,
17
+ };
18
+ }
19
+ /** Suggest GPU type based on model pipeline and tags. */
20
+ export function suggestGpu(info) {
21
+ if (info.pipelineTag === "text-generation" ||
22
+ info.tags.some((t) => t.includes("llama") || t.includes("70b"))) {
23
+ return "A100";
24
+ }
25
+ if (info.pipelineTag === "text-to-image" || info.pipelineTag === "image-segmentation") {
26
+ return "A10G";
27
+ }
28
+ return "T4";
29
+ }
30
+ //# sourceMappingURL=hf-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hf-api.js","sourceRoot":"","sources":["../../src/utils/hf-api.ts"],"names":[],"mappings":"AAuBA,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe;IAChD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,qCAAqC,OAAO,EAAE,CAAC,CAAC;IAExE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAM7B,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,WAAW,EAAG,IAAI,CAAC,YAAiC,IAAI,OAAO;QAC/D,OAAO,EAAE,IAAI,CAAC,YAAY,IAAI,SAAS;QACvC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;QACrB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK;KAC/B,CAAC;AACJ,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,UAAU,CAAC,IAAiB;IAC1C,IACE,IAAI,CAAC,WAAW,KAAK,iBAAiB;QACtC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAC/D,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,KAAK,eAAe,IAAI,IAAI,CAAC,WAAW,KAAK,oBAAoB,EAAE,CAAC;QACtF,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,29 @@
1
+ export declare const PORT_RANGES: {
2
+ server: readonly [5000, 5999];
3
+ client: readonly [6000, 6999];
4
+ nativeHmr: readonly [7000, 7999];
5
+ };
6
+ /** Test whether a port is free to bind on 127.0.0.1. Resolves with
7
+ * `true` if we could successfully open + immediately close a listener
8
+ * on it; `false` if the bind failed for any reason (EADDRINUSE,
9
+ * permission, etc.). Always resolves — never throws. */
10
+ export declare function isPortFree(port: number): Promise<boolean>;
11
+ /** Pick a port in [min, max] that is (a) not in the used-ports
12
+ * registry and (b) actually free to bind on 127.0.0.1. Scans
13
+ * sequentially from a random starting point, wrapping once. Throws
14
+ * if every port in the range is either registered or occupied. */
15
+ export declare function pickPort(min: number, max: number, used: Set<number>): Promise<number>;
16
+ export interface ProjectPorts {
17
+ server: number;
18
+ client: number;
19
+ /** Only set when desktop or mobile is selected. */
20
+ nativeHmr?: number;
21
+ }
22
+ /** Pick a coherent port set for a new project, avoiding ports already
23
+ * assigned to prior scaffolds AND ports that are actually busy on the
24
+ * host. Caller is responsible for persisting the returned ports into
25
+ * the used-ports registry. */
26
+ export declare function pickProjectPorts(used: number[], options: {
27
+ nativeHmr: boolean;
28
+ }): Promise<ProjectPorts>;
29
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/utils/ports.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,WAAW;;;;CAIvB,CAAC;AAEF;;;yDAGyD;AACzD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQzD;AAED;;;mEAGmE;AACnE,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB3F;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;+BAG+B;AAC/B,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GAC9B,OAAO,CAAC,YAAY,CAAC,CAWvB"}
@@ -0,0 +1,86 @@
1
+ /*
2
+ * Port picker.
3
+ *
4
+ * At scaffold time we assign each project a fixed set of ports so dev
5
+ * servers across multiple scaffolded projects don't collide on
6
+ * localhost. Ports come from three disjoint 1000-slot ranges:
7
+ *
8
+ * server 5000 – 5999 Express API / backend
9
+ * client 6000 – 6999 Next.js web dev server
10
+ * nativeHmr 7000 – 7999 Next dev server for Capacitor + Electron
11
+ * (only picked when desktop or mobile is
12
+ * selected, so regular web + native can
13
+ * run side-by-side without stomping)
14
+ *
15
+ * Two layers of collision avoidance:
16
+ * 1. The CLI config tracks ports handed out to prior `hatchkit
17
+ * create` runs (usedPorts registry) — avoids picking the same
18
+ * port twice across scaffolds on this machine.
19
+ * 2. Each candidate is tested by actually binding to it on
20
+ * 127.0.0.1. If a non-scaffolded process holds the port (someone
21
+ * else's dev server, a system service, etc.) we skip it and try
22
+ * the next. This is the bit that makes the picked port "real"
23
+ * enough to commit to .env.development.
24
+ *
25
+ * The scan order is: pick a random starting point inside the range,
26
+ * then step forward from there, wrapping at the end. That gives
27
+ * decent distribution across the range while also feeling like
28
+ * "auto-increment until free" at the low level.
29
+ */
30
+ import { createServer } from "node:net";
31
+ export const PORT_RANGES = {
32
+ server: [5000, 5999],
33
+ client: [6000, 6999],
34
+ nativeHmr: [7000, 7999],
35
+ };
36
+ /** Test whether a port is free to bind on 127.0.0.1. Resolves with
37
+ * `true` if we could successfully open + immediately close a listener
38
+ * on it; `false` if the bind failed for any reason (EADDRINUSE,
39
+ * permission, etc.). Always resolves — never throws. */
40
+ export function isPortFree(port) {
41
+ return new Promise((resolve) => {
42
+ const server = createServer();
43
+ server.once("error", () => resolve(false));
44
+ server.listen(port, "127.0.0.1", () => {
45
+ server.close(() => resolve(true));
46
+ });
47
+ });
48
+ }
49
+ /** Pick a port in [min, max] that is (a) not in the used-ports
50
+ * registry and (b) actually free to bind on 127.0.0.1. Scans
51
+ * sequentially from a random starting point, wrapping once. Throws
52
+ * if every port in the range is either registered or occupied. */
53
+ export async function pickPort(min, max, used) {
54
+ const span = max - min + 1;
55
+ const start = Math.floor(Math.random() * span);
56
+ let registryCollisions = 0;
57
+ let busyPorts = 0;
58
+ for (let i = 0; i < span; i++) {
59
+ const port = min + ((start + i) % span);
60
+ if (used.has(port)) {
61
+ registryCollisions++;
62
+ continue;
63
+ }
64
+ if (await isPortFree(port))
65
+ return port;
66
+ busyPorts++;
67
+ }
68
+ throw new Error(`No free port found in range ${min}-${max} — ${registryCollisions} registered to other scaffolds, ${busyPorts} held by other processes. Run \`hatchkit config reset\` to clear the registry if it's stale.`);
69
+ }
70
+ /** Pick a coherent port set for a new project, avoiding ports already
71
+ * assigned to prior scaffolds AND ports that are actually busy on the
72
+ * host. Caller is responsible for persisting the returned ports into
73
+ * the used-ports registry. */
74
+ export async function pickProjectPorts(used, options) {
75
+ const usedSet = new Set(used);
76
+ const server = await pickPort(PORT_RANGES.server[0], PORT_RANGES.server[1], usedSet);
77
+ usedSet.add(server);
78
+ const client = await pickPort(PORT_RANGES.client[0], PORT_RANGES.client[1], usedSet);
79
+ usedSet.add(client);
80
+ const ports = { server, client };
81
+ if (options.nativeHmr) {
82
+ ports.nativeHmr = await pickPort(PORT_RANGES.nativeHmr[0], PORT_RANGES.nativeHmr[1], usedSet);
83
+ }
84
+ return ports;
85
+ }
86
+ //# sourceMappingURL=ports.js.map