@warpgogol/forge 5.1.1 → 5.1.2

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 (57) hide show
  1. package/AGENTS.md +7 -0
  2. package/dist/os/compass/handlers/compass-audit-handler.d.ts.map +1 -1
  3. package/dist/os/compass/handlers/compass-audit-handler.js +3 -3
  4. package/dist/os/compass/handlers/compass-audit-handler.js.map +1 -1
  5. package/dist/os/compass/handlers/compass-change-summary-handler.d.ts.map +1 -1
  6. package/dist/os/compass/handlers/compass-change-summary-handler.js +1 -1
  7. package/dist/os/compass/handlers/compass-change-summary-handler.js.map +1 -1
  8. package/dist/os/compass/handlers/compass-inventory-handler.d.ts.map +1 -1
  9. package/dist/os/compass/handlers/compass-inventory-handler.js +1 -1
  10. package/dist/os/compass/handlers/compass-inventory-handler.js.map +1 -1
  11. package/dist/os/compass/handlers/compass-inventory.d.ts +1 -1
  12. package/dist/os/compass/handlers/compass-inventory.d.ts.map +1 -1
  13. package/dist/os/compass/handlers/compass-inventory.js +20 -5
  14. package/dist/os/compass/handlers/compass-inventory.js.map +1 -1
  15. package/dist/os/compass/handlers/compass-migrate-handler.d.ts.map +1 -1
  16. package/dist/os/compass/handlers/compass-migrate-handler.js +1 -0
  17. package/dist/os/compass/handlers/compass-migrate-handler.js.map +1 -1
  18. package/dist/os/compass/handlers/compass-migrate.d.ts +2 -0
  19. package/dist/os/compass/handlers/compass-migrate.d.ts.map +1 -1
  20. package/dist/os/compass/handlers/compass-migrate.js +1 -1
  21. package/dist/os/compass/handlers/compass-migrate.js.map +1 -1
  22. package/dist/os/compass/handlers/resolve-scan-root.js +1 -1
  23. package/dist/os/core/handlers/pinned-validate.d.ts.map +1 -1
  24. package/dist/os/core/handlers/pinned-validate.js +26 -6
  25. package/dist/os/core/handlers/pinned-validate.js.map +1 -1
  26. package/dist/src/config/forge-config.d.ts +8 -1
  27. package/dist/src/config/forge-config.d.ts.map +1 -1
  28. package/dist/src/config/forge-config.js +52 -5
  29. package/dist/src/config/forge-config.js.map +1 -1
  30. package/dist/src/onboarding/create.d.ts.map +1 -1
  31. package/dist/src/onboarding/create.js +4 -8
  32. package/dist/src/onboarding/create.js.map +1 -1
  33. package/dist/src/onboarding/doctor.d.ts.map +1 -1
  34. package/dist/src/onboarding/doctor.js +65 -0
  35. package/dist/src/onboarding/doctor.js.map +1 -1
  36. package/dist/src/onboarding/init.d.ts.map +1 -1
  37. package/dist/src/onboarding/init.js +11 -0
  38. package/dist/src/onboarding/init.js.map +1 -1
  39. package/dist/src/onboarding/upgrade.d.ts.map +1 -1
  40. package/dist/src/onboarding/upgrade.js +4 -2
  41. package/dist/src/onboarding/upgrade.js.map +1 -1
  42. package/os/compass/handlers/compass-audit-handler.ts +3 -0
  43. package/os/compass/handlers/compass-change-summary-handler.ts +1 -0
  44. package/os/compass/handlers/compass-inventory-handler.ts +1 -0
  45. package/os/compass/handlers/compass-inventory.ts +20 -6
  46. package/os/compass/handlers/compass-migrate-handler.ts +1 -0
  47. package/os/compass/handlers/compass-migrate.ts +9 -2
  48. package/os/compass/handlers/resolve-scan-root.ts +1 -1
  49. package/os/core/handlers/pinned-validate.ts +33 -7
  50. package/package.json +1 -1
  51. package/src/config/forge-config.ts +59 -5
  52. package/src/onboarding/create.ts +4 -7
  53. package/src/onboarding/doctor.ts +70 -0
  54. package/src/onboarding/init.ts +19 -1
  55. package/src/onboarding/upgrade.ts +4 -1
  56. package/src/tests/doctor-profile-id-known.test.ts +237 -0
  57. package/src/tests/pinned-validate.test.ts +134 -0
