@uluops/setup 0.2.0 → 0.6.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 (253) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +109 -89
  3. package/assets/auto-tracker-save.mjs +142 -0
  4. package/assets/claude-code/agents/anxiety-reader-agent.md +464 -0
  5. package/assets/{agents → claude-code/agents}/api-contract-validator-agent.md +9 -228
  6. package/assets/{agents → claude-code/agents}/aristotle-analyst-agent.md +51 -4
  7. package/assets/{agents → claude-code/agents}/aristotle-explorer-agent.md +6 -2
  8. package/assets/{agents → claude-code/agents}/aristotle-forecaster-agent.md +15 -230
  9. package/assets/{agents → claude-code/agents}/aristotle-validator-agent.md +12 -252
  10. package/assets/{agents → claude-code/agents}/assumption-excavator-agent.md +21 -247
  11. package/assets/{agents → claude-code/agents}/code-auditor-agent.md +12 -255
  12. package/assets/{agents → claude-code/agents}/code-optimizer-agent.md +15 -236
  13. package/assets/{agents → claude-code/agents}/code-validator-agent.md +31 -300
  14. package/assets/claude-code/agents/docs-validator-agent.md +472 -0
  15. package/assets/{agents → claude-code/agents}/frontend-validator-agent.md +15 -258
  16. package/assets/{agents → claude-code/agents}/mcp-validator-agent.md +8 -252
  17. package/assets/{agents → claude-code/agents}/pre-implementation-architect-agent.md +8 -224
  18. package/assets/{agents → claude-code/agents}/prompt-engineer-agent.md +57 -290
  19. package/assets/{agents → claude-code/agents}/prompt-pattern-analyzer-agent.md +10 -225
  20. package/assets/{agents → claude-code/agents}/prompt-quality-validator-agent.md +11 -249
  21. package/assets/{agents → claude-code/agents}/public-interface-validator-agent.md +15 -268
  22. package/assets/claude-code/agents/release-readiness-agent.md +495 -0
  23. package/assets/{agents → claude-code/agents}/security-analyst-agent.md +236 -480
  24. package/assets/{agents → claude-code/agents}/test-architect-agent.md +16 -259
  25. package/assets/{agents → claude-code/agents}/type-safety-validator-agent.md +23 -266
  26. package/assets/{agents → claude-code/agents}/workflow-synthesis-agent.md +23 -226
  27. package/assets/claude-code/commands/agents/anxiety-reader.md +157 -0
  28. package/assets/{commands → claude-code/commands}/agents/api-contract.md +156 -135
  29. package/assets/{commands → claude-code/commands}/agents/architect.md +156 -135
  30. package/assets/claude-code/commands/agents/aristotle-analyst.md +157 -0
  31. package/assets/claude-code/commands/agents/aristotle-explorer.md +157 -0
  32. package/assets/claude-code/commands/agents/aristotle-forecaster.md +157 -0
  33. package/assets/claude-code/commands/agents/aristotle-validator.md +157 -0
  34. package/assets/{commands → claude-code/commands}/agents/assumption-excavator.md +49 -6
  35. package/assets/{commands → claude-code/commands}/agents/audit.md +156 -136
  36. package/assets/{commands → claude-code/commands}/agents/docs-validate.md +156 -133
  37. package/assets/{commands → claude-code/commands}/agents/frontend.md +156 -135
  38. package/assets/{commands → claude-code/commands}/agents/mcp-validate.md +156 -136
  39. package/assets/{commands → claude-code/commands}/agents/optimize.md +156 -133
  40. package/assets/{commands → claude-code/commands}/agents/pattern-analyzer.md +150 -126
  41. package/assets/{commands → claude-code/commands}/agents/prompt-quality.md +155 -134
  42. package/assets/claude-code/commands/agents/prompt-validate.md +155 -0
  43. package/assets/{commands → claude-code/commands}/agents/public-interface.md +156 -134
  44. package/assets/{commands → claude-code/commands}/agents/release.md +156 -135
  45. package/assets/{commands → claude-code/commands}/agents/security.md +156 -137
  46. package/assets/{commands → claude-code/commands}/agents/test-review.md +156 -136
  47. package/assets/{commands → claude-code/commands}/agents/type-safety.md +156 -135
  48. package/assets/{commands → claude-code/commands}/agents/validate.md +156 -134
  49. package/assets/claude-code/commands/agents/workflow-synthesis.md +157 -0
  50. package/assets/claude-code/commands/pipelines/aristotle.md +143 -0
  51. package/assets/claude-code/commands/pipelines/ship.md +188 -0
  52. package/assets/claude-code/commands/workflows/post-implementation.md +60 -0
  53. package/assets/claude-code/commands/workflows/pre-implementation.md +46 -0
  54. package/assets/claude-code/commands/workflows/prompt-audit.md +44 -0
  55. package/assets/codex/agents/anxiety-reader-agent.toml +462 -0
  56. package/assets/codex/agents/api-contract-validator-agent.toml +738 -0
  57. package/assets/codex/agents/aristotle-analyst-agent.toml +750 -0
  58. package/assets/codex/agents/aristotle-explorer-agent.toml +155 -0
  59. package/assets/codex/agents/aristotle-forecaster-agent.toml +449 -0
  60. package/assets/codex/agents/aristotle-validator-agent.toml +424 -0
  61. package/assets/codex/agents/assumption-excavator-agent.toml +1126 -0
  62. package/assets/codex/agents/code-auditor-agent.toml +815 -0
  63. package/assets/codex/agents/code-optimizer-agent.toml +652 -0
  64. package/assets/codex/agents/code-validator-agent.toml +573 -0
  65. package/assets/codex/agents/docs-validator-agent.toml +468 -0
  66. package/assets/codex/agents/frontend-validator-agent.toml +598 -0
  67. package/assets/codex/agents/mcp-validator-agent.toml +580 -0
  68. package/assets/codex/agents/pre-implementation-architect-agent.toml +817 -0
  69. package/assets/codex/agents/prompt-engineer-agent.toml +922 -0
  70. package/assets/codex/agents/prompt-pattern-analyzer-agent.toml +689 -0
  71. package/assets/codex/agents/prompt-quality-validator-agent.toml +777 -0
  72. package/assets/codex/agents/public-interface-validator-agent.toml +695 -0
  73. package/assets/codex/agents/release-readiness-agent.toml +491 -0
  74. package/assets/codex/agents/security-analyst-agent.toml +847 -0
  75. package/assets/codex/agents/test-architect-agent.toml +615 -0
  76. package/assets/codex/agents/type-safety-validator-agent.toml +686 -0
  77. package/assets/codex/agents/workflow-synthesis-agent.toml +631 -0
  78. package/assets/gemini-cli/agents/anxiety-reader-agent.md +470 -0
  79. package/assets/gemini-cli/agents/api-contract-validator-agent.md +747 -0
  80. package/assets/gemini-cli/agents/aristotle-analyst-agent.md +758 -0
  81. package/assets/gemini-cli/agents/aristotle-explorer-agent.md +163 -0
  82. package/assets/gemini-cli/agents/aristotle-forecaster-agent.md +457 -0
  83. package/assets/gemini-cli/agents/aristotle-validator-agent.md +432 -0
  84. package/assets/gemini-cli/agents/assumption-excavator-agent.md +1134 -0
  85. package/assets/gemini-cli/agents/code-auditor-agent.md +827 -0
  86. package/assets/gemini-cli/agents/code-optimizer-agent.md +661 -0
  87. package/assets/gemini-cli/agents/code-validator-agent.md +582 -0
  88. package/assets/gemini-cli/agents/docs-validator-agent.md +477 -0
  89. package/assets/gemini-cli/agents/frontend-validator-agent.md +610 -0
  90. package/assets/gemini-cli/agents/mcp-validator-agent.md +589 -0
  91. package/assets/gemini-cli/agents/pre-implementation-architect-agent.md +826 -0
  92. package/assets/gemini-cli/agents/prompt-engineer-agent.md +931 -0
  93. package/assets/gemini-cli/agents/prompt-pattern-analyzer-agent.md +698 -0
  94. package/assets/gemini-cli/agents/prompt-quality-validator-agent.md +786 -0
  95. package/assets/gemini-cli/agents/public-interface-validator-agent.md +707 -0
  96. package/assets/gemini-cli/agents/release-readiness-agent.md +500 -0
  97. package/assets/gemini-cli/agents/security-analyst-agent.md +859 -0
  98. package/assets/gemini-cli/agents/test-architect-agent.md +624 -0
  99. package/assets/gemini-cli/agents/type-safety-validator-agent.md +695 -0
  100. package/assets/gemini-cli/agents/workflow-synthesis-agent.md +639 -0
  101. package/assets/gemini-cli/commands/agents/anxiety-reader.toml +155 -0
  102. package/assets/gemini-cli/commands/agents/api-contract.toml +154 -0
  103. package/assets/gemini-cli/commands/agents/architect.toml +154 -0
  104. package/assets/gemini-cli/commands/agents/aristotle-analyst.toml +155 -0
  105. package/assets/gemini-cli/commands/agents/aristotle-explorer.toml +155 -0
  106. package/assets/gemini-cli/commands/agents/aristotle-forecaster.toml +155 -0
  107. package/assets/gemini-cli/commands/agents/aristotle-validator.toml +155 -0
  108. package/assets/gemini-cli/commands/agents/assumption-excavator.toml +155 -0
  109. package/assets/gemini-cli/commands/agents/audit.toml +154 -0
  110. package/assets/gemini-cli/commands/agents/docs-validate.toml +154 -0
  111. package/assets/gemini-cli/commands/agents/frontend.toml +154 -0
  112. package/assets/gemini-cli/commands/agents/mcp-validate.toml +154 -0
  113. package/assets/gemini-cli/commands/agents/optimize.toml +154 -0
  114. package/assets/gemini-cli/commands/agents/pattern-analyzer.toml +148 -0
  115. package/assets/gemini-cli/commands/agents/prompt-quality.toml +153 -0
  116. package/assets/gemini-cli/commands/agents/prompt-validate.toml +153 -0
  117. package/assets/gemini-cli/commands/agents/public-interface.toml +154 -0
  118. package/assets/gemini-cli/commands/agents/release.toml +154 -0
  119. package/assets/gemini-cli/commands/agents/security.toml +154 -0
  120. package/assets/gemini-cli/commands/agents/test-review.toml +154 -0
  121. package/assets/gemini-cli/commands/agents/type-safety.toml +154 -0
  122. package/assets/gemini-cli/commands/agents/validate.toml +154 -0
  123. package/assets/gemini-cli/commands/agents/workflow-synthesis.toml +155 -0
  124. package/assets/gemini-cli/commands/pipelines/aristotle.toml +139 -0
  125. package/assets/gemini-cli/commands/pipelines/ship.toml +184 -0
  126. package/assets/gemini-cli/commands/workflows/post-implementation.toml +56 -0
  127. package/assets/gemini-cli/commands/workflows/pre-implementation.toml +42 -0
  128. package/assets/gemini-cli/commands/workflows/prompt-audit.toml +40 -0
  129. package/assets/opencode/agents/anxiety-reader-agent.md +472 -0
  130. package/assets/opencode/agents/api-contract-validator-agent.md +749 -0
  131. package/assets/opencode/agents/aristotle-analyst-agent.md +760 -0
  132. package/assets/opencode/agents/aristotle-explorer-agent.md +164 -0
  133. package/assets/opencode/agents/aristotle-forecaster-agent.md +459 -0
  134. package/assets/opencode/agents/aristotle-validator-agent.md +434 -0
  135. package/assets/opencode/agents/assumption-excavator-agent.md +1136 -0
  136. package/assets/opencode/agents/code-auditor-agent.md +826 -0
  137. package/assets/opencode/agents/code-optimizer-agent.md +663 -0
  138. package/assets/opencode/agents/code-validator-agent.md +584 -0
  139. package/assets/opencode/agents/docs-validator-agent.md +479 -0
  140. package/assets/opencode/agents/frontend-validator-agent.md +609 -0
  141. package/assets/opencode/agents/mcp-validator-agent.md +591 -0
  142. package/assets/opencode/agents/pre-implementation-architect-agent.md +828 -0
  143. package/assets/opencode/agents/prompt-engineer-agent.md +933 -0
  144. package/assets/opencode/agents/prompt-pattern-analyzer-agent.md +700 -0
  145. package/assets/opencode/agents/prompt-quality-validator-agent.md +788 -0
  146. package/assets/opencode/agents/public-interface-validator-agent.md +706 -0
  147. package/assets/opencode/agents/release-readiness-agent.md +502 -0
  148. package/assets/opencode/agents/security-analyst-agent.md +858 -0
  149. package/assets/opencode/agents/test-architect-agent.md +626 -0
  150. package/assets/opencode/agents/type-safety-validator-agent.md +697 -0
  151. package/assets/opencode/agents/workflow-synthesis-agent.md +641 -0
  152. package/dist/cli.js +22 -380
  153. package/dist/commands/helpers.d.ts +73 -0
  154. package/dist/commands/helpers.js +274 -0
  155. package/dist/commands/setup.d.ts +13 -0
  156. package/dist/commands/setup.js +93 -0
  157. package/dist/commands/uninstall.d.ts +3 -0
  158. package/dist/commands/uninstall.js +126 -0
  159. package/dist/commands/verify.d.ts +1 -0
  160. package/dist/commands/verify.js +28 -0
  161. package/dist/harnesses/claude-code.d.ts +8 -0
  162. package/dist/harnesses/claude-code.js +74 -0
  163. package/dist/harnesses/codex.d.ts +15 -0
  164. package/dist/harnesses/codex.js +54 -0
  165. package/dist/harnesses/gemini-cli.d.ts +12 -0
  166. package/dist/harnesses/gemini-cli.js +80 -0
  167. package/dist/harnesses/index.d.ts +27 -0
  168. package/dist/harnesses/index.js +54 -0
  169. package/dist/harnesses/opencode.d.ts +14 -0
  170. package/dist/harnesses/opencode.js +139 -0
  171. package/dist/harnesses/types.d.ts +106 -0
  172. package/dist/harnesses/types.js +26 -0
  173. package/dist/lib/agent-transform.d.ts +12 -0
  174. package/dist/lib/agent-transform.js +129 -0
  175. package/dist/lib/asset-catalog.d.ts +9 -0
  176. package/dist/lib/asset-catalog.js +56 -0
  177. package/dist/lib/atomic-write.d.ts +11 -0
  178. package/dist/lib/atomic-write.js +28 -0
  179. package/dist/lib/config-merger.d.ts +9 -2
  180. package/dist/lib/config-merger.js +44 -7
  181. package/dist/lib/display.d.ts +14 -0
  182. package/dist/lib/display.js +66 -0
  183. package/dist/lib/file-ops.d.ts +11 -0
  184. package/dist/lib/file-ops.js +40 -4
  185. package/dist/lib/hash.d.ts +1 -0
  186. package/dist/lib/hash.js +2 -1
  187. package/dist/lib/health.d.ts +2 -0
  188. package/dist/lib/health.js +10 -0
  189. package/dist/lib/manifest.d.ts +51 -5
  190. package/dist/lib/manifest.js +146 -13
  191. package/dist/lib/paths.d.ts +30 -3
  192. package/dist/lib/paths.js +98 -12
  193. package/dist/lib/settings-merger.d.ts +31 -8
  194. package/dist/lib/settings-merger.js +87 -24
  195. package/dist/lib/version.d.ts +2 -0
  196. package/dist/lib/version.js +10 -0
  197. package/dist/steps/agents.d.ts +4 -1
  198. package/dist/steps/agents.js +48 -9
  199. package/dist/steps/auth.js +26 -10
  200. package/dist/steps/cli.d.ts +53 -0
  201. package/dist/steps/cli.js +90 -0
  202. package/dist/steps/commands.d.ts +6 -1
  203. package/dist/steps/commands.js +36 -9
  204. package/dist/steps/detect.d.ts +3 -0
  205. package/dist/steps/detect.js +11 -0
  206. package/dist/steps/mcp.d.ts +6 -2
  207. package/dist/steps/mcp.js +39 -22
  208. package/dist/steps/metrics.d.ts +26 -10
  209. package/dist/steps/metrics.js +108 -108
  210. package/dist/steps/shell.d.ts +2 -0
  211. package/dist/steps/shell.js +26 -9
  212. package/dist/steps/signup.d.ts +7 -4
  213. package/dist/steps/signup.js +29 -20
  214. package/dist/steps/verify.d.ts +2 -2
  215. package/dist/steps/verify.js +118 -112
  216. package/package.json +40 -14
  217. package/assets/agents/docs-validator-agent.md +0 -490
  218. package/assets/agents/release-readiness-agent.md +0 -482
  219. package/assets/commands/agents/aristotle-analyst.md +0 -115
  220. package/assets/commands/agents/aristotle-explorer.md +0 -92
  221. package/assets/commands/agents/aristotle-forecaster.md +0 -114
  222. package/assets/commands/agents/aristotle-validator.md +0 -114
  223. package/assets/commands/agents/prompt-validate.md +0 -135
  224. package/assets/commands/agents/workflow-synthesis.md +0 -101
  225. package/assets/commands/workflows/aristotle.md +0 -543
  226. package/assets/commands/workflows/post-implementation.md +0 -577
  227. package/assets/commands/workflows/pre-implementation.md +0 -670
  228. package/assets/commands/workflows/prompt-audit.md +0 -754
  229. package/assets/commands/workflows/ship.md +0 -721
  230. package/dist/test/auth.test.d.ts +0 -1
  231. package/dist/test/auth.test.js +0 -43
  232. package/dist/test/config-io.test.d.ts +0 -1
  233. package/dist/test/config-io.test.js +0 -56
  234. package/dist/test/config-merger.test.d.ts +0 -1
  235. package/dist/test/config-merger.test.js +0 -94
  236. package/dist/test/detect.test.d.ts +0 -1
  237. package/dist/test/detect.test.js +0 -25
  238. package/dist/test/file-ops.test.d.ts +0 -1
  239. package/dist/test/file-ops.test.js +0 -100
  240. package/dist/test/hash.test.d.ts +0 -1
  241. package/dist/test/hash.test.js +0 -14
  242. package/dist/test/manifest.test.d.ts +0 -1
  243. package/dist/test/manifest.test.js +0 -78
  244. package/dist/test/paths.test.d.ts +0 -1
  245. package/dist/test/paths.test.js +0 -30
  246. package/dist/test/settings-merger.test.d.ts +0 -1
  247. package/dist/test/settings-merger.test.js +0 -167
  248. package/dist/test/shell-profile.test.d.ts +0 -1
  249. package/dist/test/shell-profile.test.js +0 -40
  250. package/dist/test/shell.test.d.ts +0 -1
  251. package/dist/test/shell.test.js +0 -71
  252. package/dist/test/signup.test.d.ts +0 -1
  253. package/dist/test/signup.test.js +0 -83
