@cat-factory/cli 0.10.3 → 0.10.4

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.
package/dist/io.d.ts CHANGED
@@ -20,6 +20,41 @@ export interface Io {
20
20
  /** Open a URL in the user's default browser (best-effort; resolves even if it can't). */
21
21
  openBrowser(url: string): Promise<void>;
22
22
  }
23
+ /** How to spawn the OS's URL opener: the command, its argv, and Windows' verbatim-argv flag. */
24
+ export interface OpenBrowserCommand {
25
+ cmd: string;
26
+ args: string[];
27
+ /**
28
+ * Windows only: hand the joined argv to `CreateProcess` unchanged instead of re-quoting each
29
+ * argument for `CommandLineToArgvW`, whose rules `cmd` does not follow.
30
+ */
31
+ windowsVerbatimArguments?: boolean;
32
+ }
33
+ /**
34
+ * The OS-appropriate command for opening a URL in the default browser.
35
+ *
36
+ * Windows goes through `cmd`, and cmd splits an UNQUOTED command line on `&` before the `start`
37
+ * builtin ever sees it. Every URL we open carries more than one query parameter, so this used to
38
+ * open the browser at everything up to the first `&` and then try to RUN each remaining parameter
39
+ * as a command: `cat-factory k3s` landed on a bare `?infraSetup=local-k3s` with none of the values
40
+ * the connect form prefills from, and the PAT links dropped their `scopes`.
41
+ *
42
+ * So the URL is quoted, which is also why `start`'s first argument is an empty quoted window title
43
+ * (it reads a leading quoted token as one). The quotes have to reach cmd verbatim, hence the flag.
44
+ *
45
+ * The quoting holds only while the URL carries no `"` of its own, so this SERIALIZES the input
46
+ * rather than trusting the caller to have done it: WHATWG serialization percent-encodes `"` in
47
+ * every component that can carry one and rejects it in a host, so no argument can close the quote
48
+ * and have cmd read the rest as a second command. Input that is not a URL at all throws, rather
49
+ * than reaching a shell as a command line whose meaning nobody has checked; `openBrowser` is
50
+ * best-effort and both call sites print the link before opening it. Inside the quotes cmd still
51
+ * expands a `%NAME%` reference, but the expansion is literal text there: quotes make `&` and its
52
+ * friends inert, and no Windows environment value can contain a `"` to close them, so the worst
53
+ * case is a wrong URL, never a second command.
54
+ *
55
+ * @throws {TypeError} if `url` is not a parsable absolute URL.
56
+ */
57
+ export declare function openCommand(url: string, platform: NodeJS.Platform): OpenBrowserCommand;
23
58
  /** The real, console-backed {@link Io}, implemented with `@clack/prompts`. */
24
59
  export declare function createConsoleIo(): Io;
25
60
  //# sourceMappingURL=io.d.ts.map
