@urateam/cli 0.1.38 → 0.1.40

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 (45) hide show
  1. package/dist/__tests__/init.test.d.ts +2 -0
  2. package/dist/__tests__/init.test.d.ts.map +1 -0
  3. package/dist/__tests__/init.test.js +65 -0
  4. package/dist/__tests__/init.test.js.map +1 -0
  5. package/dist/__tests__/repo.test.d.ts +2 -0
  6. package/dist/__tests__/repo.test.d.ts.map +1 -0
  7. package/dist/__tests__/repo.test.js +191 -0
  8. package/dist/__tests__/repo.test.js.map +1 -0
  9. package/dist/__tests__/start-user-level-fallback.test.d.ts +2 -0
  10. package/dist/__tests__/start-user-level-fallback.test.d.ts.map +1 -0
  11. package/dist/__tests__/start-user-level-fallback.test.js +191 -0
  12. package/dist/__tests__/start-user-level-fallback.test.js.map +1 -0
  13. package/dist/__tests__/uninstall.test.d.ts +2 -0
  14. package/dist/__tests__/uninstall.test.d.ts.map +1 -0
  15. package/dist/__tests__/uninstall.test.js +51 -0
  16. package/dist/__tests__/uninstall.test.js.map +1 -0
  17. package/dist/__tests__/user-level-config.test.d.ts +2 -0
  18. package/dist/__tests__/user-level-config.test.d.ts.map +1 -0
  19. package/dist/__tests__/user-level-config.test.js +92 -0
  20. package/dist/__tests__/user-level-config.test.js.map +1 -0
  21. package/dist/commands/init.d.ts +11 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +27 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/commands/repo.d.ts +7 -0
  26. package/dist/commands/repo.d.ts.map +1 -0
  27. package/dist/commands/repo.js +126 -0
  28. package/dist/commands/repo.js.map +1 -0
  29. package/dist/commands/start.d.ts.map +1 -1
  30. package/dist/commands/start.js +25 -0
  31. package/dist/commands/start.js.map +1 -1
  32. package/dist/commands/uninstall.d.ts +17 -0
  33. package/dist/commands/uninstall.d.ts.map +1 -0
  34. package/dist/commands/uninstall.js +38 -0
  35. package/dist/commands/uninstall.js.map +1 -0
  36. package/dist/index.js +6 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/lib/build-repo-configs.d.ts.map +1 -1
  39. package/dist/lib/build-repo-configs.js +85 -27
  40. package/dist/lib/build-repo-configs.js.map +1 -1
  41. package/dist/lib/user-level-config.d.ts +70 -0
  42. package/dist/lib/user-level-config.d.ts.map +1 -0
  43. package/dist/lib/user-level-config.js +91 -0
  44. package/dist/lib/user-level-config.js.map +1 -0
  45. package/package.json +4 -3
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=init.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/init.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * `ura init` — bootstrap a user-level urateam install.
3
+ *
4
+ * Creates `~/.urateam/` (or `$URATEAM_HOME`) with an empty `config.json`,
5
+ * a `data/` directory for the SQLite DB, and a `repos/` directory for
6
+ * managed clones. Idempotent: re-running on an already-initialized
7
+ * directory leaves the existing config untouched.
8
+ */
9
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
10
+ import { mkdtempSync, rmSync, existsSync, readFileSync, writeFileSync, } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { tmpdir } from "node:os";
13
+ import { initCommand } from "../commands/init.js";
14
+ describe("ura init", () => {
15
+ let tmp;
16
+ beforeEach(() => {
17
+ tmp = mkdtempSync(join(tmpdir(), "ura-init-"));
18
+ process.env.URATEAM_HOME = tmp;
19
+ });
20
+ afterEach(() => {
21
+ delete process.env.URATEAM_HOME;
22
+ rmSync(tmp, { recursive: true, force: true });
23
+ });
24
+ it("creates config.json, data/, repos/ under URATEAM_HOME", async () => {
25
+ await initCommand.parseAsync([], { from: "user" });
26
+ expect(existsSync(join(tmp, "config.json"))).toBe(true);
27
+ expect(existsSync(join(tmp, "data"))).toBe(true);
28
+ expect(existsSync(join(tmp, "repos"))).toBe(true);
29
+ });
30
+ it("seeds config.json with version=1 and an empty repos array", async () => {
31
+ await initCommand.parseAsync([], { from: "user" });
32
+ const raw = JSON.parse(readFileSync(join(tmp, "config.json"), "utf8"));
33
+ expect(raw.version).toBe(1);
34
+ expect(raw.repos).toEqual([]);
35
+ });
36
+ it("is idempotent: re-running does not overwrite an existing config", async () => {
37
+ await initCommand.parseAsync([], { from: "user" });
38
+ const path = join(tmp, "config.json");
39
+ const mutated = {
40
+ version: 1,
41
+ repos: [
42
+ {
43
+ url: "https://github.com/o/r.git",
44
+ path: "/tmp/r",
45
+ defaultBranch: "main",
46
+ testCommand: "pnpm test",
47
+ buildCommand: "pnpm build",
48
+ },
49
+ ],
50
+ };
51
+ writeFileSync(path, JSON.stringify(mutated));
52
+ await initCommand.parseAsync([], { from: "user" });
53
+ const after = JSON.parse(readFileSync(path, "utf8"));
54
+ expect(after.repos).toHaveLength(1);
55
+ });
56
+ it("prints the location it created on first run", async () => {
57
+ const spy = vi.spyOn(console, "log").mockImplementation(() => { });
58
+ await initCommand.parseAsync([], { from: "user" });
59
+ const out = spy.mock.calls.flat().join("\n");
60
+ expect(out).toContain(tmp);
61
+ expect(out).toMatch(/ura repo add/);
62
+ spy.mockRestore();
63
+ });
64
+ });
65
+ //# sourceMappingURL=init.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.test.js","sourceRoot":"","sources":["../../src/__tests__/init.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=repo.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/repo.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,191 @@
1
+ /**
2
+ * `ura repo {add,list,remove}` — manage repos in the user-level config.
3
+ *
4
+ * `add`: clones the repo into `~/.urateam/repos/<slug>` and appends to
5
+ * `config.json`. Slug derived from the URL's trailing path
6
+ * (foo/bar.git → bar).
7
+ * `list`: prints each configured repo.
8
+ * `remove`: filters the repo out of `config.json`. The clone on disk is
9
+ * preserved by default — `--purge` deletes it.
10
+ *
11
+ * Tests stub `cloneRepo` (from `@urateam/core`) so they don't touch the
12
+ * network or git.
13
+ */
14
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
15
+ import { mkdtempSync, rmSync, mkdirSync, writeFileSync, existsSync, } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { tmpdir } from "node:os";
18
+ import { repoCommand } from "../commands/repo.js";
19
+ import { readUserLevelConfig, writeUserLevelConfig, } from "../lib/user-level-config.js";
20
+ vi.mock("@urateam/core", async () => {
21
+ const actual = await vi.importActual("@urateam/core");
22
+ return {
23
+ ...actual,
24
+ cloneRepo: vi.fn(async (url, dest) => {
25
+ mkdirSync(dest, { recursive: true });
26
+ writeFileSync(join(dest, ".cloned"), url);
27
+ }),
28
+ };
29
+ });
30
+ describe("ura repo add", () => {
31
+ let tmp;
32
+ beforeEach(() => {
33
+ tmp = mkdtempSync(join(tmpdir(), "ura-repo-"));
34
+ process.env.URATEAM_HOME = tmp;
35
+ writeUserLevelConfig({ version: 1, repos: [] });
36
+ });
37
+ afterEach(() => {
38
+ delete process.env.URATEAM_HOME;
39
+ rmSync(tmp, { recursive: true, force: true });
40
+ });
41
+ it("clones into ~/.urateam/repos/<slug> and appends to config.json", async () => {
42
+ await repoCommand.parseAsync(["add", "https://github.com/foo/bar.git"], { from: "user" });
43
+ const cfg = readUserLevelConfig();
44
+ expect(cfg?.repos).toHaveLength(1);
45
+ expect(cfg?.repos[0].url).toBe("https://github.com/foo/bar.git");
46
+ expect(cfg?.repos[0].path).toBe(join(tmp, "repos", "bar"));
47
+ expect(cfg?.repos[0].defaultBranch).toBe("main");
48
+ });
49
+ it("rejects duplicate URLs", async () => {
50
+ await repoCommand.parseAsync(["add", "https://github.com/foo/bar.git"], { from: "user" });
51
+ await expect(repoCommand.parseAsync(["add", "https://github.com/foo/bar.git"], { from: "user" })).rejects.toThrow(/already configured/i);
52
+ });
53
+ it("derives slug from .git URL trailing path (foo/bar.git → bar)", async () => {
54
+ await repoCommand.parseAsync(["add", "git@github.com:org/awesome-tool.git"], { from: "user" });
55
+ expect(readUserLevelConfig()?.repos[0].path).toContain("awesome-tool");
56
+ });
57
+ it("accepts --branch override", async () => {
58
+ await repoCommand.parseAsync([
59
+ "add",
60
+ "https://github.com/foo/bar.git",
61
+ "--branch",
62
+ "develop",
63
+ ], { from: "user" });
64
+ expect(readUserLevelConfig()?.repos[0].defaultBranch).toBe("develop");
65
+ });
66
+ it("accepts --team and --label-pattern", async () => {
67
+ await repoCommand.parseAsync([
68
+ "add",
69
+ "https://github.com/foo/bar.git",
70
+ "--team",
71
+ "team-abc",
72
+ "--label-pattern",
73
+ "auto-implement",
74
+ ], { from: "user" });
75
+ const repo = readUserLevelConfig()?.repos[0];
76
+ expect(repo?.teamId).toBe("team-abc");
77
+ expect(repo?.labelPattern).toBe("auto-implement");
78
+ });
79
+ it("errors when 'ura init' has not been run", async () => {
80
+ // Wipe the seeded config so the next call sees a clean slate.
81
+ rmSync(tmp, { recursive: true, force: true });
82
+ mkdirSync(tmp, { recursive: true });
83
+ await expect(repoCommand.parseAsync(["add", "https://github.com/foo/bar.git"], { from: "user" })).rejects.toThrow(/ura init/i);
84
+ });
85
+ });
86
+ describe("ura repo list", () => {
87
+ let tmp;
88
+ beforeEach(() => {
89
+ tmp = mkdtempSync(join(tmpdir(), "ura-list-"));
90
+ process.env.URATEAM_HOME = tmp;
91
+ writeUserLevelConfig({
92
+ version: 1,
93
+ repos: [
94
+ {
95
+ url: "https://github.com/a/x.git",
96
+ path: "/p/x",
97
+ defaultBranch: "main",
98
+ testCommand: "pnpm test",
99
+ buildCommand: "pnpm build",
100
+ },
101
+ {
102
+ url: "https://github.com/a/y.git",
103
+ path: "/p/y",
104
+ defaultBranch: "main",
105
+ testCommand: "pnpm test",
106
+ buildCommand: "pnpm build",
107
+ },
108
+ ],
109
+ });
110
+ });
111
+ afterEach(() => {
112
+ delete process.env.URATEAM_HOME;
113
+ rmSync(tmp, { recursive: true, force: true });
114
+ });
115
+ it("prints each repo's url + path on its own line", async () => {
116
+ const spy = vi.spyOn(console, "log").mockImplementation(() => { });
117
+ await repoCommand.parseAsync(["list"], { from: "user" });
118
+ const lines = spy.mock.calls.flat().join("\n");
119
+ expect(lines).toContain("https://github.com/a/x.git");
120
+ expect(lines).toContain("https://github.com/a/y.git");
121
+ spy.mockRestore();
122
+ });
123
+ it("prints an empty-state message when no repos are configured", async () => {
124
+ writeUserLevelConfig({ version: 1, repos: [] });
125
+ const spy = vi.spyOn(console, "log").mockImplementation(() => { });
126
+ await repoCommand.parseAsync(["list"], { from: "user" });
127
+ expect(spy.mock.calls.flat().join("\n")).toMatch(/no repos/i);
128
+ spy.mockRestore();
129
+ });
130
+ });
131
+ describe("ura repo remove", () => {
132
+ let tmp;
133
+ beforeEach(() => {
134
+ tmp = mkdtempSync(join(tmpdir(), "ura-remove-"));
135
+ process.env.URATEAM_HOME = tmp;
136
+ writeUserLevelConfig({
137
+ version: 1,
138
+ repos: [
139
+ {
140
+ url: "https://github.com/a/x.git",
141
+ path: join(tmp, "repos", "x"),
142
+ defaultBranch: "main",
143
+ testCommand: "pnpm test",
144
+ buildCommand: "pnpm build",
145
+ },
146
+ ],
147
+ });
148
+ mkdirSync(join(tmp, "repos", "x"), { recursive: true });
149
+ });
150
+ afterEach(() => {
151
+ delete process.env.URATEAM_HOME;
152
+ rmSync(tmp, { recursive: true, force: true });
153
+ });
154
+ it("removes the matching entry from config.json", async () => {
155
+ await repoCommand.parseAsync(["remove", "x"], { from: "user" });
156
+ expect(readUserLevelConfig()?.repos).toHaveLength(0);
157
+ });
158
+ it("preserves the clone on disk by default (no --purge)", async () => {
159
+ await repoCommand.parseAsync(["remove", "x"], { from: "user" });
160
+ expect(existsSync(join(tmp, "repos", "x"))).toBe(true);
161
+ });
162
+ it("deletes the clone when --purge is passed", async () => {
163
+ await repoCommand.parseAsync(["remove", "x", "--purge"], {
164
+ from: "user",
165
+ });
166
+ expect(existsSync(join(tmp, "repos", "x"))).toBe(false);
167
+ });
168
+ it("errors when the slug does not match any configured repo", async () => {
169
+ await expect(repoCommand.parseAsync(["remove", "nonexistent"], { from: "user" })).rejects.toThrow(/not found/i);
170
+ });
171
+ it("refuses to --purge a path outside URATEAM_HOME (hand-edited config safety)", async () => {
172
+ // Simulate a hand-edited config.json with a dangerous path. The path's
173
+ // basename ("etc-fake-sensitive") must match the slug arg so the entry
174
+ // is found; the test exercises the path-safety guard, not the
175
+ // slug-lookup path.
176
+ writeUserLevelConfig({
177
+ version: 1,
178
+ repos: [
179
+ {
180
+ url: "https://github.com/a/etc-fake-sensitive.git",
181
+ path: "/tmp/SAFETY_TEST_DO_NOT_DELETE/etc-fake-sensitive",
182
+ defaultBranch: "main",
183
+ testCommand: "pnpm test",
184
+ buildCommand: "pnpm build",
185
+ },
186
+ ],
187
+ });
188
+ await expect(repoCommand.parseAsync(["remove", "etc-fake-sensitive", "--purge"], { from: "user" })).rejects.toThrow(/refusing to delete/i);
189
+ });
190
+ });
191
+ //# sourceMappingURL=repo.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.test.js","sourceRoot":"","sources":["../../src/__tests__/repo.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=start-user-level-fallback.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-user-level-fallback.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/start-user-level-fallback.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,191 @@
1
+ /**
2
+ * `buildRepoConfigsFromEnv` — user-level config fallback.
3
+ *
4
+ * When no `REPO_*` env vars produce a RepoConfig, the function should fall
5
+ * back to reading `~/.urateam/config.json` (or `$URATEAM_HOME/config.json`).
6
+ * Env vars win when both are present so the existing project-level
7
+ * `ura start` deploys are unaffected.
8
+ */
9
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
10
+ import { mkdtempSync, rmSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { tmpdir } from "node:os";
13
+ import { writeUserLevelConfig } from "../lib/user-level-config.js";
14
+ import { buildRepoConfigsFromEnv } from "../lib/build-repo-configs.js";
15
+ describe("buildRepoConfigsFromEnv — user-level fallback", () => {
16
+ let tmp;
17
+ const envBackup = {};
18
+ const ENV_KEYS_TO_STRIP = [
19
+ "REPO_TEAM_ID",
20
+ "REPO_URL",
21
+ "REPO_DEFAULT_BRANCH",
22
+ "REPO_TEST_CMD",
23
+ "REPO_BUILD_CMD",
24
+ ];
25
+ beforeEach(() => {
26
+ tmp = mkdtempSync(join(tmpdir(), "ura-fallback-"));
27
+ process.env.URATEAM_HOME = tmp;
28
+ for (const k of ENV_KEYS_TO_STRIP) {
29
+ envBackup[k] = process.env[k];
30
+ delete process.env[k];
31
+ }
32
+ });
33
+ afterEach(() => {
34
+ delete process.env.URATEAM_HOME;
35
+ for (const [k, v] of Object.entries(envBackup)) {
36
+ if (v === undefined)
37
+ delete process.env[k];
38
+ else
39
+ process.env[k] = v;
40
+ delete envBackup[k];
41
+ }
42
+ rmSync(tmp, { recursive: true, force: true });
43
+ });
44
+ it("returns an empty map when no env vars and no user-level config", () => {
45
+ expect(buildRepoConfigsFromEnv()).toEqual({});
46
+ });
47
+ it("loads from ~/.urateam/config.json when no REPO_* env vars are set", () => {
48
+ writeUserLevelConfig({
49
+ version: 1,
50
+ repos: [
51
+ {
52
+ url: "https://github.com/o/r.git",
53
+ path: "/tmp/r",
54
+ defaultBranch: "main",
55
+ testCommand: "pnpm test",
56
+ buildCommand: "pnpm build",
57
+ teamId: "team-1",
58
+ },
59
+ ],
60
+ });
61
+ const configs = buildRepoConfigsFromEnv();
62
+ expect(configs["team-1"]).toBeDefined();
63
+ expect(configs["team-1"].url).toBe("https://github.com/o/r.git");
64
+ expect(configs["team-1"].defaultBranch).toBe("main");
65
+ });
66
+ it("propagates labelPattern when present (BEC-177 routing)", () => {
67
+ writeUserLevelConfig({
68
+ version: 1,
69
+ repos: [
70
+ {
71
+ url: "https://github.com/o/r.git",
72
+ path: "/tmp/r",
73
+ defaultBranch: "main",
74
+ testCommand: "pnpm test",
75
+ buildCommand: "pnpm build",
76
+ teamId: "team-1",
77
+ labelPattern: "auto-implement",
78
+ },
79
+ ],
80
+ });
81
+ const configs = buildRepoConfigsFromEnv();
82
+ expect(configs["team-1"].labelPattern).toBe("auto-implement");
83
+ });
84
+ it("keys repos by url-slug when teamId is omitted", () => {
85
+ writeUserLevelConfig({
86
+ version: 1,
87
+ repos: [
88
+ {
89
+ url: "https://github.com/o/no-team.git",
90
+ path: "/tmp/no-team",
91
+ defaultBranch: "main",
92
+ testCommand: "pnpm test",
93
+ buildCommand: "pnpm build",
94
+ },
95
+ ],
96
+ });
97
+ const configs = buildRepoConfigsFromEnv();
98
+ expect(Object.keys(configs)).toHaveLength(1);
99
+ const key = Object.keys(configs)[0];
100
+ expect(key).toContain("no-team");
101
+ });
102
+ it("env vars win over user-level config (project-level back-compat)", () => {
103
+ writeUserLevelConfig({
104
+ version: 1,
105
+ repos: [
106
+ {
107
+ url: "https://github.com/user-level/r.git",
108
+ path: "/p",
109
+ defaultBranch: "main",
110
+ testCommand: "pnpm test",
111
+ buildCommand: "pnpm build",
112
+ teamId: "team-userlevel",
113
+ },
114
+ ],
115
+ });
116
+ process.env.REPO_TEAM_ID = "team-env";
117
+ process.env.REPO_URL = "https://github.com/env-var/r.git";
118
+ const configs = buildRepoConfigsFromEnv();
119
+ expect(configs["team-env"]).toBeDefined();
120
+ expect(configs["team-env"].url).toBe("https://github.com/env-var/r.git");
121
+ expect(configs["team-userlevel"]).toBeUndefined();
122
+ });
123
+ it("handles multiple repos in the user-level config", () => {
124
+ writeUserLevelConfig({
125
+ version: 1,
126
+ repos: [
127
+ {
128
+ url: "https://github.com/o/a.git",
129
+ path: "/tmp/a",
130
+ defaultBranch: "main",
131
+ testCommand: "pnpm test",
132
+ buildCommand: "pnpm build",
133
+ teamId: "team-a",
134
+ },
135
+ {
136
+ url: "https://github.com/o/b.git",
137
+ path: "/tmp/b",
138
+ defaultBranch: "main",
139
+ testCommand: "pnpm test",
140
+ buildCommand: "pnpm build",
141
+ teamId: "team-b",
142
+ },
143
+ ],
144
+ });
145
+ const configs = buildRepoConfigsFromEnv();
146
+ expect(Object.keys(configs).sort()).toEqual(["team-a", "team-b"]);
147
+ });
148
+ });
149
+ describe("requireRepoConfigs — branched error messages", () => {
150
+ let tmp;
151
+ beforeEach(() => {
152
+ tmp = mkdtempSync(join(tmpdir(), "ura-req-"));
153
+ process.env.URATEAM_HOME = tmp;
154
+ });
155
+ afterEach(() => {
156
+ delete process.env.URATEAM_HOME;
157
+ rmSync(tmp, { recursive: true, force: true });
158
+ });
159
+ it("prints a 'ura repo add' hint when ~/.urateam/config.json exists but has no repos", async () => {
160
+ writeUserLevelConfig({ version: 1, repos: [] });
161
+ const errSpy = vi.spyOn(console, "error").mockImplementation(() => { });
162
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((() => {
163
+ throw new Error("exit");
164
+ }));
165
+ const { requireRepoConfigs } = await import("../lib/build-repo-configs.js");
166
+ expect(() => requireRepoConfigs({}, "ura start")).toThrow();
167
+ const msg = errSpy.mock.calls.flat().join("\n");
168
+ expect(msg).toContain("ura repo add");
169
+ expect(msg).not.toContain("REPO_TEAM_ID and REPO_URL in .urateam/.env"); // user-level branch
170
+ errSpy.mockRestore();
171
+ exitSpy.mockRestore();
172
+ });
173
+ it("prints both install paths when no ~/.urateam/config.json exists yet", async () => {
174
+ // Don't write a config — exercises the `userConfig === null` branch
175
+ const errSpy = vi.spyOn(console, "error").mockImplementation(() => { });
176
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((() => {
177
+ throw new Error("exit");
178
+ }));
179
+ const { requireRepoConfigs } = await import("../lib/build-repo-configs.js");
180
+ expect(() => requireRepoConfigs({}, "ura start")).toThrow();
181
+ const msg = errSpy.mock.calls.flat().join("\n");
182
+ expect(msg).toContain("REPO_TEAM_ID");
183
+ expect(msg).toContain("ura init");
184
+ expect(msg).toContain("ura repo add");
185
+ errSpy.mockRestore();
186
+ exitSpy.mockRestore();
187
+ });
188
+ });
189
+ // vi needs to be available — re-import at top-level for the new tests
190
+ import { vi } from "vitest";
191
+ //# sourceMappingURL=start-user-level-fallback.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-user-level-fallback.test.js","sourceRoot":"","sources":["../../src/__tests__/start-user-level-fallback.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=uninstall.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/uninstall.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `ura uninstall` — remove the user-level install at ~/.urateam (or
3
+ * $URATEAM_HOME).
4
+ *
5
+ * Destructive, so gated on `--yes`. Without `--yes`, prints what would be
6
+ * deleted and exits 0. With `--yes`, recursively removes the directory.
7
+ * No-op if the directory doesn't exist (so re-running after a manual
8
+ * `rm -rf ~/.urateam` doesn't error).
9
+ */
10
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
11
+ import { mkdtempSync, mkdirSync, existsSync, writeFileSync, rmSync, } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { tmpdir } from "node:os";
14
+ import { uninstallCommand } from "../commands/uninstall.js";
15
+ describe("ura uninstall", () => {
16
+ let tmp;
17
+ beforeEach(() => {
18
+ tmp = mkdtempSync(join(tmpdir(), "ura-uninst-"));
19
+ process.env.URATEAM_HOME = tmp;
20
+ mkdirSync(join(tmp, "data"), { recursive: true });
21
+ mkdirSync(join(tmp, "repos"), { recursive: true });
22
+ writeFileSync(join(tmp, "config.json"), '{"version":1,"repos":[]}');
23
+ });
24
+ afterEach(() => {
25
+ delete process.env.URATEAM_HOME;
26
+ });
27
+ it("removes URATEAM_HOME when --yes is passed", async () => {
28
+ await uninstallCommand.parseAsync(["--yes"], { from: "user" });
29
+ expect(existsSync(tmp)).toBe(false);
30
+ });
31
+ it("aborts without --yes (no destructive action)", async () => {
32
+ const spy = vi.spyOn(console, "log").mockImplementation(() => { });
33
+ await uninstallCommand.parseAsync([], { from: "user" });
34
+ expect(existsSync(tmp)).toBe(true);
35
+ expect(spy.mock.calls.flat().join("\n")).toMatch(/--yes/i);
36
+ spy.mockRestore();
37
+ // Test-cleanup: remove the directory manually since uninstall didn't.
38
+ rmSync(tmp, { recursive: true, force: true });
39
+ });
40
+ it("is a no-op when URATEAM_HOME does not exist", async () => {
41
+ rmSync(tmp, { recursive: true, force: true });
42
+ await expect(uninstallCommand.parseAsync(["--yes"], { from: "user" })).resolves.not.toThrow();
43
+ });
44
+ it("prints an npm-uninstall hint after a successful removal", async () => {
45
+ const spy = vi.spyOn(console, "log").mockImplementation(() => { });
46
+ await uninstallCommand.parseAsync(["--yes"], { from: "user" });
47
+ expect(spy.mock.calls.flat().join("\n")).toContain("npm uninstall -g @urateam/cli");
48
+ spy.mockRestore();
49
+ });
50
+ });
51
+ //# sourceMappingURL=uninstall.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.test.js","sourceRoot":"","sources":["../../src/__tests__/uninstall.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=user-level-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-level-config.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/user-level-config.test.ts"],"names":[],"mappings":""}