@mondaydotcomorg/z2h-cli 0.11.5 → 0.12.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.
@@ -1 +1 @@
1
- {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,sBAAsB,CAAC,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C7F"}
1
+ {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,sBAAsB,CAAC,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C7F"}
@@ -22,7 +22,11 @@ async function createWorkspaceCommand(opts = {}) {
22
22
  if (await fs.pathExists(home)) {
23
23
  const entries = await fs.readdir(home);
24
24
  if (entries.length > 0) {
25
- throw new Error(`Workspace already exists at ${home}. Remove it and try again.`);
25
+ util_logger.output(`[z2h-cli] workspace already exists at ${home} — skipping`, {
26
+ ok: true,
27
+ workspace: home,
28
+ });
29
+ return;
26
30
  }
27
31
  }
28
32
  else {
@@ -1,5 +1,6 @@
1
1
  export interface DevOptions {
2
2
  json?: boolean;
3
+ open?: boolean;
3
4
  }
4
5
  export declare function devCommand(opts?: DevOptions): Promise<void>;
5
6
  //# sourceMappingURL=dev.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD,wBAAsB,UAAU,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0ErE"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD,wBAAsB,UAAU,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ErE"}
@@ -9,6 +9,7 @@ const util_logger = require('../util/logger.js');
9
9
  const shadow_prepare = require('../shadow/prepare.js');
10
10
  const shadow_consumerPkg = require('../shadow/consumer-pkg.js');
11
11
  const shadow_sync = require('../shadow/sync.js');
12
+ const util_openBrowser = require('../util/open-browser.js');
12
13
 
13
14
  const _interopDefault = e => e && e.__esModule ? e : { default: e };
14
15
 
@@ -68,6 +69,9 @@ async function devCommand(opts = {}) {
68
69
  port,
69
70
  url,
70
71
  });
72
+ if (opts.open) {
73
+ void util_openBrowser.openInBrowser(url);
74
+ }
71
75
  }
72
76
  });
73
77
  // Only watch consumer package.json. Source changes flow through Vite's