package/dist/io.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,MAAM,WAAW,EAAE;IACjB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAChE,+DAA+D;IAC/D,MAAM,CAAC,CAAC,SAAS,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,EAC/C,YAAY,EAAE,CAAC,GACd,OAAO,CAAC,CAAC,CAAC,CAAA;IACb,yFAAyF;IACzF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvC,qBAAqB;IACrB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAChE,yFAAyF;IACzF,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACxC;AAwBD,8EAA8E;AAC9E,wBAAgB,eAAe,IAAI,EAAE,CAwDpC"}
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,MAAM,WAAW,EAAE;IACjB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAChE,+DAA+D;IAC/D,MAAM,CAAC,CAAC,SAAS,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,EAC/C,YAAY,EAAE,CAAC,GACd,OAAO,CAAC,CAAC,CAAC,CAAA;IACb,yFAAyF;IACzF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvC,qBAAqB;IACrB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAChE,yFAAyF;IACzF,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACxC;AAED,gGAAgG;AAChG,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,EAAE,CAAA;IACd;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAA;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,kBAAkB,CActF;AAWD,8EAA8E;AAC9E,wBAAgB,eAAe,IAAI,EAAE,CA4DpC"}
package/dist/io.js CHANGED
@@ -1,15 +1,42 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { cancel, confirm as clackConfirm, isCancel, log, password, select as clackSelect, text, } from '@clack/prompts';
3
- /** The OS-appropriate command for opening a URL in the default browser. */
4
- function openCommand(url) {
5
- switch (process.platform) {
3
+ /**
4
+ * The OS-appropriate command for opening a URL in the default browser.
5
+ *
6
+ * Windows goes through `cmd`, and cmd splits an UNQUOTED command line on `&` before the `start`
7
+ * builtin ever sees it. Every URL we open carries more than one query parameter, so this used to
8
+ * open the browser at everything up to the first `&` and then try to RUN each remaining parameter
9
+ * as a command: `cat-factory k3s` landed on a bare `?infraSetup=local-k3s` with none of the values
10
+ * the connect form prefills from, and the PAT links dropped their `scopes`.
11
+ *
12
+ * So the URL is quoted, which is also why `start`'s first argument is an empty quoted window title
13
+ * (it reads a leading quoted token as one). The quotes have to reach cmd verbatim, hence the flag.
14
+ *
15
+ * The quoting holds only while the URL carries no `"` of its own, so this SERIALIZES the input
16
+ * rather than trusting the caller to have done it: WHATWG serialization percent-encodes `"` in
17
+ * every component that can carry one and rejects it in a host, so no argument can close the quote
18
+ * and have cmd read the rest as a second command. Input that is not a URL at all throws, rather
19
+ * than reaching a shell as a command line whose meaning nobody has checked; `openBrowser` is
20
+ * best-effort and both call sites print the link before opening it. Inside the quotes cmd still
21
+ * expands a `%NAME%` reference, but the expansion is literal text there: quotes make `&` and its
22
+ * friends inert, and no Windows environment value can contain a `"` to close them, so the worst
23
+ * case is a wrong URL, never a second command.
24
+ *
25
+ * @throws {TypeError} if `url` is not a parsable absolute URL.
26
+ */
27
+ export function openCommand(url, platform) {
28
+ const href = new URL(url).href;
29
+ switch (platform) {
6
30
  case 'darwin':
7
- return { cmd: 'open', args: [url] };
31
+ return { cmd: 'open', args: [href] };
8
32
  case 'win32':
9
- // `start` is a cmd builtin; the empty "" is the window title arg it requires.
10
- return { cmd: 'cmd', args: ['/c', 'start', '', url] };
33
+ return {
34
+ cmd: 'cmd',
35
+ args: ['/c', 'start', '""', `"${href}"`],
36
+ windowsVerbatimArguments: true,
37
+ };
11
38
  default:
12
- return { cmd: 'xdg-open', args: [url] };
39
+ return { cmd: 'xdg-open', args: [href] };
13
40
  }
14
41
  }
15
42
  /** A clack prompt resolved to a cancel symbol (Ctrl-C / Esc): print a notice and exit cleanly. */
@@ -58,8 +85,12 @@ export function createConsoleIo() {
58
85
  openBrowser(url) {
59
86
  return new Promise((resolve) => {
60
87
  try {
61
- const { cmd, args } = openCommand(url);
62
- const child = spawn(cmd, args, { stdio: 'ignore', detached: true });
88
+ const { cmd, args, windowsVerbatimArguments } = openCommand(url, process.platform);
89
+ const child = spawn(cmd, args, {
90
+ stdio: 'ignore',
91
+ detached: true,
92
+ windowsVerbatimArguments,
93
+ });
63
94
  child.on('error', () => resolve());
64
95
  child.unref();
65
96
  resolve();
package/dist/io.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/cli",
3
- "version": "0.10.3",
3
+ "version": "0.10.4",
4
4
  "description": "Bootstrap CLI for the Agent Architecture Board: scaffold a local-mode deployment (Node/local backend + frontend SPA) on your own machine — generates the crypto secrets, populates and gitignores the .env files, and mints a GitHub/GitLab personal access token by opening the browser at the right pre-scoped URL.",
5
5
  "keywords": [
6
6
  "bootstrap",