@flisk-sh/flisk 1.3.205 → 1.3.206

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 (48) hide show
  1. package/cli/dist/cli.js +230 -92
  2. package/cli/dist/commands/doctor.js +29 -15
  3. package/cli/dist/commands/project.js +104 -58
  4. package/cli/dist/commands/up.js +8 -5
  5. package/cli/dist/generator/template-engine.js +17 -9
  6. package/cli/dist/utils/cli-command.js +3 -1
  7. package/cli/dist/utils/demo-stage.js +315 -0
  8. package/cli/dist/utils/native-windows.js +20 -0
  9. package/cli/dist/utils/one-command.js +15 -8
  10. package/cli/dist-bundle/chunk-3QQGL3NQ.js +35 -0
  11. package/cli/dist-bundle/chunk-4W6OXDLK.js +17 -0
  12. package/cli/dist-bundle/chunk-53M5D4KE.js +2 -0
  13. package/cli/dist-bundle/{chunk-4TMLNLYG.js → chunk-5CFVN3W3.js} +1 -1
  14. package/cli/dist-bundle/{chunk-P2MFLNY2.js → chunk-6Y6G7PSD.js} +1 -1
  15. package/cli/dist-bundle/chunk-7C5VA6CW.js +57 -0
  16. package/cli/dist-bundle/chunk-D2BXXJDM.js +7 -0
  17. package/cli/dist-bundle/chunk-GANRXKBM.js +2 -0
  18. package/cli/dist-bundle/chunk-GOEBYLFN.js +2 -0
  19. package/cli/dist-bundle/chunk-LI3BXAX5.js +2 -0
  20. package/cli/dist-bundle/{chunk-BHQDQQYQ.js → chunk-NCEK46NX.js} +10 -10
  21. package/cli/dist-bundle/chunk-ODVBKN6S.js +2 -0
  22. package/cli/dist-bundle/{chunk-5G7E6CO2.js → chunk-PHI5AT3H.js} +2 -2
  23. package/cli/dist-bundle/chunk-XSPMLWAE.js +10 -0
  24. package/cli/dist-bundle/cli.js +265 -263
  25. package/cli/dist-bundle/cold-preflight-4I24DQLW.js +2 -0
  26. package/cli/dist-bundle/demo-stage-EOMANLAD.js +7 -0
  27. package/cli/dist-bundle/native-windows-X5XVLFJS.js +2 -0
  28. package/cli/dist-bundle/one-command-P6XVAXWV.js +5 -0
  29. package/cli/dist-bundle/open-6374RNL6.js +2 -0
  30. package/cli/dist-bundle/project-IRWFRXWA.js +2 -0
  31. package/cli/dist-bundle/services-VIIBMWD4.js +2 -0
  32. package/cli/dist-bundle/tilt-port-owner-AN3ITRTR.js +2 -0
  33. package/cli/dist-bundle/url-actions-D6ROTHZG.js +2 -0
  34. package/cli/package.json +1 -1
  35. package/package.json +1 -1
  36. package/cli/dist-bundle/chunk-67M3DX6J.js +0 -34
  37. package/cli/dist-bundle/chunk-CF46CD6R.js +0 -6
  38. package/cli/dist-bundle/chunk-CLQSJP6M.js +0 -21
  39. package/cli/dist-bundle/chunk-DTIHDMED.js +0 -5
  40. package/cli/dist-bundle/chunk-IQNUVQH5.js +0 -52
  41. package/cli/dist-bundle/chunk-WVSI4XL5.js +0 -4
  42. package/cli/dist-bundle/chunk-YNJTA77W.js +0 -2
  43. package/cli/dist-bundle/cold-preflight-R53YXYOC.js +0 -2
  44. package/cli/dist-bundle/one-command-YP6L6MMM.js +0 -5
  45. package/cli/dist-bundle/open-PKNOQQXA.js +0 -2
  46. package/cli/dist-bundle/project-I5QVEGNB.js +0 -2
  47. package/cli/dist-bundle/spinner-YLB6FYQH.js +0 -2
  48. package/cli/dist-bundle/tilt-port-owner-Y5LHXWPS.js +0 -2