@@ -1 +1 @@
1
- {"version":3,"file":"generate-z2h-token.d.ts","sourceRoot":"","sources":["../../src/commands/generate-z2h-token.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,yDAAyD,CAAC;AAC7F,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAuED,wBAAsB,uBAAuB,CAAC,IAAI,GAAE,uBAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/F"}
1
+ {"version":3,"file":"generate-z2h-token.d.ts","sourceRoot":"","sources":["../../src/commands/generate-z2h-token.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,yDAAyD,CAAC;AAC7F,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAwDD,wBAAsB,uBAAuB,CAAC,IAAI,GAAE,uBAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/F"}
@@ -2,10 +2,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const readline = require('node:readline/promises');
4
4
  const node_process = require('node:process');
5
- const execa = require('execa');
6
5
  const util_logger = require('../util/logger.js');
7
6
  const util_auth_writeAuth = require('../util/auth/write-auth.js');
8
7
  const util_auth_loopbackServer = require('../util/auth/loopback-server.js');
8
+ const util_openBrowser = require('../util/open-browser.js');
9
9
 
10
10
  const _interopDefault = e => e && e.__esModule ? e : { default: e };
11
11
 
@@ -13,19 +13,6 @@ const readline__default = /*#__PURE__*/_interopDefault(readline);
13
13
 
14
14
  const DEFAULT_TOKEN_PAGE_URL = 'https://bigbrain.me/bigbrain-vibe/generate-z2h-token';
15
15
  const LOOPBACK_TIMEOUT_MS = 120_000;
16
- function browserOpenCommand() {
17
- switch (process.platform) {
18
- case 'darwin':
19
- return 'open';
20
- case 'win32':
21
- return 'start';
22
- default:
23
- return 'xdg-open';
24
- }
25
- }
26
- async function openInBrowser(url) {
27
- await execa.execa(browserOpenCommand(), [url], { stdio: 'ignore' });
28
- }
29
16
  async function promptForToken() {
30
17
  const rl = readline__default.default.createInterface({ input: node_process.stdin, output: node_process.stdout });
31
18
  try {
@@ -58,7 +45,7 @@ async function runLoopbackFlow(pageUrl) {
58
45
  util_logger.info('opening your browser to mint a Z2H deploy token');
59
46
  util_logger.info(` ${fullUrl}`);
60
47
  try {
61
- await openInBrowser(fullUrl);
48
+ await util_openBrowser.openInBrowser(fullUrl);
62
49
  }
63
50
  catch {
64
51
  util_logger.warn('could not auto-open the browser. please visit the URL above manually.');
@@ -1 +1 @@
1
- {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,sBAAsB,CAAC,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C7F"}
1
+ {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,sBAAsB,CAAC,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C7F"}
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { pathExists, readdir, ensureDir, writeFile, copy } from 'fs-extra';
4
- import { setOutputMode, info, output } from '../util/logger.mjs';
4
+ import { setOutputMode, output, info } from '../util/logger.mjs';
5
5
  import { getWorkspaceHome } from '../util/workspace.mjs';
6
6
  import { getTemplatesDir } from '../util/templates.mjs';
7
7
  import { runYarnInstall } from '../util/npm/install.mjs';
@@ -16,7 +16,11 @@ async function createWorkspaceCommand(opts = {}) {
16
16
  if (await pathExists(home)) {
17
17
  const entries = await readdir(home);
18
18
  if (entries.length > 0) {
19
- throw new Error(`Workspace already exists at ${home}. Remove it and try again.`);
19
+ output(`[z2h-cli] workspace already exists at ${home} — skipping`, {
20
+ ok: true,
21
+ workspace: home,
22
+ });
23
+ return;
20
24
  }
21
25
  }
22
26
  else {
@@ -1,5 +1,6 @@
1
1
  export interface DevOptions {
2
2
  json?: boolean;
3
+ open?: boolean;
3
4
  }
4
5
  export declare function devCommand(opts?: DevOptions): Promise<void>;
5
6
  //# sourceMappingURL=dev.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/commands/dev.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD,wBAAsB,UAAU,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0ErE"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/commands/dev.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD,wBAAsB,UAAU,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ErE"}
@@ -7,6 +7,7 @@ import { setOutputMode, info, output, warn, errorLog } from '../util/logger.mjs'
7
7
  import { prepareShadow } from '../shadow/prepare.mjs';
8
8
  import { ensureConsumerPkg } from '../shadow/consumer-pkg.mjs';
9
9
  import { syncShadow } from '../shadow/sync.mjs';
10
+ import { openInBrowser } from '../util/open-browser.mjs';
10
11
 
11
12
  const TRIDENT_READY_PATTERN = /Server started at/i;
12
13
  // Should be run from the consumer app directory — uses process.cwd() to locate it.
@@ -61,6 +62,9 @@ async function devCommand(opts = {}) {
61
62
  port,
62
63
  url,
63
64
  });
65
+ if (opts.open) {
66
+ void openInBrowser(url);
67
+ }
64
68
  }
65
69
  });
66
70
  // Only watch consumer package.json. Source changes flow through Vite's
@@ -1 +1 @@
1
- {"version":3,"file":"generate-z2h-token.d.ts","sourceRoot":"","sources":["../../../src/commands/generate-z2h-token.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,yDAAyD,CAAC;AAC7F,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAuED,wBAAsB,uBAAuB,CAAC,IAAI,GAAE,uBAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/F"}
1
+ {"version":3,"file":"generate-z2h-token.d.ts","sourceRoot":"","sources":["../../../src/commands/generate-z2h-token.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,yDAAyD,CAAC;AAC7F,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAwDD,wBAAsB,uBAAuB,CAAC,IAAI,GAAE,uBAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/F"}
@@ -1,25 +1,12 @@
1
1
  import readline from 'node:readline/promises';
2
2
  import { stdin, stdout } from 'node:process';
3
- import { execa } from 'execa';
4
3
  import { setOutputMode, warn, output, info } from '../util/logger.mjs';
5
4
  import { validateJwtPattern, writeZthAuth } from '../util/auth/write-auth.mjs';
6
5
  import { startLoopbackServer } from '../util/auth/loopback-server.mjs';
6
+ import { openInBrowser } from '../util/open-browser.mjs';
7
7
 
8
8
  const DEFAULT_TOKEN_PAGE_URL = 'https://bigbrain.me/bigbrain-vibe/generate-z2h-token';
9
9
  const LOOPBACK_TIMEOUT_MS = 120_000;
10
- function browserOpenCommand() {
11
- switch (process.platform) {
12
- case 'darwin':
13
- return 'open';
14
- case 'win32':
15
- return 'start';
16
- default:
17
- return 'xdg-open';
18
- }
19
- }
20
- async function openInBrowser(url) {
21
- await execa(browserOpenCommand(), [url], { stdio: 'ignore' });
22
- }
23
10
  async function promptForToken() {
24
11
  const rl = readline.createInterface({ input: stdin, output: stdout });
25
12
  try {
@@ -70,6 +70,7 @@ async function main() {
70
70
  program
71
71
  .command('dev')
72
72
  .description('Start the Trident dev server against .zth/ with native Vite HMR')
73
+ .option('--open', 'open the browser automatically when the dev server is ready')
73
74
  .option('--json', 'emit structured JSON on stdout')
74
75
  .action(async (opts) => {
75
76
  try {
@@ -232,5 +233,8 @@ void main()
232
233
  process.exit(0);
233
234
  })
234
235
  .catch(async (err) => {
235
- await fail(`main failed: ${err.message}`, { command: 'cli-main' });
236
+ const errorMsg = err instanceof Error ? err.message : String(err);
237
+ await fail(`main failed, check you are on latest version.\nerror: ${errorMsg}`, {
238
+ command: 'cli-main',
239
+ });
236
240
  });
@@ -81,7 +81,7 @@ async function pullAndResolve(dir, env) {
81
81
  }
82
82
  await safeBackupIfDirty(dir);
83
83
  const info = await gatherConflictInfo(dir, gitEnv);
84
- throw new GitConflictError(JSON.stringify(info));
84
+ throw new GitConflictError(`Pull rejected: Git conflict detected: ${JSON.stringify(info)}`);
85
85
  }
86
86
  }
87
87
  /**
@@ -109,7 +109,7 @@ async function pushToRemote(dir, env) {
109
109
  }
110
110
  if (isRejected) {
111
111
  const info = await gatherConflictInfo(dir, gitEnv);
112
- throw new GitConflictError(JSON.stringify(info));
112
+ throw new GitConflictError(`Push rejected: Git conflict detected: ${JSON.stringify(info)}`);
113
113
  }
114
114
  throw err;
115
115
  }
@@ -0,0 +1,2 @@
1
+ export declare function openInBrowser(url: string): Promise<void>;
2
+ //# sourceMappingURL=open-browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-browser.d.ts","sourceRoot":"","sources":["../../../src/util/open-browser.ts"],"names":[],"mappings":"AAcA,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9D"}
@@ -0,0 +1,20 @@
1
+ import { execa } from 'execa';
2
+ import { errorLog } from './logger.mjs';
3
+
4
+ function browserOpenCommand() {
5
+ switch (process.platform) {
6
+ case 'darwin':
7
+ return 'open';
8
+ case 'win32':
9
+ return 'start';
10
+ default:
11
+ return 'xdg-open';
12
+ }
13
+ }
14
+ async function openInBrowser(url) {
15
+ await execa(browserOpenCommand(), [url], { stdio: 'ignore' }).catch(() => {
16
+ errorLog(`Failed to open browser for ${url}, open it manually.`);
17
+ });
18
+ }
19
+
20
+ export { openInBrowser };
package/dist/index.js CHANGED
@@ -76,6 +76,7 @@ async function main() {
76
76
  program
77
77
  .command('dev')
78
78
  .description('Start the Trident dev server against .zth/ with native Vite HMR')
79
+ .option('--open', 'open the browser automatically when the dev server is ready')
79
80
  .option('--json', 'emit structured JSON on stdout')
80
81
  .action(async (opts) => {
81
82
  try {
@@ -238,5 +239,8 @@ void main()
238
239
  process.exit(0);
239
240
  })
240
241
  .catch(async (err) => {
241
- await util_logger.fail(`main failed: ${err.message}`, { command: 'cli-main' });
242
+ const errorMsg = err instanceof Error ? err.message : String(err);
243
+ await util_logger.fail(`main failed, check you are on latest version.\nerror: ${errorMsg}`, {
244
+ command: 'cli-main',
245
+ });
242
246
  });
@@ -88,7 +88,7 @@ async function pullAndResolve(dir, env) {
88
88
  }
89
89
  await safeBackupIfDirty(dir);
90
90
  const info = await gatherConflictInfo(dir, gitEnv);
91
- throw new GitConflictError(JSON.stringify(info));
91
+ throw new GitConflictError(`Pull rejected: Git conflict detected: ${JSON.stringify(info)}`);
92
92
  }
93
93
  }
94
94
  /**
@@ -116,7 +116,7 @@ async function pushToRemote(dir, env) {
116
116
  }
117
117
  if (isRejected) {
118
118
  const info = await gatherConflictInfo(dir, gitEnv);
119
- throw new GitConflictError(JSON.stringify(info));
119
+ throw new GitConflictError(`Push rejected: Git conflict detected: ${JSON.stringify(info)}`);
120
120
  }
121
121
  throw err;
122
122
  }
@@ -0,0 +1,2 @@
1
+ export declare function openInBrowser(url: string): Promise<void>;
2
+ //# sourceMappingURL=open-browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-browser.d.ts","sourceRoot":"","sources":["../../src/util/open-browser.ts"],"names":[],"mappings":"AAcA,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9D"}
@@ -0,0 +1,22 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const execa = require('execa');
4
+ const util_logger = require('./logger.js');
5
+
6
+ function browserOpenCommand() {
7
+ switch (process.platform) {
8
+ case 'darwin':
9
+ return 'open';
10
+ case 'win32':
11
+ return 'start';
12
+ default:
13
+ return 'xdg-open';
14
+ }
15
+ }
16
+ async function openInBrowser(url) {
17
+ await execa.execa(browserOpenCommand(), [url], { stdio: 'ignore' }).catch(() => {
18
+ util_logger.errorLog(`Failed to open browser for ${url}, open it manually.`);
19
+ });
20
+ }
21
+
22
+ exports.openInBrowser = openInBrowser;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/z2h-cli",
3
- "version": "0.11.5",
3
+ "version": "0.12.0",
4
4
  "bin": "./bin/z2h-cli.js",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -51,11 +51,11 @@ describe('create-workspace', () => {
51
51
  expect(runYarnInstall).toHaveBeenCalledWith(expect.objectContaining({ cwd: tmp }));
52
52
  });
53
53
 
54
- it('refuses if the target dir is non-empty', async () => {
54
+ it('skips gracefully if the target dir is non-empty', async () => {
55
55
  await ensureDir(tmp);
56
56
  await writeJson(path.join(tmp, 'somefile.json'), { hello: 'world' });
57
57
 
58
- await expect(createWorkspaceCommand()).rejects.toThrow(/Workspace already exists/);
58
+ await expect(createWorkspaceCommand()).resolves.toBeUndefined();
59
59
  expect(runYarnInstall).not.toHaveBeenCalled();
60
60
  });
61
61
 
@@ -22,7 +22,11 @@ export async function createWorkspaceCommand(opts: CreateWorkspaceOptions = {}):
22
22
  if (await pathExists(home)) {
23
23
  const entries = await readdir(home);
24
24
  if (entries.length > 0) {
25
- throw new Error(`Workspace already exists at ${home}. Remove it and try again.`);
25
+ output(`[z2h-cli] workspace already exists at ${home} — skipping`, {
26
+ ok: true,
27
+ workspace: home,
28
+ });
29
+ return;
26
30
  }
27
31
  } else {
28
32
  await ensureDir(home);
@@ -7,10 +7,12 @@ import { info, warn, errorLog, output, setOutputMode } from '../util/logger';
7
7
  import { prepareShadow } from '../shadow/prepare';
8
8
  import { ensureConsumerPkg } from '../shadow/consumer-pkg';
9
9
  import { syncShadow } from '../shadow/sync';
10
+ import { openInBrowser } from '../util/open-browser';
10
11
  import type { ConsumerPkg } from '../types';
11
12
 
12
13
  export interface DevOptions {
13
14
  json?: boolean;
15
+ open?: boolean;
14
16
  }
15
17
 
16
18
  const TRIDENT_READY_PATTERN = /Server started at/i;
@@ -71,6 +73,9 @@ export async function devCommand(opts: DevOptions = {}): Promise<void> {
71
73
  port,
72
74
  url,
73
75
  });
76
+ if (opts.open) {
77
+ void openInBrowser(url);
78
+ }
74
79
  }
75
80
  });
76
81
 
@@ -1,9 +1,9 @@
1
1
  import readline from 'node:readline/promises';
2
2
  import { stdin, stdout } from 'node:process';
3
- import { execa } from 'execa';
4
3
  import { info, warn, output, setOutputMode } from '../util/logger';
5
4
  import { writeZthAuth, validateJwtPattern } from '../util/auth/write-auth';
6
5
  import { startLoopbackServer } from '../util/auth/loopback-server';
6
+ import { openInBrowser } from '../util/open-browser';
7
7
 
8
8
  export const DEFAULT_TOKEN_PAGE_URL = 'https://bigbrain.me/bigbrain-vibe/generate-z2h-token';
9
9
  export const LOOPBACK_TIMEOUT_MS = 120_000;
@@ -21,21 +21,6 @@ export interface GenerateZ2HTokenOptions {
21
21
  json?: boolean;
22
22
  }
23
23
 
24
- function browserOpenCommand(): string {
25
- switch (process.platform) {
26
- case 'darwin':
27
- return 'open';
28
- case 'win32':
29
- return 'start';
30
- default:
31
- return 'xdg-open';
32
- }
33
- }
34
-
35
- async function openInBrowser(url: string): Promise<void> {
36
- await execa(browserOpenCommand(), [url], { stdio: 'ignore' });
37
- }
38
-
39
24
  async function promptForToken(): Promise<string> {
40
25
  const rl = readline.createInterface({ input: stdin, output: stdout });
41
26
  try {
package/src/index.ts CHANGED
@@ -78,8 +78,9 @@ async function main(): Promise<void> {
78
78
  program
79
79
  .command('dev')
80
80
  .description('Start the Trident dev server against .zth/ with native Vite HMR')
81
+ .option('--open', 'open the browser automatically when the dev server is ready')
81
82
  .option('--json', 'emit structured JSON on stdout')
82
- .action(async (opts: { json?: boolean }) => {
83
+ .action(async (opts: { open?: boolean; json?: boolean }) => {
83
84
  try {
84
85
  await devCommand(opts);
85
86
  } catch (err) {
@@ -258,5 +259,8 @@ void main()
258
259
  process.exit(0);
259
260
  })
260
261
  .catch(async (err: unknown) => {
261
- await fail(`main failed: ${(err as Error).message}`, { command: 'cli-main' });
262
+ const errorMsg = err instanceof Error ? err.message : String(err);
263
+ await fail(`main failed, check you are on latest version.\nerror: ${errorMsg}`, {
264
+ command: 'cli-main',
265
+ });
262
266
  });
@@ -196,7 +196,7 @@ describe('pullAndResolve', () => {
196
196
  const err = await pullAndResolve(DIR).catch(e => e);
197
197
 
198
198
  expect(err).toBeInstanceOf(GitConflictError);
199
- const info = JSON.parse(err.message);
199
+ const info = JSON.parse(err.message.split('Git conflict detected: ')[1]);
200
200
  expect(info.localCommits).toEqual(['abc local commit']);
201
201
  expect(info.remoteCommits).toEqual(['def remote commit']);
202
202
  expect(info.conflictingFiles).toEqual(['src/index.ts']);
@@ -225,7 +225,7 @@ describe('pushToRemote', () => {
225
225
  const err = await pushToRemote(DIR).catch(e => e);
226
226
 
227
227
  expect(err).toBeInstanceOf(GitConflictError);
228
- const info = JSON.parse(err.message);
228
+ const info = JSON.parse(err.message.split('Git conflict detected: ')[1]);
229
229
  expect(info.localCommits).toEqual(['abc local']);
230
230
  expect(info.remoteCommits).toEqual(['def remote']);
231
231
  expect(info.conflictingFiles).toEqual(['file.ts']);
@@ -97,7 +97,7 @@ export async function pullAndResolve(dir: string, env?: Record<string, string>):
97
97
  }
98
98
  await safeBackupIfDirty(dir);
99
99
  const info = await gatherConflictInfo(dir, gitEnv);
100
- throw new GitConflictError(JSON.stringify(info));
100
+ throw new GitConflictError(`Pull rejected: Git conflict detected: ${JSON.stringify(info)}`);
101
101
  }
102
102
  }
103
103
 
@@ -125,7 +125,7 @@ export async function pushToRemote(dir: string, env?: Record<string, string>): P
125
125
  }
126
126
  if (isRejected) {
127
127
  const info = await gatherConflictInfo(dir, gitEnv);
128
- throw new GitConflictError(JSON.stringify(info));
128
+ throw new GitConflictError(`Push rejected: Git conflict detected: ${JSON.stringify(info)}`);
129
129
  }
130
130
  throw err;
131
131
  }
@@ -0,0 +1,19 @@
1
+ import { execa } from 'execa';
2
+ import { errorLog } from './logger';
3
+
4
+ function browserOpenCommand(): string {
5
+ switch (process.platform) {
6
+ case 'darwin':
7
+ return 'open';
8
+ case 'win32':
9
+ return 'start';
10
+ default:
11
+ return 'xdg-open';
12
+ }
13
+ }
14
+
15
+ export async function openInBrowser(url: string): Promise<void> {
16
+ await execa(browserOpenCommand(), [url], { stdio: 'ignore' }).catch(() => {
17
+ errorLog(`Failed to open browser for ${url}, open it manually.`);
18
+ });
19
+ }