@pushto/cli 0.2.1 → 0.4.6

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 (184) hide show
  1. package/dist/commands/__tests__/deploy-domain.test.d.ts +2 -0
  2. package/dist/commands/__tests__/deploy-domain.test.d.ts.map +1 -0
  3. package/dist/commands/__tests__/deploy-domain.test.js +41 -0
  4. package/dist/commands/__tests__/deploy-domain.test.js.map +1 -0
  5. package/dist/commands/__tests__/headless-smoke.test.d.ts +2 -0
  6. package/dist/commands/__tests__/headless-smoke.test.d.ts.map +1 -0
  7. package/dist/commands/__tests__/headless-smoke.test.js +110 -0
  8. package/dist/commands/__tests__/headless-smoke.test.js.map +1 -0
  9. package/dist/commands/auth.d.ts +2 -0
  10. package/dist/commands/auth.d.ts.map +1 -0
  11. package/dist/commands/auth.js +77 -0
  12. package/dist/commands/auth.js.map +1 -0
  13. package/dist/commands/cron.d.ts +2 -0
  14. package/dist/commands/cron.d.ts.map +1 -0
  15. package/dist/commands/cron.js +157 -0
  16. package/dist/commands/cron.js.map +1 -0
  17. package/dist/commands/db.d.ts +4 -0
  18. package/dist/commands/db.d.ts.map +1 -0
  19. package/dist/commands/db.js +63 -0
  20. package/dist/commands/db.js.map +1 -0
  21. package/dist/commands/deploy.d.ts +16 -1
  22. package/dist/commands/deploy.d.ts.map +1 -1
  23. package/dist/commands/deploy.js +230 -150
  24. package/dist/commands/deploy.js.map +1 -1
  25. package/dist/commands/doctor.d.ts.map +1 -1
  26. package/dist/commands/doctor.js +289 -54
  27. package/dist/commands/doctor.js.map +1 -1
  28. package/dist/commands/domain.d.ts.map +1 -1
  29. package/dist/commands/domain.js +52 -7
  30. package/dist/commands/domain.js.map +1 -1
  31. package/dist/commands/echo.d.ts +2 -0
  32. package/dist/commands/echo.d.ts.map +1 -0
  33. package/dist/commands/echo.js +227 -0
  34. package/dist/commands/echo.js.map +1 -0
  35. package/dist/commands/env.d.ts +3 -1
  36. package/dist/commands/env.d.ts.map +1 -1
  37. package/dist/commands/env.js +76 -50
  38. package/dist/commands/env.js.map +1 -1
  39. package/dist/commands/init.d.ts +3 -1
  40. package/dist/commands/init.d.ts.map +1 -1
  41. package/dist/commands/init.js +58 -11
  42. package/dist/commands/init.js.map +1 -1
  43. package/dist/commands/login.d.ts.map +1 -1
  44. package/dist/commands/login.js +50 -23
  45. package/dist/commands/login.js.map +1 -1
  46. package/dist/commands/logs.d.ts +3 -1
  47. package/dist/commands/logs.d.ts.map +1 -1
  48. package/dist/commands/logs.js +77 -21
  49. package/dist/commands/logs.js.map +1 -1
  50. package/dist/commands/mail.d.ts +2 -0
  51. package/dist/commands/mail.d.ts.map +1 -0
  52. package/dist/commands/mail.js +105 -0
  53. package/dist/commands/mail.js.map +1 -0
  54. package/dist/commands/open.d.ts.map +1 -1
  55. package/dist/commands/open.js +21 -1
  56. package/dist/commands/open.js.map +1 -1
  57. package/dist/commands/preview.d.ts +22 -0
  58. package/dist/commands/preview.d.ts.map +1 -0
  59. package/dist/commands/preview.js +223 -0
  60. package/dist/commands/preview.js.map +1 -0
  61. package/dist/commands/status.d.ts +3 -1
  62. package/dist/commands/status.d.ts.map +1 -1
  63. package/dist/commands/status.js +62 -12
  64. package/dist/commands/status.js.map +1 -1
  65. package/dist/commands/upgrade.d.ts.map +1 -1
  66. package/dist/commands/upgrade.js +73 -10
  67. package/dist/commands/upgrade.js.map +1 -1
  68. package/dist/commands/use.d.ts +2 -0
  69. package/dist/commands/use.d.ts.map +1 -0
  70. package/dist/commands/use.js +108 -0
  71. package/dist/commands/use.js.map +1 -0
  72. package/dist/commands/vault.d.ts +2 -0
  73. package/dist/commands/vault.d.ts.map +1 -0
  74. package/dist/commands/vault.js +119 -0
  75. package/dist/commands/vault.js.map +1 -0
  76. package/dist/commands/whoami.d.ts.map +1 -1
  77. package/dist/commands/whoami.js +12 -1
  78. package/dist/commands/whoami.js.map +1 -1
  79. package/dist/index.js +117 -14
  80. package/dist/index.js.map +1 -1
  81. package/dist/lib/__tests__/build-runner.test.d.ts +2 -0
  82. package/dist/lib/__tests__/build-runner.test.d.ts.map +1 -0
  83. package/dist/lib/__tests__/build-runner.test.js +119 -0
  84. package/dist/lib/__tests__/build-runner.test.js.map +1 -0
  85. package/dist/lib/__tests__/cron-tail.test.d.ts +2 -0
  86. package/dist/lib/__tests__/cron-tail.test.d.ts.map +1 -0
  87. package/dist/lib/__tests__/cron-tail.test.js +27 -0
  88. package/dist/lib/__tests__/cron-tail.test.js.map +1 -0
  89. package/dist/lib/__tests__/detect-static-framework.test.d.ts +2 -0
  90. package/dist/lib/__tests__/detect-static-framework.test.d.ts.map +1 -0
  91. package/dist/lib/__tests__/detect-static-framework.test.js +146 -0
  92. package/dist/lib/__tests__/detect-static-framework.test.js.map +1 -0
  93. package/dist/lib/__tests__/errors.test.d.ts +2 -0
  94. package/dist/lib/__tests__/errors.test.d.ts.map +1 -0
  95. package/dist/lib/__tests__/errors.test.js +56 -0
  96. package/dist/lib/__tests__/errors.test.js.map +1 -0
  97. package/dist/lib/__tests__/interactive.test.d.ts +2 -0
  98. package/dist/lib/__tests__/interactive.test.d.ts.map +1 -0
  99. package/dist/lib/__tests__/interactive.test.js +79 -0
  100. package/dist/lib/__tests__/interactive.test.js.map +1 -0
  101. package/dist/lib/__tests__/output.test.d.ts +2 -0
  102. package/dist/lib/__tests__/output.test.d.ts.map +1 -0
  103. package/dist/lib/__tests__/output.test.js +144 -0
  104. package/dist/lib/__tests__/output.test.js.map +1 -0
  105. package/dist/lib/__tests__/prepare-artifact.test.d.ts +2 -0
  106. package/dist/lib/__tests__/prepare-artifact.test.d.ts.map +1 -0
  107. package/dist/lib/__tests__/prepare-artifact.test.js +55 -0
  108. package/dist/lib/__tests__/prepare-artifact.test.js.map +1 -0
  109. package/dist/lib/__tests__/preview-args.test.d.ts +2 -0
  110. package/dist/lib/__tests__/preview-args.test.d.ts.map +1 -0
  111. package/dist/lib/__tests__/preview-args.test.js +37 -0
  112. package/dist/lib/__tests__/preview-args.test.js.map +1 -0
  113. package/dist/lib/api.d.ts.map +1 -1
  114. package/dist/lib/api.js +22 -4
  115. package/dist/lib/api.js.map +1 -1
  116. package/dist/lib/ask.d.ts +15 -0
  117. package/dist/lib/ask.d.ts.map +1 -0
  118. package/dist/lib/ask.js +24 -0
  119. package/dist/lib/ask.js.map +1 -0
  120. package/dist/lib/build-runner.d.ts +25 -0
  121. package/dist/lib/build-runner.d.ts.map +1 -0
  122. package/dist/lib/build-runner.js +141 -0
  123. package/dist/lib/build-runner.js.map +1 -0
  124. package/dist/lib/config.d.ts +6 -0
  125. package/dist/lib/config.d.ts.map +1 -1
  126. package/dist/lib/config.js +7 -1
  127. package/dist/lib/config.js.map +1 -1
  128. package/dist/lib/cron-tail.d.ts +10 -0
  129. package/dist/lib/cron-tail.d.ts.map +1 -0
  130. package/dist/lib/cron-tail.js +5 -0
  131. package/dist/lib/cron-tail.js.map +1 -0
  132. package/dist/lib/detect-static-framework.d.ts +31 -0
  133. package/dist/lib/detect-static-framework.d.ts.map +1 -0
  134. package/dist/lib/detect-static-framework.js +96 -0
  135. package/dist/lib/detect-static-framework.js.map +1 -0
  136. package/dist/lib/env-parse.d.ts +48 -0
  137. package/dist/lib/env-parse.d.ts.map +1 -0
  138. package/dist/lib/env-parse.js +91 -0
  139. package/dist/lib/env-parse.js.map +1 -0
  140. package/dist/lib/errors.d.ts +111 -0
  141. package/dist/lib/errors.d.ts.map +1 -0
  142. package/dist/lib/errors.js +64 -0
  143. package/dist/lib/errors.js.map +1 -0
  144. package/dist/lib/file-walker.d.ts +23 -0
  145. package/dist/lib/file-walker.d.ts.map +1 -0
  146. package/dist/lib/file-walker.js +114 -0
  147. package/dist/lib/file-walker.js.map +1 -0
  148. package/dist/lib/interactive.d.ts +13 -0
  149. package/dist/lib/interactive.d.ts.map +1 -0
  150. package/dist/lib/interactive.js +24 -0
  151. package/dist/lib/interactive.js.map +1 -0
  152. package/dist/lib/output.d.ts +24 -0
  153. package/dist/lib/output.d.ts.map +1 -0
  154. package/dist/lib/output.js +71 -0
  155. package/dist/lib/output.js.map +1 -0
  156. package/dist/lib/prepare-artifact.d.ts +22 -0
  157. package/dist/lib/prepare-artifact.d.ts.map +1 -0
  158. package/dist/lib/prepare-artifact.js +26 -0
  159. package/dist/lib/prepare-artifact.js.map +1 -0
  160. package/dist/lib/preview-args.d.ts +20 -0
  161. package/dist/lib/preview-args.d.ts.map +1 -0
  162. package/dist/lib/preview-args.js +19 -0
  163. package/dist/lib/preview-args.js.map +1 -0
  164. package/dist/lib/safe-json.d.ts +7 -2
  165. package/dist/lib/safe-json.d.ts.map +1 -1
  166. package/dist/lib/safe-json.js +23 -4
  167. package/dist/lib/safe-json.js.map +1 -1
  168. package/dist/lib/update-check.d.ts +17 -0
  169. package/dist/lib/update-check.d.ts.map +1 -0
  170. package/dist/lib/update-check.js +81 -0
  171. package/dist/lib/update-check.js.map +1 -0
  172. package/dist/lib/upload-limits.d.ts +17 -0
  173. package/dist/lib/upload-limits.d.ts.map +1 -0
  174. package/dist/lib/upload-limits.js +17 -0
  175. package/dist/lib/upload-limits.js.map +1 -0
  176. package/dist/lib/zip-project.d.ts +19 -0
  177. package/dist/lib/zip-project.d.ts.map +1 -0
  178. package/dist/lib/zip-project.js +39 -0
  179. package/dist/lib/zip-project.js.map +1 -0
  180. package/dist/version.d.ts +2 -0
  181. package/dist/version.d.ts.map +1 -0
  182. package/dist/version.js +16 -0
  183. package/dist/version.js.map +1 -0
  184. package/package.json +5 -8