@@ -0,0 +1,315 @@
1
+ // Copyright (c) 2026 Flisk Landscape contributors
2
+ // SPDX-License-Identifier: MIT
3
+ import chalk from "chalk";
4
+ import { stripTerminalControls } from "./tilt-events.js";
5
+ /**
6
+ * Rows the frame always occupies.
7
+ *
8
+ * A fixed height is what keeps the terminal from scrolling, which matters most when the
9
+ * demo is recorded: a frame that grows pushes everything off the screen.
10
+ */
11
+ export const FRAME_ROWS = 12;
12
+ /** The narrowest frame that still reads. Below this the labels are truncated to nothing. */
13
+ const MIN_FRAME_WIDTH = 24;
14
+ const STYLES = {
15
+ plain: (text) => text,
16
+ bold: chalk.bold,
17
+ dim: chalk.gray,
18
+ ok: chalk.green,
19
+ warn: chalk.yellow,
20
+ err: chalk.red,
21
+ };
22
+ /**
23
+ * State glyphs, so the frame still reads in a terminal without color and in a grayscale
24
+ * video encode. Color never carries the only signal.
25
+ */
26
+ const GLYPH = {
27
+ pending: "○",
28
+ active: "◐",
29
+ done: "✔",
30
+ failed: "✖",
31
+ };
32
+ const GLYPH_STYLE = {
33
+ pending: "dim",
34
+ active: "warn",
35
+ done: "ok",
36
+ failed: "err",
37
+ };
38
+ /**
39
+ * Control characters, including ESC, are removed from every value that reaches the frame.
40
+ *
41
+ * A repo name or an error line from git can carry ANSI sequences. Painted verbatim they
42
+ * can move the cursor and shred a fixed frame, which on a recording looks like the tool broke.
43
+ * A newline is flattened too: every cell is exactly one row tall.
44
+ */
45
+ export function sanitizeCell(value) {
46
+ return stripTerminalControls(String(value)).replace(/[\n\r\t]/g, " ");
47
+ }
48
+ /** `0.9s`, `12.4s`, `1m 12s`. Short enough to sit in a right-aligned column. */
49
+ export function formatElapsed(ms) {
50
+ if (!Number.isFinite(ms) || ms < 0)
51
+ return "0.0s";
52
+ if (ms < 10_000)
53
+ return `${(ms / 1000).toFixed(1)}s`;
54
+ if (ms < 60_000)
55
+ return `${Math.round(ms / 1000)}s`;
56
+ const minutes = Math.floor(ms / 60_000);
57
+ const seconds = Math.round((ms % 60_000) / 1000);
58
+ return `${minutes}m ${seconds}s`;
59
+ }
60
+ function plainLength(row) {
61
+ return row.reduce((total, segment) => total + segment.text.length, 0);
62
+ }
63
+ /** Cuts a row to `max` characters, keeping whole segments and ellipsizing the one that straddles. */
64
+ function truncateRow(row, max) {
65
+ if (max <= 0)
66
+ return [];
67
+ const kept = [];
68
+ let used = 0;
69
+ for (const segment of row) {
70
+ if (used >= max)
71
+ break;
72
+ const room = max - used;
73
+ if (segment.text.length <= room) {
74
+ kept.push(segment);
75
+ used += segment.text.length;
76
+ continue;
77
+ }
78
+ kept.push({ ...segment, text: `${segment.text.slice(0, Math.max(0, room - 1))}…` });
79
+ used = max;
80
+ }
81
+ return kept;
82
+ }
83
+ function padRow(row, width) {
84
+ const clipped = truncateRow(row, width);
85
+ const padding = width - plainLength(clipped);
86
+ if (padding <= 0)
87
+ return clipped;
88
+ return [...clipped, { text: " ".repeat(padding), style: "plain" }];
89
+ }
90
+ /** Left content, right-aligned content, spaces between. The label gives way first. */
91
+ function splitRow(left, right, width) {
92
+ const rightLength = plainLength(right);
93
+ const room = width - rightLength - 1;
94
+ if (room < 4)
95
+ return padRow(truncateRow([...left, ...right], width), width);
96
+ const clippedLeft = truncateRow(left, room);
97
+ const gap = width - plainLength(clippedLeft) - rightLength;
98
+ return [...clippedLeft, { text: " ".repeat(Math.max(1, gap)), style: "plain" }, ...right];
99
+ }
100
+ function rule(width) {
101
+ return [{ text: ` ${"─".repeat(Math.max(0, width - 2))}`, style: "dim" }];
102
+ }
103
+ function phaseRow(phase, width) {
104
+ return splitRow([
105
+ { text: " ", style: "plain" },
106
+ { text: GLYPH[phase.status], style: GLYPH_STYLE[phase.status] },
107
+ { text: " ", style: "plain" },
108
+ { text: sanitizeCell(phase.label), style: phase.status === "pending" ? "dim" : "plain" },
109
+ ], phase.elapsedMs === undefined ? [] : [{ text: formatElapsed(phase.elapsedMs), style: "dim" }], width);
110
+ }
111
+ function servicesLine(state) {
112
+ const total = Math.max(0, state.servicesTotal);
113
+ if (total === 0)
114
+ return "no services found";
115
+ const ready = Math.min(Math.max(0, state.servicesReady), total);
116
+ const parts = [`${ready} of ${total} services ready`];
117
+ if (state.servicesBuilding > 0)
118
+ parts.push(`${state.servicesBuilding} building`);
119
+ return parts.join(" · ");
120
+ }
121
+ /**
122
+ * Builds the frame as plain segments. No I/O, no clock, no terminal size.
123
+ *
124
+ * Keeping this pure is what makes the transcript snapshot-testable and the recording
125
+ * deterministic: the same state always paints the same twelve rows.
126
+ */
127
+ export function renderDemoFrame(state, columns = 80) {
128
+ // A pseudo-terminal can report 0 columns before the first resize. That is "unknown",
129
+ // not a tiny terminal, so it falls back to 80 instead of the minimum width.
130
+ const reported = Number.isFinite(columns) && columns > 0 ? columns : 80;
131
+ const width = Math.max(MIN_FRAME_WIDTH, Math.min(reported - 1, 78));
132
+ const rows = [];
133
+ const push = (row) => rows.push(padRow(row, width));
134
+ const blank = () => push([]);
135
+ if (state.done) {
136
+ push(splitRow([
137
+ { text: " ", style: "plain" },
138
+ { text: "✔", style: "ok" },
139
+ { text: " Your stack is running", style: "ok" },
140
+ ], [{ text: formatElapsed(state.elapsedMs), style: "dim" }], width));
141
+ push([
142
+ { text: " ", style: "plain" },
143
+ { text: sanitizeCell(state.subtitle), style: "dim" },
144
+ ]);
145
+ blank();
146
+ for (const url of state.done.urls.slice(0, 2)) {
147
+ push([
148
+ { text: " ", style: "plain" },
149
+ { text: sanitizeCell(url), style: "plain" },
150
+ ]);
151
+ }
152
+ blank();
153
+ push(rule(width));
154
+ push([
155
+ { text: " ", style: "plain" },
156
+ { text: sanitizeCell(state.done.summary), style: "plain" },
157
+ ]);
158
+ push([
159
+ { text: " ", style: "plain" },
160
+ { text: sanitizeCell(state.done.hint), style: "dim" },
161
+ ]);
162
+ blank();
163
+ push([
164
+ { text: " ", style: "plain" },
165
+ { text: `flisk ${sanitizeCell(state.done.version)}`, style: "dim" },
166
+ ]);
167
+ }
168
+ else if (state.failure) {
169
+ const failed = state.phases.find((phase) => phase.status === "failed");
170
+ push(splitRow([
171
+ { text: " ", style: "plain" },
172
+ { text: "✖", style: "err" },
173
+ { text: " ", style: "plain" },
174
+ { text: sanitizeCell(failed?.label ?? "The demo stopped"), style: "err" },
175
+ ], [{ text: formatElapsed(state.elapsedMs), style: "dim" }], width));
176
+ blank();
177
+ push([
178
+ { text: " ", style: "plain" },
179
+ { text: sanitizeCell(state.failure.message), style: "plain" },
180
+ ]);
181
+ if (state.failure.fix) {
182
+ push([
183
+ { text: " ", style: "plain" },
184
+ { text: sanitizeCell(state.failure.fix), style: "dim" },
185
+ ]);
186
+ }
187
+ blank();
188
+ push(rule(width));
189
+ if (state.detail) {
190
+ push([
191
+ { text: " ", style: "plain" },
192
+ { text: sanitizeCell(state.detail), style: "dim" },
193
+ ]);
194
+ }
195
+ if (state.failure.logPath) {
196
+ push([
197
+ { text: " ", style: "plain" },
198
+ { text: `log: ${sanitizeCell(state.failure.logPath)}`, style: "dim" },
199
+ ]);
200
+ }
201
+ }
202
+ else {
203
+ push([
204
+ { text: " ", style: "plain" },
205
+ { text: sanitizeCell(state.title), style: "bold" },
206
+ ]);
207
+ push([
208
+ { text: " ", style: "plain" },
209
+ { text: sanitizeCell(state.subtitle), style: "dim" },
210
+ ]);
211
+ blank();
212
+ const visible = state.phases.slice(0, 4);
213
+ for (const phase of visible)
214
+ push(phaseRow(phase, width));
215
+ for (let index = visible.length; index < 4; index += 1)
216
+ blank();
217
+ blank();
218
+ push(rule(width));
219
+ push([
220
+ { text: " ", style: "plain" },
221
+ { text: sanitizeCell(state.detail ?? ""), style: "dim" },
222
+ ]);
223
+ push(splitRow([
224
+ { text: " ", style: "plain" },
225
+ { text: servicesLine(state), style: "plain" },
226
+ ], [{ text: formatElapsed(state.elapsedMs), style: "dim" }], width));
227
+ }
228
+ while (rows.length < FRAME_ROWS)
229
+ rows.push(padRow([], width));
230
+ return rows.slice(0, FRAME_ROWS);
231
+ }
232
+ /** The frame as plain text lines. This is what the snapshot tests assert on. */
233
+ export function frameToPlain(rows) {
234
+ return rows.map((row) => row.map((segment) => segment.text).join(""));
235
+ }
236
+ /** Applies color to a row. Called only at paint time, so the renderer stays testable. */
237
+ export function styleRow(row) {
238
+ return row.map((segment) => STYLES[segment.style](segment.text)).join("");
239
+ }
240
+ /**
241
+ * Paints the frame in place.
242
+ *
243
+ * Each paint clears and rewrites the same {@link FRAME_ROWS} lines and then walks the cursor
244
+ * back, so the frame never scrolls. A terminal without a TTY gets one plain line per phase
245
+ * change instead, because an animated frame is meaningless in a piped log.
246
+ */
247
+ export function createDemoStage(initial, stream = process.stderr, now = Date.now) {
248
+ const animate = stream.isTTY === true;
249
+ const startedAt = now();
250
+ let state = { ...initial };
251
+ let painted = false;
252
+ let lastFrame = "";
253
+ let lastPlainSignature = "";
254
+ let timer;
255
+ const snapshot = () => {
256
+ const finished = Boolean(state.done || state.failure);
257
+ return {
258
+ ...state,
259
+ elapsedMs: finished ? state.elapsedMs : now() - startedAt,
260
+ };
261
+ };
262
+ const paint = () => {
263
+ const current = snapshot();
264
+ const rows = renderDemoFrame(current, stream.columns ?? 80);
265
+ const plain = frameToPlain(rows);
266
+ if (!animate) {
267
+ const signature = plain.join("\n");
268
+ if (signature === lastPlainSignature)
269
+ return;
270
+ lastPlainSignature = signature;
271
+ stream.write(`${plain.filter((line) => line.trim() !== "").join("\n")}\n`);
272
+ return;
273
+ }
274
+ const frame = plain.join("\n");
275
+ if (frame === lastFrame && painted)
276
+ return;
277
+ lastFrame = frame;
278
+ // Walk back to the first row of the previous paint, then clear and rewrite each line.
279
+ if (painted)
280
+ stream.write(`\x1b[${FRAME_ROWS}A`);
281
+ for (const row of rows)
282
+ stream.write(`\r\x1b[2K${styleRow(row)}\n`);
283
+ painted = true;
284
+ };
285
+ if (animate) {
286
+ paint();
287
+ timer = setInterval(paint, 200);
288
+ // The frame must never be the reason a finished demo keeps the process alive.
289
+ timer.unref?.();
290
+ }
291
+ return {
292
+ update(patch) {
293
+ state = { ...state, ...patch, phases: patch.phases ?? state.phases };
294
+ paint();
295
+ },
296
+ fail(message, fix, logPath) {
297
+ state = {
298
+ ...state,
299
+ elapsedMs: now() - startedAt,
300
+ failure: { message, fix, logPath },
301
+ phases: state.phases.map((phase) => phase.status === "active" ? { ...phase, status: "failed" } : phase),
302
+ };
303
+ paint();
304
+ },
305
+ finish(done) {
306
+ state = { ...state, elapsedMs: now() - startedAt, done };
307
+ paint();
308
+ },
309
+ stop() {
310
+ if (timer)
311
+ clearInterval(timer);
312
+ timer = undefined;
313
+ },
314
+ };
315
+ }
@@ -0,0 +1,20 @@
1
+ // Copyright (c) 2026 Flisk Landscape contributors
2
+ // SPDX-License-Identifier: MIT
3
+ /**
4
+ * The message native Windows gets when a command needs a stack.
5
+ *
6
+ * Native Windows is inspection-only: `flisk --version`, `flisk doctor` and `flisk up --dry-run`
7
+ * work, and anything that starts a stack needs Ubuntu on WSL2. Both `flisk up` and the
8
+ * one-command demo flow refuse with this message before they touch the machine.
9
+ */
10
+ export const NATIVE_WINDOWS_REFUSAL = "Landscape startup needs Ubuntu on WSL2. Native Windows is inspect-only.";
11
+ /**
12
+ * Why a command that starts a stack cannot run on this host, or null when it may proceed.
13
+ *
14
+ * `TDK_ALLOW_NATIVE_WINDOWS=1` is the unsupported escape hatch that lets it try anyway.
15
+ */
16
+ export function nativeWindowsStackRefusal(platform, allowNativeWindows) {
17
+ if (platform !== "win32" || allowNativeWindows === "1")
18
+ return null;
19
+ return NATIVE_WINDOWS_REFUSAL;
20
+ }
@@ -26,30 +26,37 @@ export function findFrontendUrl(output) {
26
26
  * A starter repository holds services and a Tiltfile, but no project configuration, and
27
27
  * `flisk up` refuses to run without one. So the one-command flow initializes the folder it
28
28
  * just cloned before it starts the stack.
29
+ *
30
+ * Nothing is inherited: a child that writes straight to the terminal corrupts the frame the
31
+ * caller is painting. Both streams are captured, and `--quiet` keeps the setup from printing
32
+ * its full configuration report at all.
29
33
  */
30
34
  export function initializeProject(binPath, cwd, env = process.env, spawnFn = spawn) {
31
35
  return new Promise((resolve) => {
32
- const child = spawnFn(process.execPath, [binPath, "project", "--yes"], {
36
+ const child = spawnFn(process.execPath, [binPath, "project", "--yes", "--quiet"], {
33
37
  cwd,
34
38
  env,
35
- stdio: ["inherit", "inherit", "pipe"],
39
+ stdio: ["ignore", "pipe", "pipe"],
40
+ });
41
+ let output = "";
42
+ child.stdout?.on("data", (chunk) => {
43
+ output += String(chunk);
36
44
  });
37
- let errors = "";
38
45
  child.stderr?.on("data", (chunk) => {
39
- errors += String(chunk);
46
+ output += String(chunk);
40
47
  });
41
- child.on("error", (error) => resolve({ ok: false, error: error.message }));
48
+ child.on("error", (error) => resolve({ ok: false, error: error.message, output }));
42
49
  child.on("close", (code) => {
43
50
  if (code === 0) {
44
- resolve({ ok: true });
51
+ resolve({ ok: true, output });
45
52
  return;
46
53
  }
47
- const last = errors
54
+ const last = output
48
55
  .split("\n")
49
56
  .map((line) => line.trim())
50
57
  .filter(Boolean)
51
58
  .pop();
52
- resolve({ ok: false, error: last ?? `the project setup failed (code ${code})` });
59
+ resolve({ ok: false, error: last ?? `the project setup failed (code ${code})`, output });
53
60
  });
54
61
  });
55
62
  }
@@ -0,0 +1,35 @@
1
+ import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
2
+ import{a as C}from"./chunk-GIMHTZNR.js";import{b as N,c as fe,d as V,i as D,j as Y,n as J,o as L,q as O}from"./chunk-NCEK46NX.js";import{$ as ae,ea as ie,fa as se,h as T,ha as ce,i as B,ja as le,ka as de,la as pe,o as h,p as b,q as t,x as re,y as G,z as W}from"./chunk-4W6OXDLK.js";import{M as U,O as z,Q as E,b as g,f as x,m as M,o as P,x as F}from"./chunk-XSPMLWAE.js";import{execFileSync as Se}from"node:child_process";import{cpSync as je,existsSync as S,readdirSync as _e,readFileSync as K,writeFileSync as we}from"node:fs";import{basename as xe,dirname as Pe,isAbsolute as Ee,join as _,resolve as q}from"node:path";import{cwd as he}from"node:process";import{fileURLToPath as Oe}from"node:url";import{Command as Ce}from"commander";var ve="-y, --yes",ye="Skip prompts and confirmations; use defaults";function ue(e,o=ye){return e.option(ve,o,!1)}async function be(e,o=!0){let l=await L({message:e,initial:o});return l||T(),l}function Le(e,o=1){e.valid||E(e.error??"Validation failed",o)}function Ie(e,o,l,s){return e.dryRun?(s?s():(console.log(`Dry run - ${o}`),console.log(`Would run: ${l}`)),!0):!1}async function qe(e,o){return await be(e,!0)?!0:(o&&o(),!1)}var I=new Map;function me(e){e!==void 0?I.delete(e):I.clear()}function Be(e=!1){let o=F(),l=o??"";if(!e){let p=I.get(l);if(p)return p}let{resources:s,problems:d}=o?ie(o):{resources:ce(),problems:[]},u=pe(s),n=de(s);se(d);let r=s.filter(p=>!p.stack),f=new Map;for(let p of s)if(p.stack){let i=f.get(p.stack)||[];i.push(p),f.set(p.stack,i)}let m={resources:s,problems:d,stacks:u,stackNames:n,unassignedResources:r,resourcesByStack:f};return I.set(l,m),m}var A={proxy:{name:"proxy",description:"Traefik reverse proxy and API gateway for routing all services",category:"core",phase:"pre_alpha",enabled_by_default:!0,dependsOn:[]},verdaccio:{name:"verdaccio",description:"Verdaccio npm registry for package management and local publishing (Premium - requires TDK_LICENSE_KEY)",category:"premium",phase:"pre_alpha",enabled_by_default:!1,dependsOn:[]},[x]:{name:x,description:"PostgreSQL database for data persistence and SQL operations",category:"core",phase:"pre_alpha",enabled_by_default:!0,dependsOn:[]},monitoring:{name:"monitoring",description:"SigNoz or SkyWalking observability platform for monitoring and tracing",category:"optional",phase:"pre_alpha",enabled_by_default:!1,dependsOn:[x]},elk:{name:"elk",description:"Elasticsearch, Logstash, Kibana stack for log aggregation and analysis",category:"optional",phase:"pre_alpha",enabled_by_default:!1,dependsOn:[]},debezium:{name:"debezium",description:"Change Data Capture for real-time data streaming from databases",category:"optional",phase:"pre_alpha",enabled_by_default:!1,dependsOn:[x]},"golden-image":{name:"golden-image",description:"Pre-built Docker image layer for faster builds and smaller deployments",category:"optional",phase:"pre_alpha",enabled_by_default:!0,dependsOn:[]}};function H(e,o){try{return le(e,o)}catch{return[]}}function Ae(e){return new Set([...e.phases.pre_alpha.enabledStacks,...e.phases.alpha.enabledStacks,...e.phases.beta.enabledStacks,...e.phases.out_of_scope.enabledStacks])}function Q(e,o){let l=Ae(e),s=o.filter(d=>!l.has(d));return s.length===0?(e.phases.pre_alpha.enabledStacks=Array.from(new Set(e.phases.pre_alpha.enabledStacks)),[]):(e.phases.pre_alpha.enabledStacks=Array.from(new Set([...e.phases.pre_alpha.enabledStacks,...s])),s)}function gt(e,o){let l=_(e,".tdk",M);if(!S(l))return[];let s=D(e),d=Q(s,H(e,o));return d.length>0&&N(l,s),d}function $e(){return Object.values(A).filter(e=>e.enabled_by_default&&e.category==="core").map(e=>e.name)}function Re(e,o){return o||(C[e]?.repo.split("/").pop()??e).replace(/\.git$/,"")}function ge(e){return e.split(`
3
+ `).map(l=>l.trim()).filter(Boolean).pop()??"unknown error"}async function Fe(e,o,l,s={}){let d=C[e];if(!d){console.log(g.red(`
4
+ \u274C Unknown template: "${e}"`)),console.log(g.yellow(`
5
+ Available templates:`));for(let[r,f]of Object.entries(C))console.log(` ${g.cyan(r)} ${g.gray(`- ${f.description}`)}`);console.log(g.gray("\nOr run `flisk project` with no template for a blank project.")),process.exit(1)}let u=Re(e,o);ae(u)||U.invalidPath(u).exit();let n=Ee(u)?u:q(he(),u);S(n)&&_e(n).length>0&&U.directoryExists(n).exit(),s.quiet||(B(`Cloning template: ${e}`),t(`${d.description}
6
+ `,0),t(`Source: ${d.bundledPath?"bundled Flisk example":d.repo}`,0),t(`Destination: ${n}
7
+ `,0));try{if(d.bundledPath){let r=q(Pe(Oe(new URL("../dist/commands/project.js",import.meta.url).href)),"../../../");je(q(r,d.bundledPath),n,{recursive:!0});let f=xe(n).replace(/-/g,"_");for(let m of["services/platform/messaging/docker-compose.yml","services/shop/orders-api/service.json","services/shop/orders-api/src/index.ts","services/shop/orders-worker/service.json","services/shop/orders-worker/src/index.ts"]){let p=_(n,m),i=K(p,"utf-8");we(p,i.replaceAll("tdk_example",f))}}else Se("git",["clone",d.repo,n],{stdio:["ignore","pipe","pipe"],encoding:"utf-8"})}catch(r){let f=r instanceof Error?r.message:String(r),m=d.bundledPath?`Bundled example copy failed (${ge(f)}). Reinstall the Flisk CLI package and try again.`:`git clone failed: ${ge(f)}. Check you have git installed and network access.`;if(s.quiet)throw new Error(m);E(m)}if(me(),!s.quiet){console.log(g.green(`
8
+ \u2705 Cloned "${e}" into ${u}/`)),t(`
9
+ Next steps:`,0),t(`1. cd ${u}`),t("2. flisk doctor # check Docker/Tilt are ready"),t("3. flisk up # start the stack"),t(`
10
+ Runtime readiness:`,0);for(let r of l)t(r,0)}}var $={version:"1.0",project:{name:"",version:"1.0.0"},phases:{pre_alpha:{name:"Pre-Alpha",description:"Core infrastructure and MVP services",enabledStacks:$e()},alpha:{name:"Alpha",description:"Essential business services",enabledStacks:[]},beta:{name:"Beta",description:"Extended features",enabledStacks:[]},out_of_scope:{name:"Out of Scope",description:"Future releases",enabledStacks:[]}},optional_infra:{monitoring:!1,elk:!1,debezium:!1,golden_image:!0,verdaccio:!1},discovery:{paths:["services/*/*"]},overrides:{}},ht=ue(new Ce("project")).description("Initialize or validate project-level master configuration").argument("[template]",`Clone a starter example instead of a blank project (${Object.keys(C).join(", ")})`).option("--path <dir>","Directory to clone the template into (default: the template's repo name)").option("--check","Check if master configs exist and are in sync").option("--force","Overwrite existing configuration (dangerous)").option("--config-file <path>","Load project config from existing JSON file").option("-q, --quiet","Only print what fails; used by `flisk demo`",!1).action(async(e,o)=>{let{assertMachineReadyOrExit:l,detectRuntimePrerequisites:s,formatRuntimeNextSteps:d}=await import("./cold-preflight-4I24DQLW.js");await l({scope:"scaffold"});let u=d(s()),n=!!o.quiet;if(e){await z(async()=>Fe(e,o.path,u,{quiet:n}));return}await z(async()=>{let r=F();r||(r=he(),n||(b(`\u{1F680} Initializing new Flisk project...
11
+ `),t(`Location: ${r}
12
+ `,0)));let f=_(r,".tdk"),m=_(f,M);if(o.check){let c=P.every(k=>S(_(r,".tdk",".tdk-out",k))),v=S(m);if(c&&v){let k=D(r);h("Project configuration is valid"),t(`Project: ${k.project.name}`,3),t(`Phases: ${Object.keys(k.phases).join(", ")}`,3),process.exit(0)}else{if(console.log(g.yellow("\u26A0\uFE0F Project configuration incomplete:")),v||t(".tdk/project.json (not found)",3),!c)for(let k of P.filter(j=>!S(_(r,".tdk/.tdk-out",j))))t(`.tdk/.tdk-out/${k} (not found)`,3);t("Run `flisk project` to create them."),process.exit(1)}}n||(B("Project Configuration"),t(`Project root: ${r}
13
+ `,0)),S(f)||(fe(f),n||h("Created: .tdk/ directory"));let p=S(m);if(p&&!o.force){n||h(".tdk/project.json exists");let c=JSON.parse(K(m,"utf-8")),v=D(r),k=H(r),j=Q(v,k);if((j.length>0||!c.phases)&&N(m,v),j.length>0&&!n&&t(`Auto-enabled discovered service stacks: ${j.join(", ")}`,0),n||b(`
14
+ \u{1F4CB} Regenerating master configuration files...
15
+ `),await Y(r,{quiet:n}),W(r))n||h("Created: .env (the defaults work as-is)");else{let y=G(r);y.length>0&&!n&&h(`Updated: .env (added ${y.join(", ")}; existing values unchanged)`)}let R=V(r);if(R.length>0&&!n&&h(`Added to .gitignore: ${R.join(", ")}`),!n){console.log(g.green(`
16
+ \u2705 Project configuration regenerated!`)),t(`
17
+ Generated in .tdk/.tdk-out/:`,0);for(let y of P)t(`- ${y}`);t(`
18
+ Runtime readiness:`,0);for(let y of u)t(y,0)}return}if(p&&o.force&&!o.yes&&(console.log(g.red(`
19
+ \u26A0\uFE0F WARNING: --force will overwrite .tdk/project.json!`)),!await L({message:"This will reset your project configuration. Continue?",initial:!1}))){T();return}let i,X=H(r);if(o.configFile){let c=q(o.configFile);S(c)||E(`Config file not found: ${c}`);let v=K(c,"utf-8");i=JSON.parse(v),n||h(`Loaded config from: ${c}`)}else if(o.yes)i=JSON.parse(JSON.stringify($)),i.project.name=r.split("/").pop()||"my-project",n||console.log(g.gray("Using default configuration (non-interactive mode)"));else{b(`\u{1F4DD} Project Setup Wizard
20
+ `);let c=await J({message:"Project name:",initial:r.split("/").pop()||"my-project",validate:a=>a.trim()!==""||"Project name is required"}),v=await J({message:"Project version:",initial:"1.0.0-alpha"}),k=Object.values(A).filter(a=>a.category==="core"&&a.phase==="pre_alpha"),j=new Set(k.map(a=>a.name)),oe=await O({message:"Select Pre-Alpha enabled stacks (core infrastructure):",choices:[...k.map(a=>({title:a.description,value:a.name,selected:a.enabled_by_default})),...X.filter(a=>!j.has(a)).map(a=>({title:`${a} (discovered service stack)`,value:a,selected:!0}))]}),R=await O({message:"Select Alpha enabled stacks (core business):",choices:[{title:"api (Backend API)",value:"api"},{title:"app (Frontend app)",value:"app"}]}),y=await O({message:"Select Beta enabled stacks (extended features):",choices:[{title:"worker (Background jobs)",value:"worker"},{title:"migrator (Database migrations)",value:"migrator"}]}),w=await O({message:"Enable optional infrastructure (high resource):",choices:Object.values(A).filter(a=>a.category==="optional").concat(Object.values(A).filter(a=>a.category==="premium")).map(a=>({title:a.description,value:a.name,selected:a.enabled_by_default}))});b(`
21
+ \u{1F4C2} Service discovery`),t("What: folder patterns Flisk scans for a service.json in each match."),t("Where: type one or more globs, comma-separated."),t("How: saved as discovery.paths in .tdk/project.json - editable later."),t(`Example: ${$.discovery.paths.join(", ")}
22
+ `);let ke=await J({message:"Folders to scan:",initial:$.discovery.paths.join(", ")});i=JSON.parse(JSON.stringify($)),i.project.name=c,i.project.version=v,i.phases.pre_alpha.enabledStacks=Array.from(new Set(oe)),i.phases.alpha.enabledStacks=Array.from(new Set(R)),i.phases.beta.enabledStacks=Array.from(new Set(y)),i.optional_infra.monitoring=w.includes("monitoring"),i.optional_infra.elk=w.includes("elk"),i.optional_infra.debezium=w.includes("debezium"),i.optional_infra.golden_image=w.includes("golden_image"),i.optional_infra.verdaccio=w.includes("verdaccio");let ne=ke.split(",").map(a=>a.trim()).filter(a=>a.length>0);i.discovery.paths=ne.length>0?ne:$.discovery.paths}let Z=Q(i,X);if(Z.length>0&&!n&&t(`Auto-enabled discovered service stacks: ${Z.join(", ")}`,0),n||b(`
23
+ \u{1F4CB} Creating project configuration...
24
+ `),N(m,i),n||(h("Created: .tdk/project.json"),t(`\u2192 Project: ${i.project.name}`),b(`
25
+ \u{1F4CB} Generating master configuration files...
26
+ `)),await Y(r,{quiet:n}),n||b(`
27
+ \u{1F527} Setting up environment variables...
28
+ `),W(r))n||h("Created: .env (the defaults work as-is)");else{let c=G(r);c.length>0?n||h(`Updated: .env (added ${c.join(", ")}; existing values unchanged)`):n||h("Found: .env (environment already configured)")}let ee=re(r);if(ee.missing.length>0){console.log(g.yellow(`
29
+ \u26A0\uFE0F Missing required environment variables:`));for(let c of ee.missing)t(`- ${c}`,1);t("\u2192 Edit .env and fill in these values before running `flisk up`",1)}let te=V(r);if(te.length>0&&!n&&h(`Added to .gitignore: ${te.join(", ")}`),!n){console.log(g.green(`
30
+ \u2705 Project configuration complete!`)),t(`
31
+ Generated files in .tdk/.tdk-out/:`,0);for(let c of P)t(`- ${c}`);t(`
32
+ Environment configuration:`,0),t("- .env (contains all required variables)"),t(`
33
+ Source file:`,0),t("- .tdk/project.json (edit this to change project structure)"),t(`
34
+ Next steps:`,0),t("1. flisk resource api --type backend --stack app # scaffold a service"),t("2. flisk up app # start it"),t(`
35
+ Runtime readiness:`,0);for(let c of u)t(c,0);t("\nAfter editing .tdk/project.json, run `flisk config regenerate`.",0)}})});export{me as a,Be as b,ue as c,Le as d,Ie as e,qe as f,gt as g,Re as h,Fe as i,ht as j};
@@ -0,0 +1,17 @@
1
+ import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
2
+ import{M as q,b as f,e as G,h as xe,i as Ee,m as ke,n as we,r as z,u as ve,v as be,x as T}from"./chunk-XSPMLWAE.js";import st,{existsSync as O,readdirSync as nn,readFileSync as rn,statSync as ce}from"node:fs";import{dirname as on,join as w}from"node:path";var j=class{data;options;constructor(t){this.data=new Map,this.options=t}has(t){let n=this.data.get(t);return n?Date.now()-n.timestamp>this.options.ttlMs?(this.data.delete(t),!1):!0:!1}get(t){if(this.has(t))return this.data.get(t)?.value}set(t,n){this.data.set(t,{value:n,timestamp:Date.now()})}delete(t){this.data.delete(t)}clear(){this.data.clear()}keys(){let t=[];for(let n of this.data.keys())this.has(n)&&t.push(n);return t}size(){return this.keys().length}};function Te(e){let t=0;return{isValid(){return Date.now()-t<e},markUpdated(){t=Date.now()},reset(){t=0}}}function ct(e,t,n){return e===1?t:n||`${t}s`}function Re(e,t,n){return`${e} ${ct(e,t,n)}`}var ut={month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"};function Sn(e){return new Date(e).toLocaleString("en-US",ut)}function yn(e){return new Date(e).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var K={success:{color:"green",icon:"\u2713",chalkFn:f.green},error:{color:"red",icon:"\u2717",chalkFn:f.red},warning:{color:"yellow",icon:"\u25CB",chalkFn:f.yellow},unknown:{color:"gray",icon:"?",chalkFn:f.gray}};function H(e){if(!e)return"unknown";let t=e.toLowerCase();return t==="ready"||t==="healthy"||t==="active"||t==="running"?"success":t==="error"||t==="failed"||t==="critical"||t==="stopped"?"error":t==="pending"||t==="starting"||t==="building"||t==="degraded"?"warning":"unknown"}function $n(e){return K[H(e)].color}function xn(e){return K[H(e)].icon}function En(e,t){return K[H(t)].chalkFn(e)}var ft={resources:{singular:"resource",command:"flisk resource <name>",context:`
3
+ To create a resource:`},stacks:{singular:"stack",command:"flisk stack <stack-name>",context:`
4
+ To create a stack, use:`},services:{singular:"service",command:"flisk resource <name>",context:`
5
+ To create a service:`},"stack-services":{singular:"service",command:"flisk resource <name> --stack <stack-name>",context:`
6
+ To add services to this stack:`}};function kn(e,t){let n=ft[e];console.log(t?f.yellow(`No ${n.singular}s found${t}.`):f.yellow(`No ${n.singular}s found.`)),console.log(f.gray(n.context)),console.log(f.gray(` ${n.command}`)),e==="stacks"&&(console.log(f.gray(`
7
+ Or create a new resource with a stack:`)),console.log(f.gray(" flisk resource <name> --stack <stack-name>")))}function wn(e){console.log(f.yellow(e||"Cancelled."))}function vn(e){console.log(f.blue(`Flisk ${e}
8
+ `))}function bn(e,t){console.log(f.green(`All ${e} are ${t}!`))}var J=62;function Tn(e="\u2500",t=J){return e.repeat(t)}function Ae(e,t=J-2){let n=Math.max(0,t-e.length),r=Math.floor(n/2),o=n-r;return" ".repeat(r)+e+" ".repeat(o)}function An(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e.padEnd(t)}function Rn(e,t){return e.length<=t?e:`${e.slice(0,t-3)}...`}function _n(e){console.log(f.green(`\u2713 ${e}`))}function On(e){console.log(f.blue(e))}function Cn(e,t=2){console.log(f.gray(`${" ".repeat(t)}${e}`))}function Dn(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Fn(e,t,n=J){let r=n-2,o="\u2500".repeat(r);console.log(),console.log(f.cyan(`\u256D${o}\u256E`)),console.log(f.cyan("\u2502")+f.bold.white(Ae(e,r))+f.cyan("\u2502")),t&&(console.log(f.cyan(`\u251C${o}\u2524`)),console.log(f.cyan("\u2502")+f.gray(Ae(t,r))+f.cyan("\u2502"))),console.log(f.cyan(`\u2570${o}\u256F`))}import{existsSync as et,readFileSync as tt}from"node:fs";import{copyFileSync as Ve,mkdirSync as It,rmSync as We,writeFileSync as Ge}from"node:fs";import{join as _}from"node:path";function A(e){return e==="backend"||e==="mcp"||e==="agent"}import{existsSync as At,readFileSync as Rt}from"node:fs";import{join as _t}from"node:path";import{randomBytes as Oe}from"node:crypto";import{existsSync as Z,readFileSync as Ce,writeFileSync as De}from"node:fs";import{join as Q}from"node:path";import{randomBytes as pt}from"node:crypto";import{closeSync as dt,fchmodSync as lt,fsyncSync as mt,openSync as ht,renameSync as gt,rmSync as St,statSync as yt,writeFileSync as $t}from"node:fs";import{basename as xt,dirname as Et,join as kt}from"node:path";function _e(e,t){let n=kt(Et(e),`.${xt(e)}.${process.pid}.${pt(4).toString("hex")}.tmp`),r;try{r=yt(e).mode&511}catch{r=void 0}try{let o=ht(n,"wx");try{r!==void 0&&lt(o,r),$t(o,t,"utf-8"),mt(o)}finally{dt(o)}gt(n,e)}catch(o){throw St(n,{force:!0}),o}}var b=[{name:"VERDACCIO_URL_DOCKER",description:"Docker-internal URL of the private npm registry (Verdaccio, a paid feature)",required:!1,default:"http://verdaccio:4873",example:"http://verdaccio:4873"},{name:"VERDACCIO_URL",description:"Local URL of the private npm registry (Verdaccio, a paid feature)",required:!1,default:"http://localhost:4873"},{name:"TILT_ENV",description:"Tilt environment name",required:!0,default:"dev",example:"dev",complete:!0},{name:"DATABASE_URL",description:"PostgreSQL connection string (uses the generated DB_PASSWORD below)",required:!1},{name:"DB_PASSWORD",description:"PostgreSQL superuser password (docker-compose POSTGRES_PASSWORD)",required:!0,example:"postgres",complete:!0},{name:"JWT_SECRET",description:"Secret that signs local-jwt tokens (generated once per project; never shared between projects)",required:!1,complete:!0}],Fe=()=>Oe(16).toString("hex"),wt=()=>Oe(32).toString("hex"),Gn=b.filter(e=>e.complete).map(e=>e.name);function Y(e,t){return e==="DB_PASSWORD"?t:e==="JWT_SECRET"?wt():e==="DATABASE_URL"?`postgresql://postgres:${t}@postgres:5432/app_dev`:b.find(n=>n.name===e)?.default??""}function vt(e){let t=e.trim(),n=t[0];if(n==='"'||n==="'"){let o=!1;for(let s=1;s<t.length;s+=1){let a=t[s];if(o){o=!1;continue}if(a==="\\"){o=!0;continue}if(a===n){let i=t.slice(1,s);if(n==='"'){let c={n:`
9
+ `,r:"\r",t:" ",'"':'"',"\\":"\\",$:"$"};return i.replace(/\\([nrt"\\$])/g,(d,p)=>c[p]??p)}return i.replace(/\\'/g,"'")}}return t}let r=e.search(/\s#/);return(r===-1?e:e.slice(0,r)).trim()}function R(e){let t=new Map,n=e.startsWith("\uFEFF")?e.slice(1):e;for(let r of n.split(/\r?\n/)){let o=r.trim();if(!o||o.startsWith("#"))continue;let s=o.startsWith("export ")?o.slice(7).trim():o,a=s.indexOf("=");if(a<=0)continue;let i=s.slice(0,a).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&t.set(i,vt(s.slice(a+1)))}return t}function Ne(e){let t=[`# ${e.description}`];return e.required&&t.push("# Required (the value below is a working default)"),e.example&&t.push(`# Example: ${e.example}`),t}function je(){let e=Fe(),t=["# \u{1F527} Flisk Environment Configuration","# Generated by `flisk project`. The defaults work as-is; edit only to change them.","# Keep this file out of git: it holds a generated database password and JWT secret.","#","# After editing, run: flisk config regenerate && flisk up",""];for(let n of b)t.push(...Ne(n)),t.push(`${n.name}=${Y(n.name,e)}`),t.push("");return t.join(`
10
+ `)}function bt(e){let t=e.match(/^[a-z][a-z0-9+.-]*:\/\/[^:/@\s]+:([^@\s]*)@/i);if(!(!t||t[1].includes("$")))return t[1]}function zn(e){let t=Q(e,".env"),n={missing:[],invalid:[],warnings:[]};if(!Z(t))return{missing:b.filter(a=>a.required).map(a=>a.name),invalid:[],warnings:[".env file not found - will be auto-generated"]};let r=R(Ce(t,"utf-8"));for(let a of b)a.required&&!r.has(a.name)&&n.missing.push(a.name),r.has(a.name)&&!(r.get(a.name)??"").trim()&&n.invalid.push(`${a.name} is set but empty`);let o=r.get("DATABASE_URL"),s=r.get("DB_PASSWORD");if(o&&s){let a=bt(o);a!==void 0&&a!==s&&n.warnings.push("DATABASE_URL carries a different password than DB_PASSWORD; the database container uses DB_PASSWORD")}return n}function Tt(e,t,n){if(!R(e).has(t))return e;let o=e.indexOf("=");if(o<0)return e;let s=e.slice(o+1),a=s.search(/\s#/),i=a<0?"":s.slice(a);return e.slice(0,o+1)+n+i}function qn(e){let t=Q(e,".env");if(!Z(t))return De(t,je(),{mode:384}),b.map(u=>u.name);let n=Ce(t,"utf-8"),r=R(n),o=b.filter(u=>u.complete?r.has(u.name)?!(r.get(u.name)??"").trim():!0:!1);if(o.length===0)return[];let s=o.filter(u=>!r.has(u.name)),a=o.filter(u=>r.has(u.name)),i=r.get("DB_PASSWORD"),c=i?.trim()?i:Fe(),d=n.split(/(\r\n|\n|\r)/);for(let u of a){let h=-1;for(let l=0;l<d.length;l+=2)R(d[l]).has(u.name)&&(h=l);if(h<0)throw new Error(`Could not locate empty .env assignment for ${u.name}`);d[h]=Tt(d[h],u.name,Y(u.name,c))}let p=d.join("");if(s.length>0){let u=["","# Added by Flisk: keys this version expects. Existing values above were not changed.",""];for(let l of s)u.push(...Ne(l)),u.push(`${l.name}=${Y(l.name,c)}`),u.push("");let h=p.endsWith(`
11
+ `)||p.endsWith("\r")?"":`
12
+ `;p+=h+u.join(`
13
+ `)}return _e(t,p),o.map(u=>u.name)}function Kn(e){let t=Q(e,".env");return Z(t)?!1:(De(t,je(),{mode:384}),!0)}var Ot="[REDACTED]",X=class extends Error{path;constructor(t,n){super(`Could not read ${t}: ${n}`),this.path=t,this.name="EnvUnreadableError"}},Ct=8;function Dt(e,t=[]){let n=[...Pe(_t(e,".env")),...t.flatMap(r=>Pe(r))];return[...new Set(n)].sort((r,o)=>o.length-r.length)}function Pe(e){if(!At(e))return[];let t;try{t=Rt(e,"utf-8")}catch(n){throw new X(e,n instanceof Error?n.message:String(n))}return[...R(t).values()].filter(n=>n.length>=Ct)}function Me(e,t){let n=e;for(let r of t)n=n.split(r).join(Ot);return n}function Ie(e,t){return t.length===0?e:typeof e=="string"?Me(e,t):Array.isArray(e)?e.map(n=>Ie(n,t)):e!==null&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ie(r,t)])):e}function Be(e,t=[]){let n;try{n=Dt(e,t)}catch(r){return()=>{throw r}}return r=>Me(r,n)}import{readFileSync as Ft}from"node:fs";import{join as Nt}from"node:path";function or(){return Ue(T())}function Ue(e){if(e)try{let t=Ft(Nt(e,".tdk",ke),"utf-8"),n=JSON.parse(t);if(n?.project?.name)return n.project.name}catch{}return"tdk-project"}function ee(e,t){let n=Ue(t??T()),r=process.env.TDK_SERVICE_BASE_URL??`http://${n}.localhost${e?`:${e}`:""}`;try{let o=new URL(r.includes("://")?r:`http://${r}`),s=o.hostname,a=o.protocol==="https:"?"443":"80",i=o.port||(e?String(e):""),c=i===a?"":i;if(s==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(s))return{appBase:`${o.protocol}//${s}${c?`:${c}`:""}`,apiBase:`${o.protocol}//${s}${c?`:${c}`:""}`};let d=s.replace(/^(app|api)\./,"");return{appBase:`${o.protocol}//app.${d}${c?`:${c}`:""}`,apiBase:`${o.protocol}//api.${d}${c?`:${c}`:""}`}}catch{return{appBase:`http://app.${n}.localhost`,apiBase:`http://api.${n}.localhost`}}}function jt(e){return`${e.replace(/\/+$/,"")}/health`}function te(e){if(A(e.config?.appType)){let t=e.name.replace(/-api$/,"");return e.config?.apiPath??`/api/${t}`}return e.config?.basePath??`/${e.name}`}function sr(e,t){return Le(e,t,n=>jt(n))}function ar(e,t){return Le(e,t,n=>n)}function Le(e,t,n){let{appBase:r,apiBase:o}=ee(t);return e.filter(s=>s.config?.appType==="frontend"||A(s.config?.appType)).map(s=>{let a=A(s.config.appType)?o:r;return{name:s.name,appType:s.config.appType,url:`${a}${n(te(s))}`}})}async function Pt(e,t){try{let n=await fetch(e.url,{method:"GET",redirect:"manual",signal:AbortSignal.timeout(t)});return{...e,ok:n.ok,status:n.status}}catch(n){let r=n instanceof Error&&n.name==="TimeoutError"?`no response within ${t}ms`:n instanceof Error?n.message:String(n);return{...e,ok:!1,error:r}}}async function ir(e,t){return Promise.all(e.map(n=>Pt(n,t)))}var Ye=60,ze=1e3,qe=1e4,Ke=200,He=64*1024,Je=new Set([404,502,503,504]),Mt=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN","EHOSTUNREACH","ENETUNREACH"]),Bt=new Set(["GET","HEAD","OPTIONS"]);function E(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Ut(e,t){if(Bt.has(t))return!0;if(!E(e))return!1;let n=E(e.cause)?e.cause:void 0,r=e.code??n?.code;return typeof r=="string"&&Mt.has(r)}function re(e){if(!E(e))return['smoke: must be an object with "via" and "steps"'];let t=[];return e.via!=="proxy"&&t.push('smoke.via: only "proxy" is supported (the check must go through the public URL)'),e.timeoutSeconds!==void 0&&!(typeof e.timeoutSeconds=="number"&&e.timeoutSeconds>0)&&t.push("smoke.timeoutSeconds: must be a number greater than 0"),!Array.isArray(e.steps)||e.steps.length===0?(t.push("smoke.steps: needs at least one step"),t):(e.steps.forEach((n,r)=>{let o=`smoke.steps[${r}]`;if(!E(n)){t.push(`${o}: must be an object`);return}let s=n.path;(typeof s!="string"||!s.startsWith("/")||s.startsWith("//"))&&t.push(`${o}.path: must start with "/" and is appended to the public URL; a full URL or relative path would skip the proxy`),n.expect!==void 0&&!(typeof n.expect=="number"&&Number.isInteger(n.expect)&&n.expect>=100&&n.expect<=599)&&t.push(`${o}.expect: must be an HTTP status between 100 and 599`),n.bodyContains!==void 0&&typeof n.bodyContains!="string"&&t.push(`${o}.bodyContains: must be a string`),n.save!==void 0&&(E(n.save)&&Object.values(n.save).every(i=>typeof i=="string"&&i.startsWith("$."))||t.push(`${o}.save: must map names to paths such as "$.id"`))}),t)}function hr(e,t){let{appBase:n,apiBase:r}=ee(t),o=[];for(let s of e){let a=s.config;if(!a?.smoke)continue;let i=a.appType,c=A(i)||i===G;if(!c&&i!=="frontend"||a.exposeViaProxy===!1)continue;let d=c?r:n,p=a.healthCheckPath||(c&&i!==G?"/health":void 0);o.push({name:s.name,baseUrl:`${d}${te(s).replace(/\/+$/,"")}`,...p?.startsWith("/")?{readyPath:p}:{},smoke:a.smoke})}return o}var Lt=10;function gr(e,t={}){let n=t.timeoutSeconds??Lt;return e.flatMap(r=>{let o=r.smoke.steps.filter(a=>(a.method??"GET").toUpperCase()==="GET"&&a.body===void 0&&!a.path.includes("{{")).map(a=>({...a,bodyContains:void 0}));if(o.length===0)return[];let s=Math.min(r.smoke.timeoutSeconds??Ye,n);return[{name:r.name,baseUrl:r.baseUrl,smoke:{via:r.smoke.via,timeoutSeconds:s,steps:o}}]})}function Vt(e,t){let n=t.replace(/^\$\.?/,"").match(/[^.[\]]+/g)??[],r=e;for(let o of n){if(r==null||o==="__proto__"||o==="constructor"||o==="prototype"||!Object.hasOwn(r,o))return;let s=Object.getOwnPropertyDescriptor(r,o);if(!s||!("value"in s))return;r=s.value}return r}function Ze(e,t){return e.replace(/\{\{(\w+)\}\}/g,(n,r)=>t[r]??n)}function ne(e,t){return typeof e=="string"?Ze(e,t):Array.isArray(e)?e.map(n=>ne(n,t)):E(e)?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,ne(r,t)])):e}function M(e){let t=e.replace(/\s+/g," ").trim();return t.length>Ke?`${t.slice(0,Ke)}...`:t}function Qe(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"step"}function Wt(e,t){let n=Qe(t),r=(e.get(n)??0)+1;return e.set(n,r),r===1?n:`${n}-${r}`}function Gt(e,t,n,r,o){try{let s=_(e,Qe(n.service),t);It(s,{recursive:!0});let a=_(s,"latest.json"),i=_(s,"body.txt");return r===void 0?We(i,{force:!0}):Ge(i,r),Ge(a,`${JSON.stringify({...n,bodyPath:r===void 0?null:"body.txt"},null,2)}
14
+ `),o&&(Ve(a,_(s,"last-success.json")),r===void 0?We(_(s,"last-success-body.txt"),{force:!0}):Ve(i,_(s,"last-success-body.txt"))),a}catch{return}}function zt(e){let t=Buffer.from(e,"utf8");if(t.length<=He)return{body:e,truncated:!1,bytes:t.length};let n=t.subarray(0,He).toString("utf8").replace(/\uFFFD$/,"");return{body:n,truncated:!0,bytes:Buffer.byteLength(n,"utf8")}}async function qt(e,t={}){let n=t.fetch??((p,u)=>fetch(p,u)),r=t.now??Date.now,o=t.sleep??(p=>new Promise(u=>setTimeout(u,p))),s=(e.smoke.timeoutSeconds??Ye)*1e3,a=r()+s,i={},c=re(e.smoke);if(c.length>0)return{name:e.name,ok:!1,failure:`${e.name}: invalid smoke block: ${c.join("; ")}`};if(e.readyPath){let p=`${e.baseUrl}${e.readyPath}`;for(;;){try{let u=await n(p,{method:"GET",signal:AbortSignal.timeout(qe)});if(await u.text(),!Je.has(u.status)&&u.status<500)break}catch{}if(r()>=a)break;await o(ze)}}a=r()+s;let d=new Map;for(let[p,u]of e.smoke.steps.entries()){let h=u.name??`step ${p+1}`,l=(u.method??"GET").toUpperCase(),me=`${e.baseUrl}${Ze(u.path,i)}`,C=u.expect??200,he=u.body!==void 0,S,D="",x,L;for(;;){x=void 0,L=void 0,S=void 0;let g=!1;try{let m=await n(me,{method:l,headers:he?{"content-type":"application/json"}:void 0,body:he?JSON.stringify(ne(u.body,i)):void 0,signal:AbortSignal.timeout(qe)});S=m.status,D=await m.text()}catch(m){g=Ut(m,l),x=m instanceof Error?m.message:String(m);let v=E(m)?m.code??(E(m.cause)?m.cause.code:void 0):void 0;L=typeof v=="string"?v:void 0}if(!(x!==void 0&&g||S!==void 0&&S!==C&&Je.has(S))||r()>=a)break;await o(ze)}let ge=!1,V=g=>{if(!ge){if(!t.redact)return g;try{return t.redact(g)}catch($){ge=!0;let m=$ instanceof Error?$.message:String($);t.warn?.(`${e.name}: ${h}: the response text was neither shown nor stored: ${m}`);return}}},W=V(me),y=S===void 0?void 0:V(D),Se=x===void 0?void 0:V(x),ye=x===void 0?void 0:L??Se,F=`${e.name}: ${h}: ${l} ${W??"(url withheld)"}`,$e;if(t.recordDir){let g=y===void 0?void 0:zt(y),$=x===void 0&&S===C&&(u.bodyContains===void 0||D.includes(u.bodyContains));$e=Gt(t.recordDir,Wt(d,h),{service:e.name,step:h,method:l,...W===void 0?{}:{url:W},expectedStatus:C,status:S??null,...ye===void 0?{}:{error:ye},truncated:g?.truncated??!1,bodyBytes:g?.bytes??0},g?.body,$)}let N=g=>({name:e.name,ok:!1,failure:g,recordPath:$e});if(x!==void 0)return N(`${F} never answered (${Se??"the error was withheld"})`);if(S!==C)return N(`${F} returned ${S}, expected ${C}${y?`: ${M(y)}`:""}`);if(u.bodyContains!==void 0&&!D.includes(u.bodyContains))return N(`${F} returned ${S} but the body does not contain "${u.bodyContains}"${y?`: ${M(y)}`:""}`);if(u.save){let g;try{g=JSON.parse(D)}catch{return N(`${F} returned a body that is not JSON, cannot save${y?`: ${M(y)}`:""}`)}for(let[$,m]of Object.entries(u.save)){let v=Vt(g,m);if(v==null||typeof v=="object")return N(`${F} response has no ${m} to save as {{${$}}}${y?`: ${M(y)}`:""}`);i[$]=String(v)}}}return{name:e.name,ok:!0}}function Sr(e){return`Smoke check failed: ${e.failure}${e.recordPath?` (record: ${e.recordPath})`:""}`}function yr(e,t,n={}){return{redact:Be(e,n.envFiles??[]),...t?{warn:t}:{}}}async function $r(e,t={}){return Promise.all(e.map(n=>qt(n,t)))}var Xe=1,wr="https://flisk.sh/schema.service.json",Kt={dependencies:"deprecated, use dependsOn (still read for now)",envVars:"deprecated, use params (still read when params is absent)",jwtSecret:"ignored. A secret must not be committed: remove it and set JWT_SECRET in the project .env"},Ht=new Set(["$schema","agent","apiBasePath","apiPath","appName","appType","backendName","basePath","build","buildContext","databaseName","dependencies","dev","dependsOn","dockerfile","enabled","exposeViaProxy","featuresEnabled","framework","healthCheckPath","image","language","name","nats","params","playwright","port","replicas","restart","runtime","sablier","schemaVersion","secrets","smoke","stack","syncs","traefik","type"]),Jt=[{path:["healthCheckPath"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["traefik","host"],pattern:/^[A-Za-z0-9.-]+$/,expected:"a hostname such as shop.backend.myproject.local"},{path:["traefik","pathPrefix"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /api/v1/shop-management"},{path:["traefik","healthCheck"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["nats","queueGroup"],pattern:/^[A-Za-z0-9_.-]+$/,expected:"letters, digits, '_', '.' or '-'"},{path:["databaseName"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["stack"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["image"],pattern:/^[A-Za-z0-9._/:@-]+$/,expected:"an image reference such as ghcr.io/acme/app:1.0"}];function B(e,t){let n=[],r=new Set;for(let{path:o,pattern:s,expected:a}of Jt){let i=e;for(let d of o)i=i&&typeof i=="object"&&!Array.isArray(i)?i[d]:void 0;if(i==null||i==="")continue;let c=`${t}.${o.join(".")}`;(typeof i!="string"||!s.test(i))&&r.add(c),typeof i!="string"?n.push(`${c}: expected a string`):s.test(i)||n.push(`${c}: must be ${a} (no spaces, line breaks or YAML syntax)`)}for(let[o,s]of Yt(e,t))r.has(o)||n.push(`${o}: ${s}`);return n}function oe(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<32||n===127||n===133||n===8232||n===8233)return!0}return!1}function Yt(e,t){let n=[],r=Object.entries(e).filter(([o])=>o!=="smoke").map(([o,s])=>[s,`${t}.${o}`]);for(let o of Object.keys(e))oe(o)&&n.push([t,"a key contains a line break"]);for(;r.length>0;){let[o,s]=r.pop();if(typeof o=="string")oe(o)&&n.push([s,"must not contain line breaks or control characters"]);else if(Array.isArray(o))for(let[a,i]of o.entries())r.push([i,`${s}[${a}]`]);else if(o&&typeof o=="object")for(let[a,i]of Object.entries(o))oe(a)?n.push([s,"a key contains a line break"]):r.push([i,`${s}.${a}`])}return n.sort(([o],[s])=>o.localeCompare(s))}var Zt=["apiPath","basePath"];function se(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let t=e;return Zt.filter(n=>n in t&&typeof t[n]!="string")}function ae(e,t){if(!e||typeof e!="object"||Array.isArray(e))return{errors:[`${t}: expected a JSON object`],warnings:[]};let n=e,r=[];for(let i of["appName","appType","stack","schemaVersion"])i in n||r.push(`${t}.${i}: required field is missing`);for(let i of["appName","appType","stack"])i in n&&typeof n[i]!="string"&&r.push(`${t}.${i}: expected a string`);"schemaVersion"in n&&n.schemaVersion!==Xe&&r.push(`${t}.schemaVersion: unsupported version ${String(n.schemaVersion)} (supported: ${Xe})`);for(let i of se(n))r.push(`${t}.${i}: expected a string`);let o=n.dev,s=o&&typeof o=="object"&&!Array.isArray(o)?o.liveReload:void 0;if(s!==void 0&&typeof s!="boolean"&&r.push(`${t}.dev.liveReload: expected true or false`),r.push(...B(n,t)),"smoke"in n)for(let i of re(n.smoke))r.push(`${t}.${i}`);let a=Object.keys(n).flatMap(i=>{let c=Kt[i];return c?[`${t}.${i}: ${c}`]:Ht.has(i)?[]:[`${t}.${i}: unknown field is preserved`]});return s===!0&&n.language!=="go"&&a.push(`${t}.dev.liveReload: only applies to Go services (language "go"); it is ignored here`),{errors:r,warnings:a,manifest:n}}function vr(e,t){if(!et(e))return[];try{let n=JSON.parse(tt(e,"utf-8"));return!n||typeof n!="object"||Array.isArray(n)?[]:B(n,t)}catch{return[]}}function br(e,t){if(!et(e))return{errors:[`${t}: file is missing`],warnings:[]};try{let n=JSON.parse(tt(e,"utf-8"));return ae(n,t)}catch(n){let r=n instanceof Error?n.message:String(n);return{errors:[`${t}: invalid JSON (${r})`],warnings:[]}}}function nt(e){if(e.length===0||e.every(n=>n==="unknown"))return"unknown";let t=e.filter(n=>n==="ready").length/e.length;return t>.9?"healthy":t>.5?"degraded":"error"}var Qt=/^[a-z0-9-]+$/;function rt(e){return Qt.test(e)}var Xt="Use lowercase letters, numbers, and hyphens only";function ot(e,t){return`${e} "${t}" is not valid. ${Xt}, e.g. "${e==="Resource name"?"my-service":"my-stack"}".`}function en(e){return e.trim()?rt(e)?{valid:!0}:{valid:!1,error:ot("Resource name",e)}:{valid:!1,error:"Resource name is required"}}function tn(e){return e.trim()?rt(e)?{valid:!0}:{valid:!1,error:ot("Stack name",e)}:{valid:!1,error:"Stack name is required"}}function _r(e){let t=e==="resource"?en:tn;return n=>{let r=t(n);return r.valid?!0:r.error??"Invalid name"}}function Or(e){return ie(z,e)?{valid:!0}:{valid:!1,error:`Invalid service. Must be one of: ${z.join(", ")}`}}function Cr(e){return Number.isInteger(e)&&e>0&&e<=65535}function Dr(e){return!e.includes("\0")&&!/[<>:"|?*]/.test(e)}function Fr(e,t="_"){return e.replace(/[^a-zA-Z0-9-]/g,t).substring(0,100)}function ie(e,t){return e.includes(t)}var sn=xe;function de(e,t=5,n=0){let r=[];if(n>t)return r;let o=st.readdirSync(e,{withFileTypes:!0});for(let s of o){let a=w(e,s.name);if(s.isDirectory()){if(an(s.name))continue;r.push(...de(a,t,n+1))}else s.isFile()&&s.name===sn&&r.push(a)}return r}function zr(e){return de(e)}function an(e){return ie(ve,e)||e.startsWith(".")}function cn(e){if(!e||typeof e!="object")return!1;let t=e,n=typeof t.runtime=="string"||typeof t.appType=="string"||typeof t.type=="string";return typeof t.appName=="string"&&n}var P=new Set;function qr(){P.clear()}var k=class extends Error{reason;constructor(t){super(t),this.reason=t,this.name="InvalidServiceJsonError"}};function ue(e){return e instanceof Error?e.message:String(e)}function un(e){let t;try{t=st.readFileSync(e,"utf-8")}catch(c){throw new k(`could not read file: ${ue(c)}`)}let n;try{n=JSON.parse(t)}catch(c){throw new k(`invalid JSON: ${ue(c)}`)}if(!cn(n))throw new k("missing required fields (appName, runtime or appType)");let r=se(n);if(r.length>0)throw new k(r.map(c=>`${c}: expected a string`).join("; "));let o=B(n,e);if(o.length>0)throw new k(o.join("; "));let s=n;for(let c of ae(n,e).warnings)P.has(c)||(P.add(c),console.warn(`\u26A0\uFE0F ${c}`));let a={...s,appType:s.appType||s.type},i=on(e);return{name:a.appName,path:i,configPath:e,config:a,stack:a.stack,port:a.port,type:a.appType}}function at(e){let t=de(e),n=[],r=[];for(let o of t)try{n.push(un(o))}catch(s){r.push({path:o,reason:s instanceof k?s.reason:ue(s)})}return{resources:n,problems:r}}function fn(e){for(let t of e){let n=`skipped ${t.path}: ${t.reason}`;P.has(n)||(P.add(n),console.warn(`\u26A0\uFE0F ${n}`))}}function it(e){let{resources:t,problems:n}=at(e);return fn(n),t}function U(){let e=T();if(!e)throw q.notInProject();return it(e)}function Kr(e){let t=e;if(!t){let n=T();if(!n)throw q.notInProject();t=at(n)}if(t.problems.length>0)throw new Error(t.problems.map(n=>`Invalid service.json at ${n.path}: ${n.reason}`).join(`
15
+ `));return t.resources}function Hr(e,t){let n=t??it(e);return pn(n)}function pn(e){let t=e||U(),n=new Set;for(let r of t)r.stack&&n.add(r.stack);return Array.from(n).sort()}function Jr(e=U()){let t=new Map;for(let r of e)if(r.stack){let o=t.get(r.stack);o?o.push(r):t.set(r.stack,[r])}let n=[];for(let[r,o]of t)n.push({name:r,description:Re(o.length,"resource"),resources:o,resourceCount:o.length});return n.sort((r,o)=>r.name.localeCompare(o.name))}function Yr(e,t){return(t??U()).filter(r=>r.stack===e)}function Zr(e,t){return(t??U()).some(r=>r.stack===e)}var le=5e3,fe=new j({ttlMs:le}),pe=new j({ttlMs:le}),I=Te(le);function Qr(){fe.clear(),pe.clear(),I.reset()}function dn(e,t){if(e==="Dockerfile"||e.startsWith("docker-compose"))return"docker";if(e==="Tiltfile"||e.endsWith(".star"))return"tilt";if(e==="vite.config.ts"||e==="tsconfig.json"||e===we)return"config";if(e==="schema.prisma"||e.includes("migration"))return"prisma";if(t){let n=t.split(`
16
+ `).slice(0,10).join(`
17
+ `);if(n.includes("GENERATED BY Flisk")||n.includes("AUTOGENERATED"))return"generated"}return"unknown"}function ln(e){let t=e.configPath;if(I.isValid()){let l=fe.get(t);if(l)return l}let n=e.path,r=ce(e.configPath),o=r.mtime.toISOString(),s=r.mtime.toISOString(),a=mn(n),i=O(w(n,"Dockerfile")),c=O(w(n,"Tiltfile")),d=O(w(n,Ee))||O(w(n,"docker-compose.yaml")),p=e.config?.appType,u=p||"backend";p||(e.name.includes("frontend")?u="frontend":(e.name.includes("sdk")||e.name.includes("lib")||e.name.includes("infra"))&&(u="library"));let h={name:e.name,stack:e.stack,type:u,port:e.config?.port,createdAt:o,lastModified:s,dependencies:e.config?.dependsOn??[],hasDockerfile:i,hasTiltfile:c,hasDockerCompose:d,autogeneratedFiles:a,status:"unknown"};return fe.set(t,h),I.markUpdated(),h}function mn(e){let t=[];for(let r of be){let o=w(e,r);if(O(o)){let s=ce(o),a=rn(o,"utf-8");t.push({name:r,path:o,type:dn(r,a),size:s.size,lastModified:s.mtime.toISOString()})}}let n=w(e,"prisma");if(O(n)){let r=nn(n);for(let o of r)if(o==="schema.prisma"||o.includes("migration")){let s=w(n,o),a=ce(s);t.push({name:`prisma/${o}`,path:s,type:"prisma",size:a.size,lastModified:a.mtime.toISOString()})}}return t.sort((r,o)=>r.name.localeCompare(o.name))}function Xr(e){let t=e.name;if(I.isValid()){let c=pe.get(t);if(c)return c}let n=e.resources.map(c=>ln(c)),r=n.map(c=>new Date(c.createdAt).getTime()),o=Math.min(...r),s=Math.max(...r),a=nt(n.map(c=>c.status)),i={name:e.name,resourceCount:n.length,createdAt:new Date(o).toISOString(),lastModified:new Date(s).toISOString(),resources:n,overallStatus:a};return pe.set(t,i),I.markUpdated(),i}export{Re as a,Sn as b,yn as c,$n as d,xn as e,En as f,kn as g,wn as h,vn as i,bn as j,J as k,Tn as l,An as m,Rn as n,_n as o,On as p,Cn as q,Dn as r,Fn as s,A as t,_e as u,Gn as v,R as w,zn as x,qn as y,Kn as z,X as A,Dt as B,Me as C,Ie as D,or as E,ee as F,jt as G,te as H,sr as I,ar as J,ir as K,hr as L,gr as M,Sr as N,yr as O,$r as P,Xe as Q,wr as R,ae as S,vr as T,br as U,nt as V,en as W,tn as X,_r as Y,Or as Z,Cr as _,Dr as $,Fr as aa,ie as ba,zr as ca,qr as da,at as ea,fn as fa,it as ga,U as ha,Kr as ia,Hr as ja,pn as ka,Jr as la,Yr as ma,Zr as na,Qr as oa,ln as pa,Xr as qa};
@@ -0,0 +1,2 @@
1
+ import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
2
+ var e="Landscape startup needs Ubuntu on WSL2. Native Windows is inspect-only.";function i(n,t){return n!=="win32"||t==="1"?null:e}export{e as a,i as b};
@@ -1,5 +1,5 @@
1
1
  import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
2
- import{b as N}from"./chunk-YNJTA77W.js";import{G as O,O as m,Ta as f,c as $,d as C,fa as T,g as U,h as E,k as F,l as P,s as l,x as M}from"./chunk-CLQSJP6M.js";import{execFileSync as de,execSync as ue}from"node:child_process";import{existsSync as R,readdirSync as V,readFileSync as y}from"node:fs";import{basename as le,dirname as me,join as u,relative as k}from"node:path";function Oe(t){return I(t,!1)}function Ne(t){return I(t,!0)}function I(t,e){return`import { Hono } from 'hono';
2
+ import{b as N}from"./chunk-GANRXKBM.js";import{a as m,ga as f,t as T}from"./chunk-4W6OXDLK.js";import{C as M,L as O,e as $,f as C,i as U,j as E,m as F,n as P,x as l}from"./chunk-XSPMLWAE.js";import{execFileSync as de,execSync as ue}from"node:child_process";import{existsSync as R,readdirSync as V,readFileSync as y}from"node:fs";import{basename as le,dirname as me,join as u,relative as k}from"node:path";function Oe(t){return I(t,!1)}function Ne(t){return I(t,!0)}function I(t,e){return`import { Hono } from 'hono';
3
3
  ${e?`import { sql } from 'drizzle-orm';
4
4
  import { db } from './db.js';
5
5
  `:""}
@@ -1,2 +1,2 @@
1
1
  import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
2
- import{r as c}from"./chunk-4TMLNLYG.js";import{execFileSync as u}from"node:child_process";import{realpathSync as l}from"node:fs";import{resolve as p}from"node:path";var m=(o,t)=>u(o,t,{encoding:"utf-8",stdio:"pipe",timeout:5e3,windowsHide:!0});function a(o,t=process.platform,e=m){if(t==="win32")return null;try{let s=e("lsof",["-nP",`-iTCP:${o}`,"-sTCP:LISTEN","-t"]).split(/\r?\n/).map(r=>r.trim()).filter(Boolean);for(let r of s){let n=e("ps",["-p",r,"-o","command="]).trim(),[i]=c(`${r} ${n}`);if(i)return i}}catch{}return null}function f(o){try{return l(o)}catch{return p(o)}}function d(o,t){return o!==null&&f(o.root)!==f(t)}async function P(o,t,e,s=a){let r={running:[],foreign:[]};for(let n of o){if(!await e(n))continue;let i=s(n);i&&d(i,t)?r.foreign.push({port:n,root:i.root}):r.running.push(n)}return r}export{a,d as b,P as c};
2
+ import{r as c}from"./chunk-5CFVN3W3.js";import{execFileSync as u}from"node:child_process";import{realpathSync as l}from"node:fs";import{resolve as p}from"node:path";var m=(o,t)=>u(o,t,{encoding:"utf-8",stdio:"pipe",timeout:5e3,windowsHide:!0});function a(o,t=process.platform,e=m){if(t==="win32")return null;try{let s=e("lsof",["-nP",`-iTCP:${o}`,"-sTCP:LISTEN","-t"]).split(/\r?\n/).map(r=>r.trim()).filter(Boolean);for(let r of s){let n=e("ps",["-p",r,"-o","command="]).trim(),[i]=c(`${r} ${n}`);if(i)return i}}catch{}return null}function f(o){try{return l(o)}catch{return p(o)}}function d(o,t){return o!==null&&f(o.root)!==f(t)}async function P(o,t,e,s=a){let r={running:[],foreign:[]};for(let n of o){if(!await e(n))continue;let i=s(n);i&&d(i,t)?r.foreign.push({port:n,root:i.root}):r.running.push(n)}return r}export{a,d as b,P as c};