dx-devkit 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/LICENSE +21 -0
  3. package/README.md +475 -2
  4. package/bin/dx-mcp.js +2 -0
  5. package/dist/command.d.ts +9 -0
  6. package/dist/command.d.ts.map +1 -0
  7. package/dist/command.js +2 -0
  8. package/dist/command.js.map +1 -0
  9. package/dist/commands/ai.d.ts +7 -0
  10. package/dist/commands/ai.d.ts.map +1 -0
  11. package/dist/commands/ai.js +148 -0
  12. package/dist/commands/ai.js.map +1 -0
  13. package/dist/commands/clean.d.ts +3 -0
  14. package/dist/commands/clean.d.ts.map +1 -0
  15. package/dist/commands/clean.js +72 -0
  16. package/dist/commands/clean.js.map +1 -0
  17. package/dist/commands/deps.d.ts +3 -0
  18. package/dist/commands/deps.d.ts.map +1 -0
  19. package/dist/commands/deps.js +98 -0
  20. package/dist/commands/deps.js.map +1 -0
  21. package/dist/commands/go.d.ts +3 -0
  22. package/dist/commands/go.d.ts.map +1 -0
  23. package/dist/commands/go.js +202 -0
  24. package/dist/commands/go.js.map +1 -0
  25. package/dist/commands/log.d.ts +3 -0
  26. package/dist/commands/log.d.ts.map +1 -0
  27. package/dist/commands/log.js +51 -0
  28. package/dist/commands/log.js.map +1 -0
  29. package/dist/commands/new.d.ts +3 -0
  30. package/dist/commands/new.d.ts.map +1 -0
  31. package/dist/commands/new.js +117 -0
  32. package/dist/commands/new.js.map +1 -0
  33. package/dist/commands/port.d.ts +4 -0
  34. package/dist/commands/port.d.ts.map +1 -0
  35. package/dist/commands/port.js +106 -0
  36. package/dist/commands/port.js.map +1 -0
  37. package/dist/commands/projects.d.ts +5 -0
  38. package/dist/commands/projects.d.ts.map +1 -0
  39. package/dist/commands/projects.js +46 -0
  40. package/dist/commands/projects.js.map +1 -0
  41. package/dist/commands/stack.d.ts +34 -0
  42. package/dist/commands/stack.d.ts.map +1 -0
  43. package/dist/commands/stack.js +140 -0
  44. package/dist/commands/stack.js.map +1 -0
  45. package/dist/commands/summary.d.ts +3 -0
  46. package/dist/commands/summary.d.ts.map +1 -0
  47. package/dist/commands/summary.js +88 -0
  48. package/dist/commands/summary.js.map +1 -0
  49. package/dist/commands/system.d.ts +5 -0
  50. package/dist/commands/system.d.ts.map +1 -0
  51. package/dist/commands/system.js +104 -0
  52. package/dist/commands/system.js.map +1 -0
  53. package/dist/commands/ui.d.ts +3 -0
  54. package/dist/commands/ui.d.ts.map +1 -0
  55. package/dist/commands/ui.js +96 -0
  56. package/dist/commands/ui.js.map +1 -0
  57. package/dist/index.d.ts +3 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +103 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/ui.d.ts +27 -0
  62. package/dist/ui.d.ts.map +1 -0
  63. package/dist/ui.js +104 -0
  64. package/dist/ui.js.map +1 -0
  65. package/node_modules/@dx/core/dist/config.d.ts +46 -0
  66. package/node_modules/@dx/core/dist/config.d.ts.map +1 -0
  67. package/node_modules/@dx/core/dist/config.js +131 -0
  68. package/node_modules/@dx/core/dist/config.js.map +1 -0
  69. package/node_modules/@dx/core/dist/fuzzy.d.ts +15 -0
  70. package/node_modules/@dx/core/dist/fuzzy.d.ts.map +1 -0
  71. package/node_modules/@dx/core/dist/fuzzy.js +63 -0
  72. package/node_modules/@dx/core/dist/fuzzy.js.map +1 -0
  73. package/node_modules/@dx/core/dist/index.d.ts +17 -0
  74. package/node_modules/@dx/core/dist/index.d.ts.map +1 -0
  75. package/node_modules/@dx/core/dist/index.js +19 -0
  76. package/node_modules/@dx/core/dist/index.js.map +1 -0
  77. package/node_modules/@dx/core/dist/runs.d.ts +19 -0
  78. package/node_modules/@dx/core/dist/runs.d.ts.map +1 -0
  79. package/node_modules/@dx/core/dist/runs.js +41 -0
  80. package/node_modules/@dx/core/dist/runs.js.map +1 -0
  81. package/node_modules/@dx/core/dist/tools/aiSetup.d.ts +58 -0
  82. package/node_modules/@dx/core/dist/tools/aiSetup.d.ts.map +1 -0
  83. package/node_modules/@dx/core/dist/tools/aiSetup.js +243 -0
  84. package/node_modules/@dx/core/dist/tools/aiSetup.js.map +1 -0
  85. package/node_modules/@dx/core/dist/tools/cleanup.d.ts +61 -0
  86. package/node_modules/@dx/core/dist/tools/cleanup.d.ts.map +1 -0
  87. package/node_modules/@dx/core/dist/tools/cleanup.js +171 -0
  88. package/node_modules/@dx/core/dist/tools/cleanup.js.map +1 -0
  89. package/node_modules/@dx/core/dist/tools/deps.d.ts +57 -0
  90. package/node_modules/@dx/core/dist/tools/deps.d.ts.map +1 -0
  91. package/node_modules/@dx/core/dist/tools/deps.js +151 -0
  92. package/node_modules/@dx/core/dist/tools/deps.js.map +1 -0
  93. package/node_modules/@dx/core/dist/tools/devErrors.d.ts +74 -0
  94. package/node_modules/@dx/core/dist/tools/devErrors.d.ts.map +1 -0
  95. package/node_modules/@dx/core/dist/tools/devErrors.js +261 -0
  96. package/node_modules/@dx/core/dist/tools/devErrors.js.map +1 -0
  97. package/node_modules/@dx/core/dist/tools/doctor.d.ts +12 -0
  98. package/node_modules/@dx/core/dist/tools/doctor.d.ts.map +1 -0
  99. package/node_modules/@dx/core/dist/tools/doctor.js +176 -0
  100. package/node_modules/@dx/core/dist/tools/doctor.js.map +1 -0
  101. package/node_modules/@dx/core/dist/tools/github.d.ts +31 -0
  102. package/node_modules/@dx/core/dist/tools/github.d.ts.map +1 -0
  103. package/node_modules/@dx/core/dist/tools/github.js +80 -0
  104. package/node_modules/@dx/core/dist/tools/github.js.map +1 -0
  105. package/node_modules/@dx/core/dist/tools/journal.d.ts +23 -0
  106. package/node_modules/@dx/core/dist/tools/journal.d.ts.map +1 -0
  107. package/node_modules/@dx/core/dist/tools/journal.js +80 -0
  108. package/node_modules/@dx/core/dist/tools/journal.js.map +1 -0
  109. package/node_modules/@dx/core/dist/tools/launch.d.ts +24 -0
  110. package/node_modules/@dx/core/dist/tools/launch.d.ts.map +1 -0
  111. package/node_modules/@dx/core/dist/tools/launch.js +137 -0
  112. package/node_modules/@dx/core/dist/tools/launch.js.map +1 -0
  113. package/node_modules/@dx/core/dist/tools/ports.d.ts +42 -0
  114. package/node_modules/@dx/core/dist/tools/ports.d.ts.map +1 -0
  115. package/node_modules/@dx/core/dist/tools/ports.js +220 -0
  116. package/node_modules/@dx/core/dist/tools/ports.js.map +1 -0
  117. package/node_modules/@dx/core/dist/tools/projects.d.ts +58 -0
  118. package/node_modules/@dx/core/dist/tools/projects.d.ts.map +1 -0
  119. package/node_modules/@dx/core/dist/tools/projects.js +208 -0
  120. package/node_modules/@dx/core/dist/tools/projects.js.map +1 -0
  121. package/node_modules/@dx/core/dist/tools/scaffold.d.ts +40 -0
  122. package/node_modules/@dx/core/dist/tools/scaffold.d.ts.map +1 -0
  123. package/node_modules/@dx/core/dist/tools/scaffold.js +188 -0
  124. package/node_modules/@dx/core/dist/tools/scaffold.js.map +1 -0
  125. package/node_modules/@dx/core/dist/tools/stacks.d.ts +119 -0
  126. package/node_modules/@dx/core/dist/tools/stacks.d.ts.map +1 -0
  127. package/node_modules/@dx/core/dist/tools/stacks.js +386 -0
  128. package/node_modules/@dx/core/dist/tools/stacks.js.map +1 -0
  129. package/node_modules/@dx/core/dist/tools/summary.d.ts +87 -0
  130. package/node_modules/@dx/core/dist/tools/summary.d.ts.map +1 -0
  131. package/node_modules/@dx/core/dist/tools/summary.js +331 -0
  132. package/node_modules/@dx/core/dist/tools/summary.js.map +1 -0
  133. package/node_modules/@dx/core/package.json +20 -0
  134. package/node_modules/@dx/mcp/dist/index.d.ts +3 -0
  135. package/node_modules/@dx/mcp/dist/index.d.ts.map +1 -0
  136. package/node_modules/@dx/mcp/dist/index.js +540 -0
  137. package/node_modules/@dx/mcp/dist/index.js.map +1 -0
  138. package/node_modules/@dx/mcp/package.json +8 -0
  139. package/node_modules/@dx/web/dist/api.d.ts +13 -0
  140. package/node_modules/@dx/web/dist/api.d.ts.map +1 -0
  141. package/node_modules/@dx/web/dist/api.js +351 -0
  142. package/node_modules/@dx/web/dist/api.js.map +1 -0
  143. package/node_modules/@dx/web/dist/background.d.ts +2 -0
  144. package/node_modules/@dx/web/dist/background.d.ts.map +1 -0
  145. package/node_modules/@dx/web/dist/background.js +24 -0
  146. package/node_modules/@dx/web/dist/background.js.map +1 -0
  147. package/node_modules/@dx/web/dist/check.d.ts +39 -0
  148. package/node_modules/@dx/web/dist/check.d.ts.map +1 -0
  149. package/node_modules/@dx/web/dist/check.js +97 -0
  150. package/node_modules/@dx/web/dist/check.js.map +1 -0
  151. package/node_modules/@dx/web/dist/dev.d.ts +109 -0
  152. package/node_modules/@dx/web/dist/dev.d.ts.map +1 -0
  153. package/node_modules/@dx/web/dist/dev.js +645 -0
  154. package/node_modules/@dx/web/dist/dev.js.map +1 -0
  155. package/node_modules/@dx/web/dist/link.d.ts +45 -0
  156. package/node_modules/@dx/web/dist/link.d.ts.map +1 -0
  157. package/node_modules/@dx/web/dist/link.js +150 -0
  158. package/node_modules/@dx/web/dist/link.js.map +1 -0
  159. package/node_modules/@dx/web/dist/proxy.d.ts +21 -0
  160. package/node_modules/@dx/web/dist/proxy.d.ts.map +1 -0
  161. package/node_modules/@dx/web/dist/proxy.js +140 -0
  162. package/node_modules/@dx/web/dist/proxy.js.map +1 -0
  163. package/node_modules/@dx/web/dist/server.d.ts +33 -0
  164. package/node_modules/@dx/web/dist/server.d.ts.map +1 -0
  165. package/node_modules/@dx/web/dist/server.js +184 -0
  166. package/node_modules/@dx/web/dist/server.js.map +1 -0
  167. package/node_modules/@dx/web/package.json +26 -0
  168. package/node_modules/@dx/web/public/app.js +1553 -0
  169. package/node_modules/@dx/web/public/icon.svg +1 -0
  170. package/node_modules/@dx/web/public/index.html +47 -0
  171. package/node_modules/@dx/web/public/styles.css +1124 -0
  172. package/package.json +52 -4
