@speedkit/cli 4.17.1 → 4.19.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 (47) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +75 -1
  3. package/dist/commands/browser/clean.d.ts +9 -0
  4. package/dist/commands/browser/clean.js +43 -0
  5. package/dist/commands/browser/list.d.ts +6 -0
  6. package/dist/commands/browser/list.js +29 -0
  7. package/dist/commands/browser/update.d.ts +6 -0
  8. package/dist/commands/browser/update.js +32 -0
  9. package/dist/commands/config/setup.d.ts +10 -0
  10. package/dist/commands/config/setup.js +28 -0
  11. package/dist/helpers/cli-config.d.ts +19 -0
  12. package/dist/helpers/cli-config.js +70 -4
  13. package/dist/helpers/cli-config.spec.d.ts +1 -0
  14. package/dist/helpers/cli-config.spec.js +70 -0
  15. package/dist/helpers/environment.d.ts +15 -0
  16. package/dist/helpers/environment.js +40 -0
  17. package/dist/helpers/environment.spec.d.ts +1 -0
  18. package/dist/helpers/environment.spec.js +28 -0
  19. package/dist/hooks/init/first-run.d.ts +8 -0
  20. package/dist/hooks/init/first-run.js +36 -0
  21. package/dist/services/customer-config/templates/config_SpeedKit.js.hbs +11 -0
  22. package/dist/services/setup/browser/browser-detector.d.ts +27 -0
  23. package/dist/services/setup/browser/browser-detector.js +47 -0
  24. package/dist/services/setup/browser/browser-manager.d.ts +43 -0
  25. package/dist/services/setup/browser/browser-manager.js +101 -0
  26. package/dist/services/setup/browser/browser-setup-service.d.ts +28 -0
  27. package/dist/services/setup/browser/browser-setup-service.js +136 -0
  28. package/dist/services/setup/difftool/difftool-detector.d.ts +14 -0
  29. package/dist/services/setup/difftool/difftool-detector.js +27 -0
  30. package/dist/services/setup/difftool/difftool-setup-service.d.ts +15 -0
  31. package/dist/services/setup/difftool/difftool-setup-service.js +46 -0
  32. package/dist/services/setup/index.d.ts +10 -0
  33. package/dist/services/setup/index.js +10 -0
  34. package/dist/services/setup/os/detector-helper.d.ts +29 -0
  35. package/dist/services/setup/os/detector-helper.js +65 -0
  36. package/dist/services/setup/os/tool-registry.d.ts +38 -0
  37. package/dist/services/setup/os/tool-registry.js +194 -0
  38. package/dist/services/setup/os/tool-registry.spec.d.ts +1 -0
  39. package/dist/services/setup/os/tool-registry.spec.js +26 -0
  40. package/dist/services/setup/setup-context.d.ts +14 -0
  41. package/dist/services/setup/setup-context.js +15 -0
  42. package/dist/services/setup/setup-service-factory.d.ts +10 -0
  43. package/dist/services/setup/setup-service-factory.js +37 -0
  44. package/dist/services/setup/setup-service.d.ts +20 -0
  45. package/dist/services/setup/setup-service.js +37 -0
  46. package/oclif.manifest.json +122 -1
  47. package/package.json +1 -1