@@ -1,40 +0,0 @@
1
- import { describe, it, expect, vi, afterEach } from "vitest";
2
- import { getShellProfile } from "../lib/paths.js";
3
- afterEach(() => {
4
- vi.unstubAllEnvs();
5
- });
6
- describe("getShellProfile", () => {
7
- it("returns .zshrc for zsh shell", () => {
8
- vi.stubEnv("SHELL", "/bin/zsh");
9
- const result = getShellProfile();
10
- expect(result).not.toBeNull();
11
- expect(result.shell).toBe("zsh");
12
- expect(result.path).toMatch(/\.zshrc$/);
13
- });
14
- it("returns .bashrc for bash on linux", () => {
15
- vi.stubEnv("SHELL", "/bin/bash");
16
- // getShellProfile checks platform() — on linux it returns .bashrc
17
- const result = getShellProfile();
18
- expect(result).not.toBeNull();
19
- expect(result.shell).toBe("bash");
20
- // On linux: .bashrc, on darwin: .bash_profile
21
- expect(result.path).toMatch(/\.bash(rc|_profile)$/);
22
- });
23
- it("returns config.fish for fish shell", () => {
24
- vi.stubEnv("SHELL", "/usr/bin/fish");
25
- const result = getShellProfile();
26
- expect(result).not.toBeNull();
27
- expect(result.shell).toBe("fish");
28
- expect(result.path).toMatch(/config\.fish$/);
29
- });
30
- it("returns null for unknown shell", () => {
31
- vi.stubEnv("SHELL", "/bin/csh");
32
- const result = getShellProfile();
33
- expect(result).toBeNull();
34
- });
35
- it("returns null when SHELL is empty", () => {
36
- vi.stubEnv("SHELL", "");
37
- const result = getShellProfile();
38
- expect(result).toBeNull();
39
- });
40
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,71 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { writeFile, readFile, unlink, mkdtemp } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { writeShellExport, removeShellExport } from "../steps/shell.js";
6
- let tmpDir;
7
- let profilePath;
8
- beforeEach(async () => {
9
- tmpDir = await mkdtemp(join(tmpdir(), "uluops-test-"));
10
- profilePath = join(tmpDir, ".bashrc");
11
- });
12
- afterEach(async () => {
13
- try {
14
- await unlink(profilePath);
15
- }
16
- catch {
17
- // may not exist
18
- }
19
- });
20
- describe("writeShellExport", () => {
21
- it("creates profile with fenced block if file does not exist", async () => {
22
- await writeShellExport(profilePath, "ulr_abc123", false);
23
- const content = await readFile(profilePath, "utf-8");
24
- expect(content).toContain("# --- UluOps (managed by @uluops/setup) ---");
25
- expect(content).toContain('export ULUOPS_API_KEY="ulr_abc123"');
26
- expect(content).toContain("# --- /UluOps ---");
27
- });
28
- it("appends fenced block to existing file", async () => {
29
- await writeFile(profilePath, "# existing content\n");
30
- await writeShellExport(profilePath, "ulr_abc123", false);
31
- const content = await readFile(profilePath, "utf-8");
32
- expect(content).toContain("# existing content");
33
- expect(content).toContain('export ULUOPS_API_KEY="ulr_abc123"');
34
- });
35
- it("replaces existing fenced block on re-run", async () => {
36
- await writeShellExport(profilePath, "ulr_old", false);
37
- await writeShellExport(profilePath, "ulr_new", false);
38
- const content = await readFile(profilePath, "utf-8");
39
- expect(content).toContain('export ULUOPS_API_KEY="ulr_new"');
40
- expect(content).not.toContain("ulr_old");
41
- // Only one fenced block should exist
42
- expect(content.split("# --- UluOps").length).toBe(2);
43
- });
44
- it("does not modify files in dry-run mode", async () => {
45
- await writeFile(profilePath, "# existing\n");
46
- await writeShellExport(profilePath, "ulr_abc123", true);
47
- const content = await readFile(profilePath, "utf-8");
48
- expect(content).toBe("# existing\n");
49
- });
50
- });
51
- describe("removeShellExport", () => {
52
- it("removes the fenced block from the file", async () => {
53
- const initial = "# before\n\n# --- UluOps (managed by @uluops/setup) ---\nexport ULUOPS_API_KEY=\"ulr_abc\"\n# --- /UluOps ---\n\n# after\n";
54
- await writeFile(profilePath, initial);
55
- await removeShellExport(profilePath);
56
- const content = await readFile(profilePath, "utf-8");
57
- expect(content).toContain("# before");
58
- expect(content).toContain("# after");
59
- expect(content).not.toContain("ULUOPS_API_KEY");
60
- expect(content).not.toContain("UluOps");
61
- });
62
- it("does nothing if no fenced block exists", async () => {
63
- await writeFile(profilePath, "# no uluops here\n");
64
- await removeShellExport(profilePath);
65
- const content = await readFile(profilePath, "utf-8");
66
- expect(content).toBe("# no uluops here\n");
67
- });
68
- it("does nothing if file does not exist", async () => {
69
- await expect(removeShellExport(join(tmpDir, "nonexistent"))).resolves.toBeUndefined();
70
- });
71
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,83 +0,0 @@
1
- import { describe, it, expect, vi, afterEach } from "vitest";
2
- import { validatePassword, validateEmail } from "../steps/signup.js";
3
- describe("validatePassword", () => {
4
- it("accepts a valid password", () => {
5
- expect(validatePassword("GoodPass1")).toBe(true);
6
- });
7
- it("rejects passwords shorter than 8 chars", () => {
8
- expect(validatePassword("Short1A")).toContain("at least 8");
9
- });
10
- it("rejects passwords longer than 128 chars", () => {
11
- const long = "Aa1" + "x".repeat(126);
12
- expect(validatePassword(long)).toContain("at most 128");
13
- });
14
- it("rejects passwords without lowercase", () => {
15
- expect(validatePassword("ALLCAPS123")).toContain("lowercase");
16
- });
17
- it("rejects passwords without uppercase", () => {
18
- expect(validatePassword("alllower123")).toContain("uppercase");
19
- });
20
- it("rejects passwords without number", () => {
21
- expect(validatePassword("NoNumbersHere")).toContain("number");
22
- });
23
- });
24
- describe("validateEmail", () => {
25
- it("accepts a valid email", () => {
26
- expect(validateEmail("user@example.com")).toBe(true);
27
- });
28
- it("rejects empty string", () => {
29
- expect(validateEmail("")).toContain("required");
30
- });
31
- it("rejects missing @", () => {
32
- expect(validateEmail("notanemail")).toContain("Invalid");
33
- });
34
- it("rejects missing domain", () => {
35
- expect(validateEmail("user@")).toContain("Invalid");
36
- });
37
- });
38
- describe("signup (network)", () => {
39
- afterEach(() => {
40
- vi.restoreAllMocks();
41
- });
42
- it("handles 409 conflict (duplicate email)", async () => {
43
- vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
44
- ok: false,
45
- status: 409,
46
- json: async () => ({ error: { message: "Email already exists" } }),
47
- headers: new Headers(),
48
- }));
49
- const { signup } = await import("../steps/signup.js");
50
- // Mock inquirer prompts
51
- vi.mock("@inquirer/prompts", () => ({
52
- input: vi.fn().mockResolvedValue("existing@example.com"),
53
- password: vi.fn().mockResolvedValue("ValidPass1"),
54
- }));
55
- await expect(signup()).rejects.toThrow("already registered");
56
- vi.unstubAllGlobals();
57
- });
58
- it("handles 429 rate limit", async () => {
59
- vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
60
- ok: false,
61
- status: 429,
62
- json: async () => ({ error: { message: "Too many requests" } }),
63
- headers: new Headers({ "Retry-After": "30" }),
64
- }));
65
- const { signup } = await import("../steps/signup.js");
66
- vi.mock("@inquirer/prompts", () => ({
67
- input: vi.fn().mockResolvedValue("user@example.com"),
68
- password: vi.fn().mockResolvedValue("ValidPass1"),
69
- }));
70
- await expect(signup()).rejects.toThrow("Rate limited");
71
- vi.unstubAllGlobals();
72
- });
73
- it("handles network failure", async () => {
74
- vi.stubGlobal("fetch", vi.fn().mockRejectedValue(new TypeError("fetch failed")));
75
- const { signup } = await import("../steps/signup.js");
76
- vi.mock("@inquirer/prompts", () => ({
77
- input: vi.fn().mockResolvedValue("user@example.com"),
78
- password: vi.fn().mockResolvedValue("ValidPass1"),
79
- }));
80
- await expect(signup()).rejects.toThrow("Can't reach");
81
- vi.unstubAllGlobals();
82
- });
83
- });