@@ -0,0 +1,146 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { detectStaticFramework } from '../detect-static-framework.js';
6
+ let dir;
7
+ beforeEach(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pushto-detect-')); });
8
+ afterEach(() => { fs.rmSync(dir, { recursive: true, force: true }); });
9
+ const writePkg = (pkg) => {
10
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(pkg));
11
+ };
12
+ describe('detectStaticFramework', () => {
13
+ it('detects a stock vite scaffold (no start script) as vite, spa', () => {
14
+ writePkg({ devDependencies: { vite: '^5.0.0' }, scripts: { dev: 'vite', build: 'tsc -b && vite build', preview: 'vite preview' } });
15
+ const d = detectStaticFramework(dir);
16
+ expect(d).toEqual({ framework: 'vite', spa: true, outputDirs: ['dist'] });
17
+ });
18
+ it('detects vite via config file when the dep is indirect', () => {
19
+ writePkg({ scripts: { build: 'vite build' } });
20
+ fs.writeFileSync(path.join(dir, 'vite.config.ts'), 'export default {}');
21
+ expect(detectStaticFramework(dir)?.framework).toBe('vite');
22
+ });
23
+ it('start script wins: vite + start stays dynamic (null)', () => {
24
+ writePkg({ dependencies: { vite: '^5.0.0', express: '^4.0.0' }, scripts: { build: 'vite build', start: 'node server.js' } });
25
+ expect(detectStaticFramework(dir)).toBeNull();
26
+ });
27
+ it('SSR frameworks are never static-build: next/nuxt/sveltekit/remix/solidstart', () => {
28
+ for (const deps of [
29
+ { next: '1' }, { nuxt: '1' }, { '@sveltejs/kit': '1' },
30
+ { '@remix-run/node': '1' }, { '@remix-run/dev': '1' }, { '@solidjs/start': '1' },
31
+ ]) {
32
+ writePkg({ dependencies: { ...deps, vite: '^5.0.0' }, scripts: { build: 'x' } });
33
+ expect(detectStaticFramework(dir)).toBeNull();
34
+ }
35
+ });
36
+ it('specific frameworks beat the vite catch-all', () => {
37
+ writePkg({ dependencies: { astro: '^4.0.0' }, scripts: { build: 'astro build' } });
38
+ expect(detectStaticFramework(dir)).toEqual({ framework: 'astro', spa: false, outputDirs: ['dist'] });
39
+ });
40
+ it('detects gatsby (public/), cra (build/), eleventy (_site/)', () => {
41
+ writePkg({ dependencies: { gatsby: '^5.0.0' }, scripts: { build: 'gatsby build' } });
42
+ expect(detectStaticFramework(dir)).toEqual({ framework: 'gatsby', spa: false, outputDirs: ['public'] });
43
+ writePkg({ dependencies: { 'react-scripts': '^5.0.0' }, scripts: { build: 'react-scripts build' } });
44
+ expect(detectStaticFramework(dir)).toEqual({ framework: 'cra', spa: true, outputDirs: ['build'] });
45
+ writePkg({ devDependencies: { '@11ty/eleventy': '^2.0.0' }, scripts: { build: 'eleventy' } });
46
+ expect(detectStaticFramework(dir)).toEqual({ framework: 'eleventy', spa: false, outputDirs: ['_site'] });
47
+ });
48
+ it('angular: expands output candidates from angular.json outputPath', () => {
49
+ writePkg({ dependencies: { '@angular/core': '^17.0.0' }, scripts: { build: 'ng build' } });
50
+ fs.writeFileSync(path.join(dir, 'angular.json'), JSON.stringify({
51
+ projects: { 'my-app': { architect: { build: { options: { outputPath: 'dist/my-app' } } } } },
52
+ }));
53
+ expect(detectStaticFramework(dir)).toEqual({
54
+ framework: 'angular', spa: true,
55
+ outputDirs: ['dist/my-app/browser', 'dist/my-app'],
56
+ });
57
+ });
58
+ it('angular: falls back to dist/<projectName>/browser when outputPath absent', () => {
59
+ writePkg({ dependencies: { '@angular/core': '^17.0.0' }, scripts: { build: 'ng build' } });
60
+ fs.writeFileSync(path.join(dir, 'angular.json'), JSON.stringify({
61
+ projects: { 'my-app': { architect: { build: { options: {} } } } },
62
+ }));
63
+ expect(detectStaticFramework(dir)?.outputDirs).toEqual(['dist/my-app/browser', 'dist/my-app']);
64
+ });
65
+ it('no package.json → null; malformed package.json → null', () => {
66
+ expect(detectStaticFramework(dir)).toBeNull();
67
+ fs.writeFileSync(path.join(dir, 'package.json'), '{nope');
68
+ expect(detectStaticFramework(dir)).toBeNull();
69
+ });
70
+ });
71
+ describe('detectStaticFramework — stock dev-server start scripts do not defeat detection', () => {
72
+ // Stock scaffolds ship a `start` script that runs the framework's OWN
73
+ // dev server, not an app server: CRA `react-scripts start`, Angular
74
+ // `ng serve`, Gatsby `gatsby develop`, Eleventy `eleventy --serve`. The
75
+ // old rule ("any start script means dynamic") routed every one of these
76
+ // past the static-build path even though none of them run a real server.
77
+ it('real CRA script block (react-scripts start/build/test/eject) is still detected as cra', () => {
78
+ writePkg({
79
+ dependencies: { 'react-scripts': '^5.0.0' },
80
+ scripts: {
81
+ start: 'react-scripts start',
82
+ build: 'react-scripts build',
83
+ test: 'react-scripts test',
84
+ eject: 'react-scripts eject',
85
+ },
86
+ });
87
+ expect(detectStaticFramework(dir)).toEqual({ framework: 'cra', spa: true, outputDirs: ['build'] });
88
+ });
89
+ it('real Angular script block (ng serve) is still detected as angular', () => {
90
+ writePkg({
91
+ dependencies: { '@angular/core': '^17.0.0' },
92
+ scripts: { ng: 'ng', start: 'ng serve', build: 'ng build' },
93
+ });
94
+ expect(detectStaticFramework(dir)?.framework).toBe('angular');
95
+ });
96
+ it('real Gatsby script block (gatsby develop) is still detected as gatsby', () => {
97
+ writePkg({
98
+ dependencies: { gatsby: '^5.0.0' },
99
+ scripts: { develop: 'gatsby develop', start: 'gatsby develop', build: 'gatsby build' },
100
+ });
101
+ expect(detectStaticFramework(dir)).toEqual({ framework: 'gatsby', spa: false, outputDirs: ['public'] });
102
+ });
103
+ it('real Eleventy script block (eleventy --serve) is still detected as eleventy', () => {
104
+ writePkg({
105
+ devDependencies: { '@11ty/eleventy': '^2.0.0' },
106
+ scripts: { build: 'eleventy', start: 'eleventy --serve' },
107
+ });
108
+ expect(detectStaticFramework(dir)).toEqual({ framework: 'eleventy', spa: false, outputDirs: ['_site'] });
109
+ });
110
+ it('eleventy-base-blog real scaffold: npx-prefixed start script stays static-build', () => {
111
+ writePkg({
112
+ devDependencies: { '@11ty/eleventy': '^3.0.0' },
113
+ scripts: { build: 'npx @11ty/eleventy', start: 'npx @11ty/eleventy --serve --quiet' },
114
+ });
115
+ expect(detectStaticFramework(dir)?.framework).toBe('eleventy');
116
+ });
117
+ it('cra with a CUSTOM start script stays dynamic (null)', () => {
118
+ writePkg({
119
+ dependencies: { 'react-scripts': '^5.0.0' },
120
+ scripts: { start: 'node server.js', build: 'react-scripts build' },
121
+ });
122
+ expect(detectStaticFramework(dir)).toBeNull();
123
+ });
124
+ it('vite + start script that is just "vite preview" is still static-build (own dev server)', () => {
125
+ writePkg({
126
+ dependencies: { vite: '^5.0.0' },
127
+ scripts: { build: 'vite build', start: 'vite preview' },
128
+ });
129
+ expect(detectStaticFramework(dir)?.framework).toBe('vite');
130
+ });
131
+ it('vite + start script with extra flags still counts as the dev server (word-boundary match)', () => {
132
+ writePkg({
133
+ dependencies: { vite: '^5.0.0' },
134
+ scripts: { build: 'vite build', start: 'vite preview --port 4173' },
135
+ });
136
+ expect(detectStaticFramework(dir)?.framework).toBe('vite');
137
+ });
138
+ it('vite + a lookalike start script that only shares a prefix is NOT a word-boundary match (stays dynamic)', () => {
139
+ writePkg({
140
+ dependencies: { vite: '^5.0.0' },
141
+ scripts: { build: 'vite build', start: 'vite-custom-wrapper.js' },
142
+ });
143
+ expect(detectStaticFramework(dir)).toBeNull();
144
+ });
145
+ });
146
+ //# sourceMappingURL=detect-static-framework.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-static-framework.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/detect-static-framework.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=errors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/errors.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CODES, EXIT, exitCodeFor, isRetryable, buildError } from '../errors.js';
3
+ /**
4
+ * PINs the exit-code contract that makes the CLI machine-consumable.
5
+ *
6
+ * Before this existed, 112 of the CLI's 113 process.exit() calls resolved
7
+ * to 1, so a caller reading $? could not tell "your repo is broken" from
8
+ * "our server blipped". The registry is closed and the band is DERIVED
9
+ * from the code precisely so no future call site gets to pick a number.
10
+ *
11
+ * The "never 1" assertion is the load-bearing one: 1 is reserved for
12
+ * genuinely unclassified failures, so any KNOWN code reaching it means
13
+ * someone added a code without deciding what it means.
14
+ */
15
+ describe('exit code registry', () => {
16
+ it('derives a band for every registered code', () => {
17
+ for (const code of Object.keys(CODES)) {
18
+ expect(typeof exitCodeFor(code)).toBe('number');
19
+ }
20
+ });
21
+ it('never maps a known code to the unclassified band', () => {
22
+ for (const code of Object.keys(CODES)) {
23
+ expect(exitCodeFor(code)).not.toBe(EXIT.UNCLASSIFIED);
24
+ }
25
+ });
26
+ it('marks upstream failures retryable and local failures not', () => {
27
+ expect(isRetryable('NETWORK')).toBe(true);
28
+ expect(isRetryable('SERVER_ERROR')).toBe(true);
29
+ expect(isRetryable('ARTIFACT_TOO_LARGE')).toBe(false);
30
+ expect(isRetryable('NOT_AUTHENTICATED')).toBe(false);
31
+ });
32
+ it('puts auth at 10, local input at 30, quota at 50, upstream at 60', () => {
33
+ expect(exitCodeFor('NOT_AUTHENTICATED')).toBe(10);
34
+ expect(exitCodeFor('MISSING_ENTRYPOINT')).toBe(30);
35
+ expect(exitCodeFor('PAID_FEATURE')).toBe(50);
36
+ expect(exitCodeFor('NETWORK')).toBe(60);
37
+ });
38
+ it('builds an error carrying its own retryable bit', () => {
39
+ const err = buildError('NETWORK', "couldn't reach pushto.host.", {
40
+ fix: { label: 'try again', cmd: 'pushto deploy' },
41
+ });
42
+ expect(err).toEqual({
43
+ code: 'NETWORK',
44
+ human: "couldn't reach pushto.host.",
45
+ retryable: true,
46
+ fix: { label: 'try again', cmd: 'pushto deploy' },
47
+ });
48
+ });
49
+ it('omits optional keys it was not given', () => {
50
+ const err = buildError('NO_PROJECT', 'no project here.');
51
+ expect(err).toEqual({ code: 'NO_PROJECT', human: 'no project here.', retryable: false });
52
+ expect('fix' in err).toBe(false);
53
+ expect('stage' in err).toBe(false);
54
+ });
55
+ });
56
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/errors.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=interactive.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/interactive.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,79 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { canPrompt } from '../interactive.js';
3
+ /**
4
+ * PINs the rule that an agent gets correct behavior with ZERO flags.
5
+ *
6
+ * Requiring --yes would not have fixed the deploy hang, because an agent
7
+ * that has never read our docs does not know the flag exists. So prompting
8
+ * is RESOLVED from ambient state, and a flag can only ever turn it further
9
+ * off. Every branch below is a real way a machine invokes us.
10
+ */
11
+ const orig = {
12
+ stdin: process.stdin.isTTY,
13
+ stdout: process.stdout.isTTY,
14
+ ci: process.env.CI,
15
+ ni: process.env.PUSHTO_NONINTERACTIVE,
16
+ };
17
+ const setTTY = (stdin, stdout) => {
18
+ Object.defineProperty(process.stdin, 'isTTY', { value: stdin, configurable: true });
19
+ Object.defineProperty(process.stdout, 'isTTY', { value: stdout, configurable: true });
20
+ };
21
+ afterEach(() => {
22
+ setTTY(orig.stdin, orig.stdout);
23
+ if (orig.ci === undefined)
24
+ delete process.env.CI;
25
+ else
26
+ process.env.CI = orig.ci;
27
+ if (orig.ni === undefined)
28
+ delete process.env.PUSHTO_NONINTERACTIVE;
29
+ else
30
+ process.env.PUSHTO_NONINTERACTIVE = orig.ni;
31
+ });
32
+ describe('canPrompt', () => {
33
+ it('allows prompting for a human on a full terminal', () => {
34
+ setTTY(true, true);
35
+ delete process.env.CI;
36
+ delete process.env.PUSHTO_NONINTERACTIVE;
37
+ expect(canPrompt()).toBe(true);
38
+ });
39
+ it('refuses when stdin is not a tty (the agent case)', () => {
40
+ setTTY(false, true);
41
+ delete process.env.CI;
42
+ delete process.env.PUSHTO_NONINTERACTIVE;
43
+ expect(canPrompt()).toBe(false);
44
+ });
45
+ it('refuses when stdout is piped', () => {
46
+ setTTY(true, false);
47
+ delete process.env.CI;
48
+ delete process.env.PUSHTO_NONINTERACTIVE;
49
+ expect(canPrompt()).toBe(false);
50
+ });
51
+ it('refuses under CI', () => {
52
+ setTTY(true, true);
53
+ process.env.CI = '1';
54
+ delete process.env.PUSHTO_NONINTERACTIVE;
55
+ expect(canPrompt()).toBe(false);
56
+ });
57
+ it('refuses under PUSHTO_NONINTERACTIVE', () => {
58
+ setTTY(true, true);
59
+ delete process.env.CI;
60
+ process.env.PUSHTO_NONINTERACTIVE = '1';
61
+ expect(canPrompt()).toBe(false);
62
+ });
63
+ it('refuses when --json or --yes was passed, even on a real terminal', () => {
64
+ setTTY(true, true);
65
+ delete process.env.CI;
66
+ delete process.env.PUSHTO_NONINTERACTIVE;
67
+ expect(canPrompt({ json: true })).toBe(false);
68
+ expect(canPrompt({ yes: true })).toBe(false);
69
+ });
70
+ it('treats CI="" and CI="false" as not set, matching shell convention', () => {
71
+ setTTY(true, true);
72
+ delete process.env.PUSHTO_NONINTERACTIVE;
73
+ process.env.CI = '';
74
+ expect(canPrompt()).toBe(true);
75
+ process.env.CI = 'false';
76
+ expect(canPrompt()).toBe(true);
77
+ });
78
+ });
79
+ //# sourceMappingURL=interactive.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/interactive.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=output.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/output.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,144 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest';
2
+ import { emitOk, emitErr, progress, spinnerStream } from '../output.js';
3
+ import { buildError } from '../errors.js';
4
+ /**
5
+ * PINs stdout purity under --json.
6
+ *
7
+ * The contract an agent depends on is `pushto deploy --json | jq` working
8
+ * with no filtering, which means stdout carries EXACTLY one JSON object and
9
+ * nothing else. ora writes to stdout by default in every spine command, so
10
+ * a single un-redirected spinner frame is enough to corrupt the payload —
11
+ * that is what the spinnerStream assertion guards.
12
+ */
13
+ const captureStdout = () => {
14
+ let buf = '';
15
+ const spy = vi.spyOn(process.stdout, 'write').mockImplementation((chunk) => {
16
+ buf += String(chunk);
17
+ return true;
18
+ });
19
+ return { text: () => buf, restore: () => spy.mockRestore() };
20
+ };
21
+ const captureStderr = () => {
22
+ let buf = '';
23
+ const spy = vi.spyOn(process.stderr, 'write').mockImplementation((chunk) => {
24
+ buf += String(chunk);
25
+ return true;
26
+ });
27
+ return { text: () => buf, restore: () => spy.mockRestore() };
28
+ };
29
+ afterEach(() => vi.restoreAllMocks());
30
+ describe('json mode', () => {
31
+ it('writes exactly one parseable object to stdout', () => {
32
+ const out = captureStdout();
33
+ emitOk({ url: 'https://x.pushto.host' }, { json: true });
34
+ const text = out.text();
35
+ out.restore();
36
+ expect(() => JSON.parse(text)).not.toThrow();
37
+ expect(JSON.parse(text)).toEqual({ ok: true, url: 'https://x.pushto.host' });
38
+ });
39
+ it('routes progress to stderr, never stdout', () => {
40
+ const out = captureStdout();
41
+ const err = captureStderr();
42
+ progress('zipping project...', { json: true });
43
+ const stdout = out.text();
44
+ const stderr = err.text();
45
+ out.restore();
46
+ err.restore();
47
+ expect(stdout).toBe('');
48
+ expect(stderr).toContain('zipping project');
49
+ });
50
+ it('serialises an error with its code, retryable bit and fix', () => {
51
+ const out = captureStdout();
52
+ emitErr(buildError('MISSING_ENTRYPOINT', 'no package.json in the repo root.', {
53
+ stage: 'build',
54
+ fix: { label: 'point at the subfolder', cmd: 'pushto deploy --root ./app' },
55
+ }), { json: true });
56
+ const text = out.text();
57
+ out.restore();
58
+ expect(JSON.parse(text)).toEqual({
59
+ ok: false,
60
+ stage: 'build',
61
+ retryable: false,
62
+ error: {
63
+ code: 'MISSING_ENTRYPOINT',
64
+ human: 'no package.json in the repo root.',
65
+ fix: { label: 'point at the subfolder', cmd: 'pushto deploy --root ./app' },
66
+ },
67
+ });
68
+ });
69
+ it('points spinners at stderr in json mode and stdout otherwise', () => {
70
+ expect(spinnerStream({ json: true })).toBe(process.stderr);
71
+ expect(spinnerStream({})).toBe(process.stdout);
72
+ });
73
+ });
74
+ describe('human mode', () => {
75
+ it('prints prose to stdout and never emits json', () => {
76
+ const out = captureStdout();
77
+ emitOk({ url: 'https://x.pushto.host', human: 'live at https://x.pushto.host' }, {});
78
+ const text = out.text();
79
+ out.restore();
80
+ expect(text).toContain('live at https://x.pushto.host');
81
+ expect(text.trim().startsWith('{')).toBe(false);
82
+ });
83
+ it('prints the fix command under the error', () => {
84
+ const err = captureStderr();
85
+ emitErr(buildError('NO_PROJECT', 'no project here.', {
86
+ fix: { label: 'get started', cmd: 'pushto init <name>' },
87
+ }), {});
88
+ const text = err.text();
89
+ err.restore();
90
+ expect(text).toContain('no project here.');
91
+ expect(text).toContain('pushto init <name>');
92
+ });
93
+ /**
94
+ * `label: cmd` cannot express a sentence with words AFTER the command, so
95
+ * adopting the structured shape silently rewrote hand-written copy —
96
+ * "run pushto login first." became "sign in: pushto login". `prose` keeps
97
+ * the original sentence while agents still read label/cmd.
98
+ */
99
+ it('reproduces hand-written prose verbatim, placing the command inline', () => {
100
+ const err = captureStderr();
101
+ emitErr(buildError('NOT_AUTHENTICATED', 'not logged in.', {
102
+ fix: { label: 'sign in', cmd: 'pushto login', prose: 'run {cmd} first.' },
103
+ }), {});
104
+ const text = err.text();
105
+ err.restore();
106
+ // eslint-disable-next-line no-control-regex -- strip ANSI to compare the sentence itself
107
+ const plain = text.replace(/\[[0-9;]*m/g, '');
108
+ expect(plain).toBe('> not logged in.\n run pushto login first.\n');
109
+ });
110
+ it('falls back to "label: cmd" when no prose is supplied', () => {
111
+ const err = captureStderr();
112
+ emitErr(buildError('NO_PROJECT', 'no project here.', {
113
+ fix: { label: 'get started', cmd: 'pushto init <name>' },
114
+ }), {});
115
+ const text = err.text();
116
+ err.restore();
117
+ // eslint-disable-next-line no-control-regex -- strip ANSI to compare the sentence itself
118
+ const plain = text.replace(/\[[0-9;]*m/g, '');
119
+ expect(plain).toBe('> no project here.\n get started: pushto init <name>\n');
120
+ });
121
+ });
122
+ describe('prose never reaches machine output', () => {
123
+ it('strips the {cmd} placeholder field from the json fix object', () => {
124
+ const out = captureStdout();
125
+ emitErr(buildError('NOT_AUTHENTICATED', 'not logged in.', {
126
+ stage: 'auth',
127
+ fix: { label: 'sign in', cmd: 'pushto login', prose: 'run {cmd} first.' },
128
+ }), { json: true });
129
+ const text = out.text();
130
+ out.restore();
131
+ expect(text).not.toContain('{cmd}');
132
+ expect(JSON.parse(text)).toEqual({
133
+ ok: false,
134
+ stage: 'auth',
135
+ retryable: false,
136
+ error: {
137
+ code: 'NOT_AUTHENTICATED',
138
+ human: 'not logged in.',
139
+ fix: { label: 'sign in', cmd: 'pushto login' },
140
+ },
141
+ });
142
+ });
143
+ });
144
+ //# sourceMappingURL=output.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/output.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=prepare-artifact.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-artifact.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/prepare-artifact.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { prepareArtifact } from '../prepare-artifact.js';
6
+ import { ARTIFACT_META_NAME } from '../build-runner.js';
7
+ let dir;
8
+ beforeEach(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pushto-prep-')); });
9
+ afterEach(() => {
10
+ fs.rmSync(dir, { recursive: true, force: true });
11
+ // Remove all exit listeners added during this test to avoid leaking listeners
12
+ // between tests. Vitest runs this in a worker, but exit hooks persist in the
13
+ // process, so we clean up to avoid interference with later tests.
14
+ process.removeAllListeners('exit');
15
+ });
16
+ describe('prepareArtifact', () => {
17
+ it('non-framework project passes through as source', async () => {
18
+ fs.writeFileSync(path.join(dir, 'index.html'), '<h1>hi</h1>');
19
+ const r = await prepareArtifact(dir, () => undefined);
20
+ expect(r).toEqual({ kind: 'source', zipDir: dir });
21
+ });
22
+ it('framework project builds and returns the artifact dir with the meta marker present', async () => {
23
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({
24
+ devDependencies: { vite: '^5.0.0' },
25
+ scripts: { build: 'node -e "require(\'fs\').mkdirSync(\'dist\',{recursive:true});require(\'fs\').writeFileSync(\'dist/index.html\',\'built\')"' },
26
+ }));
27
+ fs.mkdirSync(path.join(dir, 'node_modules'), { recursive: true });
28
+ const beforeListenerCount = process.listenerCount('exit');
29
+ const r = await prepareArtifact(dir, () => undefined);
30
+ expect(r.kind).toBe('artifact');
31
+ if (r.kind === 'artifact') {
32
+ // Verify exit hook was registered
33
+ expect(process.listenerCount('exit')).toBe(beforeListenerCount + 1);
34
+ expect(r.framework).toBe('vite');
35
+ expect(r.zipDir).toBe(path.join(dir, 'dist'));
36
+ const meta = JSON.parse(fs.readFileSync(path.join(r.zipDir, ARTIFACT_META_NAME), 'utf-8'));
37
+ expect(meta).toMatchObject({ framework: 'vite', spa: true });
38
+ // Verify cleanup is idempotent — calling twice should not throw and marker should stay gone
39
+ r.cleanup();
40
+ expect(fs.existsSync(path.join(r.zipDir, ARTIFACT_META_NAME))).toBe(false);
41
+ r.cleanup(); // Second call should not throw
42
+ expect(fs.existsSync(path.join(r.zipDir, ARTIFACT_META_NAME))).toBe(false);
43
+ }
44
+ });
45
+ it('framework project with a failing build returns failed and writes no meta', async () => {
46
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({
47
+ devDependencies: { vite: '^5.0.0' },
48
+ scripts: { build: 'node -e "process.exit(1)"' },
49
+ }));
50
+ fs.mkdirSync(path.join(dir, 'node_modules'), { recursive: true });
51
+ const r = await prepareArtifact(dir, () => undefined);
52
+ expect(r.kind).toBe('failed');
53
+ });
54
+ });
55
+ //# sourceMappingURL=prepare-artifact.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-artifact.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/prepare-artifact.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,IAAI,GAAW,CAAC;AAChB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpF,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,8EAA8E;IAC9E,6EAA6E;IAC7E,kEAAkE;IAClE,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,aAAa,CAAC,CAAC;QAC9D,MAAM,CAAC,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QAClG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;YAC9D,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACnC,OAAO,EAAE,EAAE,KAAK,EAAE,6HAA6H,EAAE;SAClJ,CAAC,CAAC,CAAC;QACJ,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC1D,MAAM,CAAC,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChC,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC1B,kCAAkC;YAClC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,CAAC,CAAC;YAEpE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YAC3F,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YAE7D,4FAA4F;YAC5F,CAAC,CAAC,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3E,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,+BAA+B;YAC5C,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;YAC9D,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACnC,OAAO,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE;SAChD,CAAC,CAAC,CAAC;QACJ,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=preview-args.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-args.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/preview-args.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { resolvePreviewAction } from '../preview-args.js';
3
+ /**
4
+ * PINs for the `pushto preview` dispatcher's action grammar.
5
+ *
6
+ * docs/cli and the command's own help have taught "(create, ls, rm)" since
7
+ * the command shipped — but the dispatcher treated ANY unknown action word
8
+ * as a directory, so the documented `pushto preview create --branch x`
9
+ * died with "not a directory: create". The verb now exists; a positional
10
+ * directory still works.
11
+ */
12
+ describe('resolvePreviewAction', () => {
13
+ it('bare invocation creates from the current directory', () => {
14
+ expect(resolvePreviewAction('', [])).toEqual({ kind: 'create', dir: '.' });
15
+ });
16
+ it('the documented `create` verb creates from the current directory', () => {
17
+ expect(resolvePreviewAction('create', [])).toEqual({ kind: 'create', dir: '.' });
18
+ });
19
+ it('`create <dir>` targets that directory', () => {
20
+ expect(resolvePreviewAction('create', ['dist'])).toEqual({ kind: 'create', dir: 'dist' });
21
+ });
22
+ it('a bare positional directory still works (pushto preview dist)', () => {
23
+ expect(resolvePreviewAction('dist', [])).toEqual({ kind: 'create', dir: 'dist' });
24
+ });
25
+ it('ls and list both list', () => {
26
+ expect(resolvePreviewAction('ls', [])).toEqual({ kind: 'ls' });
27
+ expect(resolvePreviewAction('list', [])).toEqual({ kind: 'ls' });
28
+ });
29
+ it('rm and delete both remove, carrying the ref', () => {
30
+ expect(resolvePreviewAction('rm', ['feature-x'])).toEqual({ kind: 'rm', ref: 'feature-x' });
31
+ expect(resolvePreviewAction('delete', ['abc123'])).toEqual({ kind: 'rm', ref: 'abc123' });
32
+ });
33
+ it('rm without a ref reports the miss instead of guessing', () => {
34
+ expect(resolvePreviewAction('rm', [])).toEqual({ kind: 'rm', ref: undefined });
35
+ });
36
+ });
37
+ //# sourceMappingURL=preview-args.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-args.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/preview-args.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;;;;;;GAQG;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,oBAAoB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5F,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AA+CA,eAAO,MAAM,GAAG,GAAU,MAAM,MAAM,EAAE,UAAS,WAAgB,KAAG,OAAO,CAAC,QAAQ,CAyBnF,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,QAAO,WAAqD,CAAC"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAgEA,eAAO,MAAM,GAAG,GAAU,MAAM,MAAM,EAAE,UAAS,WAAgB,KAAG,OAAO,CAAC,QAAQ,CA4BnF,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,QAAO,WAAqD,CAAC"}