@@ -0,0 +1,194 @@
1
+ /**
2
+ * OS-specific registry of the browsers and diff/editor tools the first-run
3
+ * wizard knows how to detect. Detection strategies differ per platform, so the
4
+ * candidate executable paths and PATH launcher names are grouped by platform.
5
+ *
6
+ * This module holds only data + pure helpers; the actual filesystem probing
7
+ * lives in the browser/diff-tool detectors.
8
+ */
9
+ export const BROWSERS = [
10
+ {
11
+ id: "chrome",
12
+ name: "Google Chrome",
13
+ commands: ["google-chrome", "google-chrome-stable", "chrome"],
14
+ paths: {
15
+ darwin: ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"],
16
+ win32: [
17
+ "%ProgramFiles%\\Google\\Chrome\\Application\\chrome.exe",
18
+ "%ProgramFiles(x86)%\\Google\\Chrome\\Application\\chrome.exe",
19
+ "%LOCALAPPDATA%\\Google\\Chrome\\Application\\chrome.exe",
20
+ ],
21
+ linux: [
22
+ "/usr/bin/google-chrome",
23
+ "/usr/bin/google-chrome-stable",
24
+ "/opt/google/chrome/chrome",
25
+ ],
26
+ },
27
+ },
28
+ {
29
+ id: "chromium",
30
+ name: "Chromium",
31
+ commands: ["chromium", "chromium-browser"],
32
+ paths: {
33
+ darwin: ["/Applications/Chromium.app/Contents/MacOS/Chromium"],
34
+ win32: ["%ProgramFiles%\\Chromium\\Application\\chrome.exe"],
35
+ linux: [
36
+ "/usr/bin/chromium",
37
+ "/usr/bin/chromium-browser",
38
+ "/snap/bin/chromium",
39
+ ],
40
+ },
41
+ },
42
+ {
43
+ id: "edge",
44
+ name: "Microsoft Edge",
45
+ commands: ["microsoft-edge", "microsoft-edge-stable", "msedge"],
46
+ paths: {
47
+ darwin: [
48
+ "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
49
+ ],
50
+ win32: [
51
+ "%ProgramFiles(x86)%\\Microsoft\\Edge\\Application\\msedge.exe",
52
+ "%ProgramFiles%\\Microsoft\\Edge\\Application\\msedge.exe",
53
+ ],
54
+ linux: [
55
+ "/usr/bin/microsoft-edge",
56
+ "/usr/bin/microsoft-edge-stable",
57
+ "/opt/microsoft/msedge/msedge",
58
+ ],
59
+ },
60
+ },
61
+ {
62
+ id: "brave",
63
+ name: "Brave",
64
+ commands: ["brave-browser", "brave"],
65
+ paths: {
66
+ darwin: ["/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"],
67
+ win32: [
68
+ "%ProgramFiles%\\BraveSoftware\\Brave-Browser\\Application\\brave.exe",
69
+ "%ProgramFiles(x86)%\\BraveSoftware\\Brave-Browser\\Application\\brave.exe",
70
+ ],
71
+ linux: [
72
+ "/usr/bin/brave-browser",
73
+ "/usr/bin/brave",
74
+ "/opt/brave.com/brave/brave",
75
+ ],
76
+ },
77
+ },
78
+ ];
79
+ export const EDITORS = [
80
+ {
81
+ id: "idea",
82
+ name: "IntelliJ IDEA",
83
+ commands: ["idea"],
84
+ diffExecTemplate: '"$exec" diff "$file1" "$file2"',
85
+ paths: {
86
+ darwin: [
87
+ "/Applications/IntelliJ IDEA.app/Contents/MacOS/idea",
88
+ "/usr/local/bin/idea",
89
+ ],
90
+ win32: ["%LOCALAPPDATA%\\JetBrains\\Toolbox\\scripts\\idea.cmd"],
91
+ linux: ["/usr/local/bin/idea", "/opt/idea/bin/idea.sh"],
92
+ },
93
+ },
94
+ {
95
+ id: "webstorm",
96
+ name: "WebStorm",
97
+ commands: ["webstorm"],
98
+ diffExecTemplate: '"$exec" diff "$file1" "$file2"',
99
+ paths: {
100
+ darwin: [
101
+ "/Applications/WebStorm.app/Contents/MacOS/webstorm",
102
+ "/usr/local/bin/webstorm",
103
+ ],
104
+ win32: ["%LOCALAPPDATA%\\JetBrains\\Toolbox\\scripts\\webstorm.cmd"],
105
+ linux: ["/usr/local/bin/webstorm", "/opt/webstorm/bin/webstorm.sh"],
106
+ },
107
+ },
108
+ {
109
+ id: "pycharm",
110
+ name: "PyCharm",
111
+ commands: ["pycharm", "charm"],
112
+ diffExecTemplate: '"$exec" diff "$file1" "$file2"',
113
+ paths: {
114
+ darwin: [
115
+ "/Applications/PyCharm.app/Contents/MacOS/pycharm",
116
+ "/usr/local/bin/charm",
117
+ ],
118
+ win32: ["%LOCALAPPDATA%\\JetBrains\\Toolbox\\scripts\\pycharm.cmd"],
119
+ linux: ["/usr/local/bin/charm", "/opt/pycharm/bin/pycharm.sh"],
120
+ },
121
+ },
122
+ {
123
+ id: "code",
124
+ name: "Visual Studio Code",
125
+ commands: ["code"],
126
+ diffExecTemplate: '"$exec" --diff "$file1" "$file2"',
127
+ paths: {
128
+ darwin: [
129
+ "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code",
130
+ "/usr/local/bin/code",
131
+ ],
132
+ win32: [
133
+ "%LOCALAPPDATA%\\Programs\\Microsoft VS Code\\bin\\code.cmd",
134
+ "%ProgramFiles%\\Microsoft VS Code\\bin\\code.cmd",
135
+ ],
136
+ linux: ["/usr/bin/code", "/usr/share/code/bin/code", "/snap/bin/code"],
137
+ },
138
+ },
139
+ {
140
+ id: "codium",
141
+ name: "VSCodium",
142
+ commands: ["codium"],
143
+ diffExecTemplate: '"$exec" --diff "$file1" "$file2"',
144
+ paths: {
145
+ darwin: [
146
+ "/Applications/VSCodium.app/Contents/Resources/app/bin/codium",
147
+ "/usr/local/bin/codium",
148
+ ],
149
+ win32: ["%LOCALAPPDATA%\\Programs\\VSCodium\\bin\\codium.cmd"],
150
+ linux: ["/usr/bin/codium", "/snap/bin/codium"],
151
+ },
152
+ },
153
+ {
154
+ id: "cursor",
155
+ name: "Cursor",
156
+ commands: ["cursor"],
157
+ diffExecTemplate: '"$exec" --diff "$file1" "$file2"',
158
+ paths: {
159
+ darwin: [
160
+ "/Applications/Cursor.app/Contents/Resources/app/bin/cursor",
161
+ "/usr/local/bin/cursor",
162
+ ],
163
+ win32: [
164
+ "%LOCALAPPDATA%\\Programs\\cursor\\resources\\app\\bin\\cursor.cmd",
165
+ ],
166
+ linux: ["/usr/bin/cursor", "/opt/cursor/bin/cursor"],
167
+ },
168
+ },
169
+ ];
170
+ /**
171
+ * Normalizes an unknown platform string into one of the supported platforms.
172
+ * Falls back to "linux" for the various *nix variants Node may report.
173
+ */
174
+ export function normalizePlatform(platform) {
175
+ if (platform === "darwin" || platform === "win32") {
176
+ return platform;
177
+ }
178
+ return "linux";
179
+ }
180
+ /**
181
+ * Expands `~` (home) and Windows `%VAR%` tokens in a candidate path. Unknown
182
+ * `%VAR%` tokens are left untouched so a later existence check simply misses.
183
+ */
184
+ export function expandCandidatePath(raw, home, env = process.env) {
185
+ let expanded = raw;
186
+ if (expanded.startsWith("~")) {
187
+ expanded = home + expanded.slice(1);
188
+ }
189
+ expanded = expanded.replaceAll(/%([^%]+)%/g, (match, name) => {
190
+ const value = env[name];
191
+ return value === undefined ? match : value;
192
+ });
193
+ return expanded;
194
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { expect } from "chai";
2
+ import { describe, it } from "mocha";
3
+ import { expandCandidatePath, normalizePlatform } from "./tool-registry.js";
4
+ describe("tool-registry.normalizePlatform", () => {
5
+ it("passes through supported platforms", () => {
6
+ expect(normalizePlatform("darwin")).to.equal("darwin");
7
+ expect(normalizePlatform("win32")).to.equal("win32");
8
+ expect(normalizePlatform("linux")).to.equal("linux");
9
+ });
10
+ it("falls back to linux for other *nix variants", () => {
11
+ expect(normalizePlatform("freebsd")).to.equal("linux");
12
+ expect(normalizePlatform("openbsd")).to.equal("linux");
13
+ });
14
+ });
15
+ describe("tool-registry.expandCandidatePath", () => {
16
+ it("expands a leading ~ to the home directory", () => {
17
+ expect(expandCandidatePath("~/bin/idea", "/home/tester")).to.equal("/home/tester/bin/idea");
18
+ });
19
+ it("expands known %VAR% tokens from env", () => {
20
+ const env = { LOCALAPPDATA: "C:\\Users\\t\\AppData\\Local" };
21
+ expect(expandCandidatePath("%LOCALAPPDATA%\\Programs\\code.cmd", "C:\\Users\\t", env)).to.equal("C:\\Users\\t\\AppData\\Local\\Programs\\code.cmd");
22
+ });
23
+ it("leaves unknown %VAR% tokens untouched", () => {
24
+ expect(expandCandidatePath("%NOPE%\\x.exe", "/home", {})).to.equal("%NOPE%\\x.exe");
25
+ });
26
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Inputs for the first-run wizard. No logic.
3
+ */
4
+ export declare class SetupContext {
5
+ /** true when invoked from the npm postinstall hook */
6
+ readonly postInstall: boolean;
7
+ /** re-run even if setup was already completed */
8
+ readonly force: boolean;
9
+ constructor(
10
+ /** true when invoked from the npm postinstall hook */
11
+ postInstall?: boolean,
12
+ /** re-run even if setup was already completed */
13
+ force?: boolean);
14
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Inputs for the first-run wizard. No logic.
3
+ */
4
+ export class SetupContext {
5
+ postInstall;
6
+ force;
7
+ constructor(
8
+ /** true when invoked from the npm postinstall hook */
9
+ postInstall = false,
10
+ /** re-run even if setup was already completed */
11
+ force = false) {
12
+ this.postInstall = postInstall;
13
+ this.force = force;
14
+ }
15
+ }
@@ -0,0 +1,10 @@
1
+ import { Config } from "@oclif/core";
2
+ import { SetupContext } from "./setup-context.js";
3
+ import { SetupService } from "./setup-service.js";
4
+ export declare class SetupServiceFactory {
5
+ private readonly oclifConfig;
6
+ private readonly context;
7
+ private service?;
8
+ constructor(oclifConfig: Config, context?: SetupContext);
9
+ getService(): SetupService;
10
+ }
@@ -0,0 +1,37 @@
1
+ import { CliServiceFactory } from "../cli/index.js";
2
+ import { CliConfig } from "../../helpers/cli-config.js";
3
+ import { normalizePlatform } from "./os/tool-registry.js";
4
+ import { BrowserDetector } from "./browser/browser-detector.js";
5
+ import { BrowserManager } from "./browser/browser-manager.js";
6
+ import { BrowserSetupService } from "./browser/browser-setup-service.js";
7
+ import { DiffToolDetector } from "./difftool/difftool-detector.js";
8
+ import { DiffToolSetupService } from "./difftool/difftool-setup-service.js";
9
+ import { SetupContext } from "./setup-context.js";
10
+ import { SetupService } from "./setup-service.js";
11
+ export class SetupServiceFactory {
12
+ oclifConfig;
13
+ context;
14
+ service;
15
+ constructor(oclifConfig, context = new SetupContext()) {
16
+ this.oclifConfig = oclifConfig;
17
+ this.context = context;
18
+ }
19
+ getService() {
20
+ if (this.service instanceof SetupService) {
21
+ return this.service;
22
+ }
23
+ const cli = new CliServiceFactory().getService();
24
+ const cliConfig = new CliConfig(this.oclifConfig);
25
+ const userConfig = cliConfig.load();
26
+ const platform = normalizePlatform(this.oclifConfig.platform);
27
+ const home = this.oclifConfig.home;
28
+ const cacheDir = userConfig.tempFolder;
29
+ const browserDetector = new BrowserDetector(platform, home, cacheDir);
30
+ const browserManager = new BrowserManager(cacheDir, cli);
31
+ const browserSetup = new BrowserSetupService(cli, cliConfig, userConfig, browserDetector, browserManager);
32
+ const diffDetector = new DiffToolDetector(platform, home);
33
+ const diffSetup = new DiffToolSetupService(cli, cliConfig, userConfig, diffDetector);
34
+ this.service = new SetupService(cli, cliConfig, userConfig, browserSetup, diffSetup, this.context);
35
+ return this.service;
36
+ }
37
+ }
@@ -0,0 +1,20 @@
1
+ import { CliServiceInterface } from "../cli/index.js";
2
+ import { CliConfig, UserCliConfig } from "../../helpers/cli-config.js";
3
+ import { BrowserSetupService } from "./browser/browser-setup-service.js";
4
+ import { DiffToolSetupService } from "./difftool/difftool-setup-service.js";
5
+ import { SetupContext } from "./setup-context.js";
6
+ export declare class SetupService {
7
+ private readonly cli;
8
+ private readonly cliConfig;
9
+ private readonly userConfig;
10
+ private readonly browserSetup;
11
+ private readonly diffSetup;
12
+ private readonly context;
13
+ constructor(cli: CliServiceInterface, cliConfig: CliConfig, userConfig: UserCliConfig, browserSetup: BrowserSetupService, diffSetup: DiffToolSetupService, context: SetupContext);
14
+ /** Runs the full first-run wizard (browser + diff tool) and marks it done. */
15
+ run(): Promise<void>;
16
+ /** True when the first-run wizard has already been completed once. */
17
+ isFirstRunCompleted(): boolean;
18
+ /** Update-reminder check for the browser, used by the init hook. */
19
+ remindBrowserUpdate(): Promise<void>;
20
+ }
@@ -0,0 +1,37 @@
1
+ export class SetupService {
2
+ cli;
3
+ cliConfig;
4
+ userConfig;
5
+ browserSetup;
6
+ diffSetup;
7
+ context;
8
+ constructor(cli, cliConfig, userConfig, browserSetup, diffSetup, context) {
9
+ this.cli = cli;
10
+ this.cliConfig = cliConfig;
11
+ this.userConfig = userConfig;
12
+ this.browserSetup = browserSetup;
13
+ this.diffSetup = diffSetup;
14
+ this.context = context;
15
+ }
16
+ /** Runs the full first-run wizard (browser + diff tool) and marks it done. */
17
+ async run() {
18
+ this.cli.spacer();
19
+ this.cli.write(this.cli.style.bold("Speed Kit CLI — setup"));
20
+ this.cli.comment("Configure the browser and diff tool used for onboarding and deploys.");
21
+ this.cli.spacer();
22
+ await this.browserSetup.run();
23
+ this.cli.spacer();
24
+ await this.diffSetup.run();
25
+ this.cliConfig.save({ firstRunCompleted: true });
26
+ this.cli.spacer();
27
+ this.cli.writeSuccess("Setup complete. Re-run any time with `sk config setup`.");
28
+ }
29
+ /** True when the first-run wizard has already been completed once. */
30
+ isFirstRunCompleted() {
31
+ return Boolean(this.userConfig.firstRunCompleted) && !this.context.force;
32
+ }
33
+ /** Update-reminder check for the browser, used by the init hook. */
34
+ async remindBrowserUpdate() {
35
+ await this.browserSetup.remindIfDue();
36
+ }
37
+ }
@@ -855,6 +855,87 @@
855
855
  "fish.js"
856
856
  ]
857
857
  },
858
+ "browser:clean": {
859
+ "aliases": [],
860
+ "args": {},
861
+ "description": "Remove puppeteer-managed browser builds from the cache",
862
+ "examples": [
863
+ "$ sk browser clean",
864
+ "$ sk browser clean --all"
865
+ ],
866
+ "flags": {
867
+ "all": {
868
+ "char": "a",
869
+ "description": "Remove all cached browser builds without prompting",
870
+ "name": "all",
871
+ "allowNo": false,
872
+ "type": "boolean"
873
+ }
874
+ },
875
+ "hasDynamicHelp": false,
876
+ "hiddenAliases": [],
877
+ "id": "browser:clean",
878
+ "pluginAlias": "@speedkit/cli",
879
+ "pluginName": "@speedkit/cli",
880
+ "pluginType": "core",
881
+ "strict": true,
882
+ "enableJsonFlag": false,
883
+ "isESM": true,
884
+ "relativePath": [
885
+ "dist",
886
+ "commands",
887
+ "browser",
888
+ "clean.js"
889
+ ]
890
+ },
891
+ "browser:list": {
892
+ "aliases": [],
893
+ "args": {},
894
+ "description": "List detected system browsers and puppeteer-managed builds",
895
+ "examples": [
896
+ "$ sk browser list"
897
+ ],
898
+ "flags": {},
899
+ "hasDynamicHelp": false,
900
+ "hiddenAliases": [],
901
+ "id": "browser:list",
902
+ "pluginAlias": "@speedkit/cli",
903
+ "pluginName": "@speedkit/cli",
904
+ "pluginType": "core",
905
+ "strict": true,
906
+ "enableJsonFlag": false,
907
+ "isESM": true,
908
+ "relativePath": [
909
+ "dist",
910
+ "commands",
911
+ "browser",
912
+ "list.js"
913
+ ]
914
+ },
915
+ "browser:update": {
916
+ "aliases": [],
917
+ "args": {},
918
+ "description": "Update the puppeteer-managed browser to the latest build of its channel",
919
+ "examples": [
920
+ "$ sk browser update"
921
+ ],
922
+ "flags": {},
923
+ "hasDynamicHelp": false,
924
+ "hiddenAliases": [],
925
+ "id": "browser:update",
926
+ "pluginAlias": "@speedkit/cli",
927
+ "pluginName": "@speedkit/cli",
928
+ "pluginType": "core",
929
+ "strict": true,
930
+ "enableJsonFlag": false,
931
+ "isESM": true,
932
+ "relativePath": [
933
+ "dist",
934
+ "commands",
935
+ "browser",
936
+ "update.js"
937
+ ]
938
+ },
858
939
  "config:edit": {
859
940
  "aliases": [],
860
941
  "args": {},
@@ -878,7 +959,47 @@
878
959
  "config",
879
960
  "edit.js"
880
961
  ]
962
+ },
963
+ "config:setup": {
964
+ "aliases": [],
965
+ "args": {},
966
+ "description": "Run the Speed Kit CLI setup wizard (choose browser and diff tool)",
967
+ "examples": [
968
+ "$ sk config setup",
969
+ "$ sk config setup --force"
970
+ ],
971
+ "flags": {
972
+ "force": {
973
+ "char": "f",
974
+ "description": "Re-run even if setup was already completed",
975
+ "name": "force",
976
+ "allowNo": false,
977
+ "type": "boolean"
978
+ },
979
+ "postInstall": {
980
+ "description": "Internal flag used by the npm postinstall hook",
981
+ "hidden": true,
982
+ "name": "postInstall",
983
+ "allowNo": false,
984
+ "type": "boolean"
985
+ }
986
+ },
987
+ "hasDynamicHelp": false,
988
+ "hiddenAliases": [],
989
+ "id": "config:setup",
990
+ "pluginAlias": "@speedkit/cli",
991
+ "pluginName": "@speedkit/cli",
992
+ "pluginType": "core",
993
+ "strict": true,
994
+ "enableJsonFlag": false,
995
+ "isESM": true,
996
+ "relativePath": [
997
+ "dist",
998
+ "commands",
999
+ "config",
1000
+ "setup.js"
1001
+ ]
881
1002
  }
882
1003
  },
883
- "version": "4.17.1"
1004
+ "version": "4.19.0"
884
1005
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@speedkit/cli",
3
3
  "description": "Speed Kit CLI",
4
- "version": "4.17.1",
4
+ "version": "4.19.0",
5
5
  "author": {
6
6
  "name": "Baqend.com",
7
7
  "email": "info@baqend.com"