@@ -0,0 +1,88 @@
1
+ import { spawn } from "node:child_process";
2
+ import { parseArgs } from "node:util";
3
+ import { buildSummary, formatSummary, loadConfig, openInEditor, recordRun, saveSummary } from "@dx/core";
4
+ import { c, ok, tildify, UsageError, warn } from "../ui.js";
5
+ export const summaryCommand = {
6
+ name: "summary",
7
+ aliases: ["week"],
8
+ summary: "Your commits across all projects plus your journal, as a ready-to-send update",
9
+ usage: [
10
+ "dx summary the last 7 days, printed as markdown",
11
+ "dx summary --days 1 just today (handy for a standup)",
12
+ "dx summary --copy also copy it to the clipboard",
13
+ "dx summary --save also save it to ~/.dx/summaries/<date>.md",
14
+ "dx summary --save --open save it and open the file in your editor",
15
+ "dx summary --all-authors count everyone's commits, not only yours",
16
+ "dx summary --no-github skip pull requests from GitHub (works offline)",
17
+ "dx summary --json the raw data",
18
+ ].join("\n"),
19
+ async run(argv) {
20
+ const { values } = parseArgs({
21
+ args: argv,
22
+ allowNegative: true,
23
+ options: {
24
+ days: { type: "string", short: "d" },
25
+ copy: { type: "boolean", short: "c" },
26
+ save: { type: "boolean", short: "s" },
27
+ open: { type: "boolean", short: "o" },
28
+ "all-authors": { type: "boolean", short: "a" },
29
+ json: { type: "boolean" },
30
+ github: { type: "boolean", default: true },
31
+ },
32
+ });
33
+ const days = values.days === undefined ? 7 : Number(values.days);
34
+ if (!Number.isInteger(days) || days < 1 || days > 366)
35
+ throw new UsageError("--days must be a whole number from 1 to 366.");
36
+ const config = loadConfig();
37
+ const summary = await buildSummary({ days, config, allAuthors: values["all-authors"], github: values.github });
38
+ if (values.json) {
39
+ console.log(JSON.stringify(summary, null, 2));
40
+ return;
41
+ }
42
+ const markdown = formatSummary(summary);
43
+ console.log(markdown);
44
+ for (const s of summary.skipped)
45
+ warn(`Skipped ${s.project}: ${s.reason}`);
46
+ if (summary.github && "error" in summary.github)
47
+ warn(`No pull requests: ${summary.github.error}`);
48
+ if (!summary.projects.length && !summary.journal.length) {
49
+ console.log(c.dim('Log what you do with: dx log "what you did"'));
50
+ }
51
+ else {
52
+ console.log(c.dim(`Commits by ${summary.author}. Everyone's: dx summary --all-authors`));
53
+ }
54
+ if (values.copy) {
55
+ try {
56
+ await copyToClipboard(markdown);
57
+ ok("Copied to the clipboard");
58
+ }
59
+ catch (err) {
60
+ warn(`Couldn't copy to the clipboard: ${err.message}`);
61
+ }
62
+ }
63
+ if (values.save || values.open) {
64
+ const file = saveSummary(markdown, summary);
65
+ ok(`Saved ${tildify(file)}`);
66
+ if (values.open)
67
+ await openInEditor(file, config.editor);
68
+ }
69
+ const commits = summary.projects.reduce((n, p) => n + p.commits.length, 0);
70
+ recordRun("summary", true, `${days}d: ${commits} commit(s), ${summary.journal.length} journal entr${summary.journal.length === 1 ? "y" : "ies"}`);
71
+ },
72
+ };
73
+ /** Copies text to the system clipboard, keeping accents and symbols intact. */
74
+ function copyToClipboard(text) {
75
+ // clip.exe garbles non-ASCII text sent as UTF-8; UTF-16 works. No byte order mark: clip.exe would paste it.
76
+ const [command, args, input] = process.platform === "win32"
77
+ ? ["clip.exe", [], Buffer.from(text, "utf16le")]
78
+ : process.platform === "darwin"
79
+ ? ["pbcopy", [], Buffer.from(text, "utf8")]
80
+ : ["sh", ["-c", "wl-copy 2>/dev/null || xclip -selection clipboard"], Buffer.from(text, "utf8")];
81
+ return new Promise((resolve, reject) => {
82
+ const child = spawn(command, args, { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
83
+ child.once("error", reject);
84
+ child.once("close", (code) => (code === 0 ? resolve() : reject(new Error(`${command} exited with ${code}`))));
85
+ child.stdin.end(input);
86
+ });
87
+ }
88
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/commands/summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Command } from "../command.js";
2
+ export declare const configCommand: Command;
3
+ export declare const doctorCommand: Command;
4
+ export declare const runsCommand: Command;
5
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/commands/system.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,eAAO,MAAM,aAAa,EAAE,OAmD3B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,OAc3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,OA2BzB,CAAC"}
@@ -0,0 +1,104 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { parseArgs } from "node:util";
4
+ import { configPath, loadConfig, openInEditor, readRuns, runDoctor, saveConfig } from "@dx/core";
5
+ import { c, ok, table, tildify, UsageError } from "../ui.js";
6
+ export const configCommand = {
7
+ name: "config",
8
+ summary: "Show or change dx settings",
9
+ usage: [
10
+ "dx config show the settings file",
11
+ "dx config edit open it in your editor",
12
+ "dx config add-root <path> scan another folder for projects",
13
+ "dx config editor <command> set the editor command, e.g. cursor",
14
+ "dx config github <username> your GitHub username, for pull requests in dx summary",
15
+ ].join("\n"),
16
+ async run(argv) {
17
+ const [action, ...rest] = argv;
18
+ const config = loadConfig();
19
+ if (!action) {
20
+ console.log(c.dim(configPath()));
21
+ console.log(JSON.stringify(config, null, 2));
22
+ return;
23
+ }
24
+ if (action === "edit") {
25
+ await openInEditor(configPath(), config.editor);
26
+ ok(`Opened ${tildify(configPath())}`);
27
+ return;
28
+ }
29
+ if (action === "add-root") {
30
+ const target = rest.join(" ").trim();
31
+ if (!target)
32
+ throw new UsageError("Which folder? e.g. dx config add-root C:\\code");
33
+ const abs = path.resolve(target);
34
+ if (!fs.existsSync(abs))
35
+ throw new UsageError(`Folder not found: ${abs}`);
36
+ if (!config.projectsRoots.some((r) => r.toLowerCase() === abs.toLowerCase()))
37
+ config.projectsRoots.push(abs);
38
+ saveConfig(config);
39
+ ok(`Projects roots: ${config.projectsRoots.map(tildify).join(", ")}`);
40
+ return;
41
+ }
42
+ if (action === "editor") {
43
+ const editor = rest.join(" ").trim();
44
+ if (!editor)
45
+ throw new UsageError("Which command? e.g. dx config editor cursor");
46
+ config.editor = editor;
47
+ saveConfig(config);
48
+ ok(`Editor set to ${editor}`);
49
+ return;
50
+ }
51
+ if (action === "github") {
52
+ const user = rest.join(" ").trim().replace(/^@/, "");
53
+ if (!/^[A-Za-z0-9-]{1,39}$/.test(user))
54
+ throw new UsageError("Which GitHub username? e.g. dx config github octocat");
55
+ config.githubUser = user;
56
+ saveConfig(config);
57
+ ok(`GitHub username set to ${user}`);
58
+ return;
59
+ }
60
+ throw new UsageError(`Unknown config action: ${action}`);
61
+ },
62
+ };
63
+ export const doctorCommand = {
64
+ name: "doctor",
65
+ summary: "Check that dx works on this machine",
66
+ usage: "dx doctor",
67
+ async run() {
68
+ const checks = await runDoctor();
69
+ const icon = { ok: c.green("✓"), warn: c.yellow("!"), fail: c.red("✗") };
70
+ for (const check of checks) {
71
+ console.log(`${icon[check.status]} ${c.bold(check.name.padEnd(17))} ${check.detail}`);
72
+ if (check.fix)
73
+ console.log(` ${" ".repeat(17)} ${c.dim("fix:")} ${c.cyan(check.fix)}`);
74
+ }
75
+ if (checks.some((x) => x.fix))
76
+ console.log(c.dim("\nYour AI tool can apply these fixes: ask it to check dx's setup."));
77
+ return checks.some((x) => x.status === "fail") ? 1 : 0;
78
+ },
79
+ };
80
+ export const runsCommand = {
81
+ name: "runs",
82
+ summary: "Recent tool runs, so failures are never silent",
83
+ usage: "dx runs [--limit 30] [--failed]",
84
+ async run(argv) {
85
+ const { values } = parseArgs({
86
+ args: argv,
87
+ options: { limit: { type: "string", short: "n" }, failed: { type: "boolean", short: "f" } },
88
+ });
89
+ let runs = readRuns(Math.max(1, Number(values.limit) || 30));
90
+ if (values.failed)
91
+ runs = runs.filter((r) => !r.ok);
92
+ if (runs.length === 0) {
93
+ console.log(values.failed ? "No failed runs." : "No runs recorded yet.");
94
+ return;
95
+ }
96
+ console.log(table(["WHEN", "TOOL", "FROM", "RESULT"], runs.map((r) => [
97
+ new Date(r.at).toLocaleString(),
98
+ r.tool,
99
+ c.dim(r.source ?? ""),
100
+ r.ok ? c.green("ok") + (r.detail ? c.dim(` ${r.detail}`) : "") : c.red("failed") + ` ${r.detail ?? ""}`,
101
+ ])));
102
+ },
103
+ };
104
+ //# sourceMappingURL=system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/commands/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEjG,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,4BAA4B;IACrC,KAAK,EAAE;QACL,oDAAoD;QACpD,oDAAoD;QACpD,8DAA8D;QAC9D,iEAAiE;QACjE,mFAAmF;KACpF,CAAC,IAAI,CAAC,IAAI,CAAC;IACZ,KAAK,CAAC,GAAG,CAAC,IAAI;QACZ,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAC/B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,YAAY,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,EAAE,CAAC,UAAU,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QACD,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,UAAU,CAAC,gDAAgD,CAAC,CAAC;YACpF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;gBAAE,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC7G,UAAU,CAAC,MAAM,CAAC,CAAC;YACnB,EAAE,CAAC,mBAAmB,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QACD,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,UAAU,CAAC,6CAA6C,CAAC,CAAC;YACjF,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,UAAU,CAAC,MAAM,CAAC,CAAC;YACnB,EAAE,CAAC,iBAAiB,MAAM,EAAE,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QACD,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACrD,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,MAAM,IAAI,UAAU,CAAC,sDAAsD,CAAC,CAAC;YACrH,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;YACzB,UAAU,CAAC,MAAM,CAAC,CAAC;YACnB,EAAE,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QACD,MAAM,IAAI,UAAU,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAC;IAC3D,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,qCAAqC;IAC9C,KAAK,EAAE,WAAW;IAClB,KAAK,CAAC,GAAG;QACP,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAW,CAAC;QAClF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YACtF,IAAI,KAAK,CAAC,GAAG;gBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC,CAAC;QACvH,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,gDAAgD;IACzD,KAAK,EAAE,iCAAiC;IACxC,KAAK,CAAC,GAAG,CAAC,IAAI;QACZ,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;YAC3B,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;SAC5F,CAAC,CAAC;QACH,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7D,IAAI,MAAM,CAAC,MAAM;YAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CACT,KAAK,CACH,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAClC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,EAAE;YAC/B,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;YACrB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE;SAC1G,CAAC,CACH,CACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "../command.js";
2
+ export declare const uiCommand: Command;
3
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/commands/ui.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,eAAO,MAAM,SAAS,EAAE,OAgFvB,CAAC"}
@@ -0,0 +1,96 @@
1
+ import { parseArgs } from "node:util";
2
+ import { autoConnectAiTools, openUrl, recordRun } from "@dx/core";
3
+ import { startDashboard } from "@dx/web";
4
+ import { ensureDashboard, findDashboard } from "@dx/web/link";
5
+ import { c, info, ok, UsageError, warn } from "../ui.js";
6
+ export const uiCommand = {
7
+ name: "ui",
8
+ aliases: ["dashboard"],
9
+ summary: "Open the dx dashboard in your browser: every dx tool, with buttons",
10
+ usage: [
11
+ "dx ui open the dashboard (starting it here if it isn't running)",
12
+ "dx ui --background start it without a terminal; it stops itself when idle for 30 minutes",
13
+ "dx ui --stop stop the running dashboard and the dev servers it runs",
14
+ "dx ui --port 5000 use another port (default 4646)",
15
+ "dx ui --no-open don't open the browser",
16
+ "",
17
+ "It runs on this computer only (127.0.0.1). AI tools connected to dx start it in the background",
18
+ "when they need a dev server, and `dx ui` then just opens that one.",
19
+ ].join("\n"),
20
+ async run(argv) {
21
+ const { values } = parseArgs({
22
+ args: argv,
23
+ allowNegative: true,
24
+ options: {
25
+ port: { type: "string", short: "p" },
26
+ open: { type: "boolean", default: true },
27
+ background: { type: "boolean" },
28
+ stop: { type: "boolean" },
29
+ },
30
+ });
31
+ const port = values.port === undefined ? undefined : Number(values.port);
32
+ if (port !== undefined && (!Number.isInteger(port) || port < 0 || port > 65535))
33
+ throw new UsageError("--port must be a port number.");
34
+ const running = await findDashboard();
35
+ if (values.stop) {
36
+ if (!running) {
37
+ info("The dashboard isn't running.");
38
+ return;
39
+ }
40
+ await running.post("/api/shutdown");
41
+ ok("Dashboard stopped");
42
+ return;
43
+ }
44
+ if (running) {
45
+ ok(`The dx dashboard is already running at ${c.cyan(running.url)}${running.info.background ? c.dim(" (in the background)") : ""}`);
46
+ if (values.open)
47
+ await openBrowser(running.url);
48
+ return;
49
+ }
50
+ if (values.background) {
51
+ const client = await ensureDashboard();
52
+ ok(`dx dashboard running in the background at ${c.cyan(client.url)}`);
53
+ info(c.dim("It stops itself after 30 minutes with no dev servers and nobody using it. dx ui --stop stops it now."));
54
+ if (values.open)
55
+ await openBrowser(client.url);
56
+ return;
57
+ }
58
+ const dashboard = await startDashboard({ port });
59
+ ok(`dx dashboard running at ${c.cyan(dashboard.url)}`);
60
+ info(c.dim("Ctrl+C to stop. Dev servers started from the dashboard stop with it."));
61
+ recordRun("ui", true, dashboard.url);
62
+ void autoConnectAiTools()
63
+ .then((results) => {
64
+ const done = results.filter((r) => r.ok);
65
+ if (done.length)
66
+ info(c.dim(`Connected dx to ${done.map((r) => r.name).join(", ")}.`));
67
+ })
68
+ .catch(() => undefined);
69
+ if (values.open)
70
+ await openBrowser(dashboard.url);
71
+ await new Promise((resolve) => {
72
+ let stopping = false;
73
+ const stop = () => {
74
+ if (stopping)
75
+ return;
76
+ stopping = true;
77
+ console.log("");
78
+ info("Stopping the dashboard…");
79
+ void dashboard.close().then(resolve, resolve);
80
+ };
81
+ process.on("SIGINT", stop);
82
+ process.on("SIGTERM", stop);
83
+ void dashboard.closed.then(resolve);
84
+ });
85
+ ok("Dashboard stopped");
86
+ },
87
+ };
88
+ async function openBrowser(url) {
89
+ try {
90
+ await openUrl(url);
91
+ }
92
+ catch (err) {
93
+ warn(`Couldn't open the browser: ${err.message}. Open ${url} yourself.`);
94
+ }
95
+ }
96
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/commands/ui.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import { recordRun } from "@dx/core";
4
+ import { errorsCommand, firstRunSetup, logsCommand, setupCommand } from "./commands/ai.js";
5
+ import { cleanCommand } from "./commands/clean.js";
6
+ import { depsCommand } from "./commands/deps.js";
7
+ import { goCommand } from "./commands/go.js";
8
+ import { logCommand } from "./commands/log.js";
9
+ import { newCommand } from "./commands/new.js";
10
+ import { killCommand, portCommand } from "./commands/port.js";
11
+ import { projectsCommand } from "./commands/projects.js";
12
+ import { downCommand, upCommand } from "./commands/stack.js";
13
+ import { summaryCommand } from "./commands/summary.js";
14
+ import { configCommand, doctorCommand, runsCommand } from "./commands/system.js";
15
+ import { uiCommand } from "./commands/ui.js";
16
+ import { c, UsageError } from "./ui.js";
17
+ // To add a tool: write packages/cli/src/commands/<tool>.ts and add it to this list.
18
+ const commands = [
19
+ uiCommand,
20
+ goCommand,
21
+ upCommand,
22
+ downCommand,
23
+ newCommand,
24
+ projectsCommand,
25
+ portCommand,
26
+ killCommand,
27
+ logCommand,
28
+ summaryCommand,
29
+ cleanCommand,
30
+ depsCommand,
31
+ logsCommand,
32
+ errorsCommand,
33
+ setupCommand,
34
+ configCommand,
35
+ runsCommand,
36
+ doctorCommand,
37
+ ];
38
+ function version() {
39
+ try {
40
+ const pkg = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
41
+ return pkg.version;
42
+ }
43
+ catch {
44
+ return "unknown";
45
+ }
46
+ }
47
+ function help() {
48
+ console.log(`${c.bold("dx")} ${c.dim(version())} your developer toolkit\n`);
49
+ const width = Math.max(...commands.map((cmd) => cmd.name.length));
50
+ for (const cmd of commands)
51
+ console.log(` ${c.cyan(cmd.name.padEnd(width))} ${cmd.summary}`);
52
+ console.log(`\n${c.dim("Details for one command: dx help <command>")}`);
53
+ }
54
+ function find(name) {
55
+ return commands.find((cmd) => cmd.name === name || cmd.aliases?.includes(name));
56
+ }
57
+ async function main(argv) {
58
+ const [name, ...rest] = argv;
59
+ if (!name || name === "help" || name === "--help" || name === "-h") {
60
+ const target = rest[0] && find(rest[0]);
61
+ if (target) {
62
+ console.log(`${c.bold(target.summary)}\n\n${target.usage}`);
63
+ return 0;
64
+ }
65
+ help();
66
+ return 0;
67
+ }
68
+ if (name === "--version" || name === "-v") {
69
+ console.log(version());
70
+ return 0;
71
+ }
72
+ const command = find(name);
73
+ if (!command) {
74
+ console.error(`${c.red("Unknown command:")} ${name}\n`);
75
+ help();
76
+ return 1;
77
+ }
78
+ if (rest.includes("--help") || rest.includes("-h")) {
79
+ console.log(`${c.bold(command.summary)}\n\n${command.usage}`);
80
+ return 0;
81
+ }
82
+ try {
83
+ if (command !== setupCommand)
84
+ await firstRunSetup();
85
+ return (await command.run(rest)) ?? 0;
86
+ }
87
+ catch (err) {
88
+ const e = err;
89
+ if (err instanceof UsageError || e.code?.startsWith("ERR_PARSE_ARGS")) {
90
+ console.error(`${c.red("✗")} ${e.message}\n\n${c.dim("Usage:")}\n${command.usage}`);
91
+ return 2;
92
+ }
93
+ recordRun(command.name, false, e.message);
94
+ console.error(`${c.red("✗")} ${e.message}`);
95
+ if (process.env.DX_DEBUG)
96
+ console.error(e.stack);
97
+ return 1;
98
+ }
99
+ }
100
+ main(process.argv.slice(2)).then((code) => {
101
+ process.exitCode = code;
102
+ });
103
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/ui.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ export declare const c: {
2
+ bold: (s: string) => string;
3
+ dim: (s: string) => string;
4
+ red: (s: string) => string;
5
+ green: (s: string) => string;
6
+ yellow: (s: string) => string;
7
+ blue: (s: string) => string;
8
+ magenta: (s: string) => string;
9
+ cyan: (s: string) => string;
10
+ };
11
+ export declare class UsageError extends Error {
12
+ }
13
+ /** Left-aligned columns. The last column is cut to fit the terminal width. */
14
+ export declare function table(header: string[], rows: string[][]): string;
15
+ export declare function truncate(s: string, max: number): string;
16
+ /** "C:\Users\you\projects\todo-app" → "~\projects\todo-app" */
17
+ export declare function tildify(p: string): string;
18
+ export declare function relativeTime(ms: number, now?: number): string;
19
+ export declare function ask(question: string): Promise<string>;
20
+ /** Yes/no question. Without a terminal to ask in, the answer is no. */
21
+ export declare function confirm(question: string): Promise<boolean>;
22
+ /** Numbered pick list. Returns undefined if the user enters nothing or there is no terminal. */
23
+ export declare function pick<T>(items: T[], label: (item: T) => string, prompt?: string): Promise<T | undefined>;
24
+ export declare function ok(msg: string): void;
25
+ export declare function warn(msg: string): void;
26
+ export declare function info(msg: string): void;
27
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,CAAC;cAFoC,MAAM;aAAN,MAAM;aAAN,MAAM;eAAN,MAAM;gBAAN,MAAM;cAAN,MAAM;iBAAN,MAAM;cAAN,MAAM;CAWvD,CAAC;AAEF,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAKxC,8EAA8E;AAC9E,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAiBhE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED,+DAA+D;AAC/D,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGzC;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,MAAM,CAajE;AAED,wBAAsB,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO3D;AAED,uEAAuE;AACvE,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAIhE;AAED,gGAAgG;AAChG,wBAAsB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAAE,MAAM,SAAa,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAOjH;AAED,wBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtC"}
package/dist/ui.js ADDED
@@ -0,0 +1,104 @@
1
+ import os from "node:os";
2
+ import { createInterface } from "node:readline/promises";
3
+ const color = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
4
+ const wrap = (open, close) => (s) => (color ? `\x1b[${open}m${s}\x1b[${close}m` : s);
5
+ export const c = {
6
+ bold: wrap(1, 22),
7
+ dim: wrap(2, 22),
8
+ red: wrap(31, 39),
9
+ green: wrap(32, 39),
10
+ yellow: wrap(33, 39),
11
+ blue: wrap(34, 39),
12
+ magenta: wrap(35, 39),
13
+ cyan: wrap(36, 39),
14
+ };
15
+ export class UsageError extends Error {
16
+ }
17
+ const ANSI = /\x1b\[[0-9;]*m/g;
18
+ const visible = (s) => s.replace(ANSI, "").length;
19
+ /** Left-aligned columns. The last column is cut to fit the terminal width. */
20
+ export function table(header, rows) {
21
+ const all = [header.map((h) => c.dim(h)), ...rows];
22
+ const widths = header.map((_, i) => Math.max(...all.map((r) => visible(r[i] ?? ""))));
23
+ const termWidth = process.stdout.columns ?? 120;
24
+ const fixed = widths.slice(0, -1).reduce((a, w) => a + w + 2, 0);
25
+ const lastMax = Math.max(20, termWidth - fixed - 1);
26
+ return all
27
+ .map((r) => r
28
+ .map((cell, i) => {
29
+ const isLast = i === r.length - 1;
30
+ if (isLast)
31
+ return truncate(cell ?? "", lastMax);
32
+ return (cell ?? "") + " ".repeat(widths[i] - visible(cell ?? "") + 2);
33
+ })
34
+ .join(""))
35
+ .join("\n");
36
+ }
37
+ export function truncate(s, max) {
38
+ if (visible(s) <= max)
39
+ return s;
40
+ const plain = s.replace(ANSI, "");
41
+ return plain.slice(0, Math.max(0, max - 1)) + "…";
42
+ }
43
+ /** "C:\Users\you\projects\todo-app" → "~\projects\todo-app" */
44
+ export function tildify(p) {
45
+ const home = os.homedir();
46
+ return p.toLowerCase().startsWith(home.toLowerCase()) ? "~" + p.slice(home.length) : p;
47
+ }
48
+ export function relativeTime(ms, now = Date.now()) {
49
+ if (!ms)
50
+ return "—";
51
+ const s = Math.round((now - ms) / 1000);
52
+ if (s < 60)
53
+ return "just now";
54
+ const m = Math.round(s / 60);
55
+ if (m < 60)
56
+ return `${m}m ago`;
57
+ const h = Math.round(m / 60);
58
+ if (h < 24)
59
+ return `${h}h ago`;
60
+ const d = Math.round(h / 24);
61
+ if (d < 30)
62
+ return `${d}d ago`;
63
+ const mo = Math.round(d / 30);
64
+ if (mo < 12)
65
+ return `${mo}mo ago`;
66
+ return `${Math.round(mo / 12)}y ago`;
67
+ }
68
+ export async function ask(question) {
69
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
70
+ try {
71
+ return (await rl.question(question)).trim();
72
+ }
73
+ finally {
74
+ rl.close();
75
+ }
76
+ }
77
+ /** Yes/no question. Without a terminal to ask in, the answer is no. */
78
+ export async function confirm(question) {
79
+ if (!process.stdin.isTTY)
80
+ return false;
81
+ const answer = await ask(`${question} ${c.dim("[y/N]")} `);
82
+ return /^y(es)?$/i.test(answer);
83
+ }
84
+ /** Numbered pick list. Returns undefined if the user enters nothing or there is no terminal. */
85
+ export async function pick(items, label, prompt = "Pick one") {
86
+ if (items.length === 0)
87
+ return undefined;
88
+ items.forEach((item, i) => console.log(` ${c.cyan(String(i + 1).padStart(2))} ${label(item)}`));
89
+ if (!process.stdin.isTTY)
90
+ return undefined;
91
+ const answer = await ask(`${prompt} ${c.dim(`(1-${items.length}, Enter to cancel)`)}: `);
92
+ const n = Number(answer);
93
+ return Number.isInteger(n) && n >= 1 && n <= items.length ? items[n - 1] : undefined;
94
+ }
95
+ export function ok(msg) {
96
+ console.log(`${c.green("✓")} ${msg}`);
97
+ }
98
+ export function warn(msg) {
99
+ console.log(`${c.yellow("!")} ${msg}`);
100
+ }
101
+ export function info(msg) {
102
+ console.log(`${c.dim("·")} ${msg}`);
103
+ }
104
+ //# sourceMappingURL=ui.js.map
package/dist/ui.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}