@@ -0,0 +1,134 @@
1
+ import { test, expect, describe } from "vitest";
2
+ import { mkdtemp, rm, mkdir, writeFile } from "node:fs/promises";
3
+ import { execFile } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+ import { join } from "node:path";
6
+ import { tmpdir } from "node:os";
7
+ import { runPinnedValidate } from "../../os/core/handlers/pinned-validate.ts";
8
+ import type { ForgeCommandInput, ForgeRuntimeContext } from "../../src/types.ts";
9
+
10
+ const execFileAsync = promisify(execFile);
11
+
12
+ async function makeTempDir(): Promise<string> {
13
+ return mkdtemp(join(tmpdir(), "forge-pinned-validate-test-"));
14
+ }
15
+
16
+ function makeContext(workspaceRoot: string): ForgeRuntimeContext {
17
+ return {
18
+ workspaceRoot,
19
+ logger: {
20
+ section: () => {},
21
+ info: () => {},
22
+ warn: () => {},
23
+ error: () => {},
24
+ success: () => {},
25
+ },
26
+ dryRun: false,
27
+ outputFormat: "json",
28
+ };
29
+ }
30
+
31
+ function makeInput(): ForgeCommandInput {
32
+ return { argv: [], flags: {} };
33
+ }
34
+
35
+ async function git(dir: string, args: string[]): Promise<void> {
36
+ await execFileAsync("git", args, { cwd: dir });
37
+ }
38
+
39
+ /**
40
+ * Scaffold a git repo with a committed pinned.yaml protecting docs/rfcs/
41
+ * and one committed RFC file. Returns the repo dir.
42
+ */
43
+ async function makeRepo(): Promise<string> {
44
+ const dir = await makeTempDir();
45
+ await git(dir, ["init"]);
46
+ await git(dir, ["config", "user.email", "test@example.com"]);
47
+ await git(dir, ["config", "user.name", "Test"]);
48
+ await mkdir(join(dir, ".forge"), { recursive: true });
49
+ await writeFile(
50
+ join(dir, ".forge", "pinned.yaml"),
51
+ "pinned:\n - path: docs/rfcs/\n mode: protect\n reason: RFC directory\n",
52
+ );
53
+ await mkdir(join(dir, "docs", "rfcs"), { recursive: true });
54
+ await writeFile(join(dir, "docs", "rfcs", "rfc-0001.md"), "# RFC 1\n");
55
+ await git(dir, ["add", "-A"]);
56
+ await git(dir, ["commit", "-m", "init"]);
57
+ return dir;
58
+ }
59
+
60
+ describe("runPinnedValidate", () => {
61
+ test("passes for intra-directory move inside a pinned dir (docs.archive)", async () => {
62
+ const dir = await makeRepo();
63
+ try {
64
+ // Simulate docs.archive: docs/rfcs/rfc-0001.md → docs/rfcs/archive/implemented/rfc-0001.md
65
+ await mkdir(join(dir, "docs", "rfcs", "archive", "implemented"), { recursive: true });
66
+ await git(dir, ["mv", "docs/rfcs/rfc-0001.md", "docs/rfcs/archive/implemented/rfc-0001.md"]);
67
+
68
+ const result = await runPinnedValidate(makeInput(), makeContext(dir));
69
+ expect(result.data?.status).toBe("pass");
70
+ expect(result.data?.violations).toHaveLength(0);
71
+ expect(result.exitCode).toBe(0);
72
+ } finally {
73
+ await rm(dir, { recursive: true, force: true });
74
+ }
75
+ });
76
+
77
+ test("flags move out of a pinned dir", async () => {
78
+ const dir = await makeRepo();
79
+ try {
80
+ await mkdir(join(dir, "docs", "other"), { recursive: true });
81
+ await git(dir, ["mv", "docs/rfcs/rfc-0001.md", "docs/other/rfc-0001.md"]);
82
+
83
+ const result = await runPinnedValidate(makeInput(), makeContext(dir));
84
+ expect(result.data?.status).toBe("fail");
85
+ expect(result.data?.violations.length).toBeGreaterThan(0);
86
+ expect(
87
+ result.data?.violations.some(
88
+ (v) => v.path === "docs/rfcs/rfc-0001.md" && v.operation === "move",
89
+ ),
90
+ ).toBe(true);
91
+ } finally {
92
+ await rm(dir, { recursive: true, force: true });
93
+ }
94
+ });
95
+
96
+ test("flags move into a pinned dir", async () => {
97
+ const dir = await makeRepo();
98
+ try {
99
+ // Source must be committed first — otherwise git records the staged
100
+ // result as A (add), not R (rename).
101
+ await writeFile(join(dir, "incoming.md"), "# incoming\n");
102
+ await git(dir, ["add", "incoming.md"]);
103
+ await git(dir, ["commit", "-m", "add incoming"]);
104
+ await git(dir, ["mv", "incoming.md", "docs/rfcs/incoming.md"]);
105
+
106
+ const result = await runPinnedValidate(makeInput(), makeContext(dir));
107
+ expect(result.data?.status).toBe("fail");
108
+ expect(
109
+ result.data?.violations.some(
110
+ (v) => v.path === "docs/rfcs/incoming.md" && v.operation === "move",
111
+ ),
112
+ ).toBe(true);
113
+ } finally {
114
+ await rm(dir, { recursive: true, force: true });
115
+ }
116
+ });
117
+
118
+ test("flags delete of a pinned file", async () => {
119
+ const dir = await makeRepo();
120
+ try {
121
+ await git(dir, ["rm", "docs/rfcs/rfc-0001.md"]);
122
+
123
+ const result = await runPinnedValidate(makeInput(), makeContext(dir));
124
+ expect(result.data?.status).toBe("fail");
125
+ expect(
126
+ result.data?.violations.some(
127
+ (v) => v.path === "docs/rfcs/rfc-0001.md" && v.operation === "delete",
128
+ ),
129
+ ).toBe(true);
130
+ } finally {
131
+ await rm(dir, { recursive: true, force: true });
132
+ }
133
+ });
134
+ });