@momentiq/dark-factory-cli 2.18.0 → 3.0.1

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 (119) hide show
  1. package/README.md +33 -15
  2. package/dist/adapters/cursor-sdk.d.ts.map +1 -1
  3. package/dist/adapters/cursor-sdk.js +14 -2
  4. package/dist/adapters/cursor-sdk.js.map +1 -1
  5. package/dist/adapters/index.d.ts +1 -0
  6. package/dist/adapters/index.d.ts.map +1 -1
  7. package/dist/adapters/index.js +6 -0
  8. package/dist/adapters/index.js.map +1 -1
  9. package/dist/adapters/mode-scope.d.ts +86 -0
  10. package/dist/adapters/mode-scope.d.ts.map +1 -0
  11. package/dist/adapters/mode-scope.js +456 -0
  12. package/dist/adapters/mode-scope.js.map +1 -0
  13. package/dist/branch-protection/audit_branch_protection.py +152 -26
  14. package/dist/cli.d.ts +5 -0
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +17 -1
  17. package/dist/cli.js.map +1 -1
  18. package/dist/commands/mode.d.ts.map +1 -1
  19. package/dist/commands/mode.js +135 -10
  20. package/dist/commands/mode.js.map +1 -1
  21. package/dist/commands/objectives.d.ts +27 -3
  22. package/dist/commands/objectives.d.ts.map +1 -1
  23. package/dist/commands/objectives.js +347 -53
  24. package/dist/commands/objectives.js.map +1 -1
  25. package/dist/cycle-doc-validator/validate_cycle_doc.py +128 -11
  26. package/dist/doctor.d.ts.map +1 -1
  27. package/dist/doctor.js +8 -4
  28. package/dist/doctor.js.map +1 -1
  29. package/dist/evidence/index.d.ts +1 -0
  30. package/dist/evidence/index.d.ts.map +1 -1
  31. package/dist/evidence/index.js +5 -0
  32. package/dist/evidence/index.js.map +1 -1
  33. package/dist/evidence/ui-visual/embed.d.ts +65 -0
  34. package/dist/evidence/ui-visual/embed.d.ts.map +1 -0
  35. package/dist/evidence/ui-visual/embed.js +176 -0
  36. package/dist/evidence/ui-visual/embed.js.map +1 -0
  37. package/dist/evidence/ui-visual/index.d.ts +2 -0
  38. package/dist/evidence/ui-visual/index.d.ts.map +1 -0
  39. package/dist/evidence/ui-visual/index.js +6 -0
  40. package/dist/evidence/ui-visual/index.js.map +1 -0
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/mcp/cycle-doc/parser.d.ts +3 -3
  46. package/dist/mcp/cycle-doc/parser.d.ts.map +1 -1
  47. package/dist/mcp/cycle-doc/parser.js +2 -2
  48. package/dist/mcp/cycle-doc/parser.js.map +1 -1
  49. package/dist/mcp/tools/doctor.d.ts +5 -0
  50. package/dist/mcp/tools/doctor.d.ts.map +1 -1
  51. package/dist/mcp/tools/doctor.js +10 -1
  52. package/dist/mcp/tools/doctor.js.map +1 -1
  53. package/dist/mcp/tools/review-bypass.d.ts +5 -0
  54. package/dist/mcp/tools/review-bypass.d.ts.map +1 -1
  55. package/dist/mcp/tools/review-bypass.js +9 -1
  56. package/dist/mcp/tools/review-bypass.js.map +1 -1
  57. package/dist/mode/apply.d.ts +8 -0
  58. package/dist/mode/apply.d.ts.map +1 -0
  59. package/dist/mode/apply.js +118 -0
  60. package/dist/mode/apply.js.map +1 -0
  61. package/dist/mode/context.d.ts +50 -0
  62. package/dist/mode/context.d.ts.map +1 -0
  63. package/dist/mode/context.js +127 -0
  64. package/dist/mode/context.js.map +1 -0
  65. package/dist/mode/critic-registration.d.ts +66 -0
  66. package/dist/mode/critic-registration.d.ts.map +1 -0
  67. package/dist/mode/critic-registration.js +279 -0
  68. package/dist/mode/critic-registration.js.map +1 -0
  69. package/dist/mode/guard.d.ts +15 -0
  70. package/dist/mode/guard.d.ts.map +1 -0
  71. package/dist/mode/guard.js +160 -0
  72. package/dist/mode/guard.js.map +1 -0
  73. package/dist/mode/init.d.ts.map +1 -1
  74. package/dist/mode/init.js +14 -5
  75. package/dist/mode/init.js.map +1 -1
  76. package/dist/mode/loadConfig.d.ts +34 -0
  77. package/dist/mode/loadConfig.d.ts.map +1 -0
  78. package/dist/mode/loadConfig.js +38 -0
  79. package/dist/mode/loadConfig.js.map +1 -0
  80. package/dist/mode/prompts/designer-baseline.md +47 -0
  81. package/dist/mode/resolve.d.ts +1 -1
  82. package/dist/mode/resolve.d.ts.map +1 -1
  83. package/dist/mode/resolve.js +19 -3
  84. package/dist/mode/resolve.js.map +1 -1
  85. package/dist/mode/scope-policy.d.ts +41 -0
  86. package/dist/mode/scope-policy.d.ts.map +1 -0
  87. package/dist/mode/scope-policy.js +97 -0
  88. package/dist/mode/scope-policy.js.map +1 -0
  89. package/dist/mode/status.d.ts.map +1 -1
  90. package/dist/mode/status.js +2 -9
  91. package/dist/mode/status.js.map +1 -1
  92. package/dist/onboard/validate.d.ts +24 -6
  93. package/dist/onboard/validate.d.ts.map +1 -1
  94. package/dist/onboard/validate.js +87 -14
  95. package/dist/onboard/validate.js.map +1 -1
  96. package/dist/skills/config.d.ts +2 -113
  97. package/dist/skills/config.d.ts.map +1 -1
  98. package/dist/skills/config.js +19 -62
  99. package/dist/skills/config.js.map +1 -1
  100. package/dist/skills/index.d.ts +1 -1
  101. package/dist/skills/index.d.ts.map +1 -1
  102. package/dist/skills/index.js +1 -1
  103. package/dist/skills/index.js.map +1 -1
  104. package/dist/skills/install.d.ts.map +1 -1
  105. package/dist/skills/install.js +7 -0
  106. package/dist/skills/install.js.map +1 -1
  107. package/package.json +2 -2
  108. package/skills/designer-brief/SKILL.md.tmpl +74 -0
  109. package/skills/designer-brief/skill.json +17 -0
  110. package/skills/designer-build/SKILL.md.tmpl +63 -0
  111. package/skills/designer-build/skill.json +17 -0
  112. package/skills/designer-handoff/SKILL.md.tmpl +64 -0
  113. package/skills/designer-handoff/skill.json +17 -0
  114. package/skills/designer-ship/SKILL.md.tmpl +77 -0
  115. package/skills/designer-ship/skill.json +17 -0
  116. package/skills/objectives/SKILL.md.tmpl +16 -1
  117. package/skills/verify/producer/ui-visual-surfaces.ts +261 -0
  118. package/skills/verify/producer/ui-visual.config.ts +22 -0
  119. package/skills/verify/producer/ui-visual.producer.spec.ts +137 -0
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Reusable **`ui-visual` (Designer Mode) verification-route producer** (cycle 27
3
+ * Phase C).
4
+ *
5
+ * The Designer-Mode sibling of `ui-route.producer.spec.ts`. Same evidence shape
6
+ * and the same shared plumbing (`playwright-route.sh`, pointed here via
7
+ * `DF_UI_ROUTE_CONFIG=ui-visual.config.ts`), with ONE difference that makes it
8
+ * usable by a non-technical operator: the capture surfaces are **auto-derived**
9
+ * from the changed Next.js app-router files (`ui-visual-surfaces.ts`) instead of a
10
+ * hand-authored `SURFACES[]`. A changed `app/pricing/page.tsx` is captured at
11
+ * `/pricing`; the designer edits no config.
12
+ *
13
+ * For each derived surface it captures the required floor:
14
+ * (1) an **ARIA snapshot** (accessibility tree — structural, tamper-resistant),
15
+ * (2) an **after screenshot** at the SHA under review, plus an optional
16
+ * **before screenshot** baseline when `DF_UI_ROUTE_BEFORE_BASE_URL` is set
17
+ * (the before/after pair the PR embed helper renders for humans).
18
+ *
19
+ * Fail-closed coverage (see `planCapture`): a changed product-UI path that maps to
20
+ * NO route (a bare component, a non-`app/` `*.tsx`), or a DYNAMIC page (`[slug]` /
21
+ * `[...all]`), BLOCKS the route — auto-derivation can evidence neither by rendering
22
+ * an unrelated surface. Dynamic pages are unsupported by this auto-derive route, so
23
+ * capture them with the engineer `playwright` route (hand-authored surfaces); cover
24
+ * a component by also touching the page(s) that render it. Never passes with zero
25
+ * evidence: a harness-only or signal-less run smoke-captures the home surface.
26
+ *
27
+ * ── CONSUMER REFERENCE FILE — copy into your repo (with `ui-visual-surfaces.ts`
28
+ * and `ui-visual.config.ts`) and own it. `df skills install verify` does NOT
29
+ * overwrite it.
30
+ */
31
+ import { test, expect, type Page } from "@playwright/test";
32
+ import { mkdirSync, writeFileSync } from "node:fs";
33
+ import { join } from "node:path";
34
+ import {
35
+ deriveSurfacesFromChangedPaths,
36
+ planCapture,
37
+ type DerivedSurface,
38
+ } from "./ui-visual-surfaces";
39
+
40
+ const SHA = process.env.DF_UI_ROUTE_SHA ?? "unknown";
41
+ const OUT_DIR =
42
+ process.env.DF_UI_ROUTE_OUT ?? `agent-reviews/quality-gates/ui/${SHA}`;
43
+ const BEFORE_BASE_URL = process.env.DF_UI_ROUTE_BEFORE_BASE_URL?.replace(/\/$/, "");
44
+
45
+ const CHANGED_UI_PATHS = (process.env.DF_UI_ROUTE_CHANGED_PATHS ?? "")
46
+ .split(/\r?\n/)
47
+ .map((p) => p.trim())
48
+ .filter(Boolean);
49
+
50
+ const partition = deriveSurfacesFromChangedPaths(CHANGED_UI_PATHS);
51
+
52
+ // The capture decision + fail-closed contract live in the pure, unit-tested
53
+ // `planCapture`: a dynamic-page change FAILS CLOSED (it has no auto-navigable URL
54
+ // — see the module header) instead of "passing" on an unrelated capture. Never
55
+ // zero evidence for a real static change.
56
+ const plan = planCapture(partition);
57
+ const CAPTURE_SURFACES: DerivedSurface[] = plan.capture;
58
+
59
+ function routeOutDir(slug: string): string {
60
+ return join(OUT_DIR, slug);
61
+ }
62
+
63
+ // FAIL-CLOSED coverage gate: when `planCapture` cannot produce real evidence for a
64
+ // changed path (an uncovered bare component, or a dynamic page with no concrete
65
+ // surface), the route FAILS rather than "passing" on an unrelated home capture.
66
+ test("ui-visual coverage — every changed UI path maps to a real capture or is exempt", async () => {
67
+ if (plan.failClosed) throw new Error(plan.failClosed.message);
68
+ expect(plan.failClosed).toBeNull();
69
+ });
70
+
71
+ async function captureBefore(page: Page, surface: DerivedSurface, dir: string): Promise<void> {
72
+ if (!BEFORE_BASE_URL) return;
73
+ const beforeUrl = `${BEFORE_BASE_URL}${surface.path}`;
74
+ try {
75
+ await page.goto(beforeUrl, { waitUntil: "networkidle", timeout: 30_000 });
76
+ await page.screenshot({ path: join(dir, "before.png"), fullPage: true });
77
+ } catch (err) {
78
+ // The baseline is best-effort; a missing/unreachable baseline must not fail
79
+ // the route (the ARIA + after capture is the floor). Record why.
80
+ test.info().annotations.push({
81
+ type: "before-capture-skipped",
82
+ description: `baseline ${beforeUrl} unreachable: ${
83
+ err instanceof Error ? err.message : String(err)
84
+ }`,
85
+ });
86
+ }
87
+ }
88
+
89
+ for (const surface of CAPTURE_SURFACES) {
90
+ test(`ui-visual evidence — ${surface.slug} (${surface.path})`, async ({ page }) => {
91
+ const dir = routeOutDir(surface.slug);
92
+ mkdirSync(dir, { recursive: true });
93
+
94
+ // --- (optional) BEFORE baseline from the configured origin ---
95
+ await captureBefore(page, surface, dir);
96
+
97
+ // --- AFTER: the SHA under review ---
98
+ await page.goto(surface.path, { waitUntil: "networkidle", timeout: 30_000 });
99
+
100
+ // Structural render floor: a real page exposes a `main` landmark. This is a
101
+ // relaxed, copy-STABLE assertion (no per-surface heading to hand-author) that
102
+ // still fails a blank screen / crash / error boundary — the point of a gate.
103
+ await expect(page.getByRole("main").first()).toBeVisible({ timeout: 15_000 });
104
+
105
+ // Floor evidence #1 — ARIA snapshot (accessibility tree). Structural,
106
+ // diff-able, hard to stage. Non-trivial, then persisted.
107
+ const ariaSnapshot = await page.locator("body").ariaSnapshot();
108
+ expect(ariaSnapshot.trim().length).toBeGreaterThan(0);
109
+ writeFileSync(join(dir, "aria.snapshot.txt"), `${ariaSnapshot}\n`, "utf8");
110
+
111
+ // Floor evidence #2 — the "after" screenshot bound to the gated SHA.
112
+ await page.screenshot({ path: join(dir, "after.png"), fullPage: true });
113
+
114
+ writeFileSync(
115
+ join(dir, "meta.json"),
116
+ `${JSON.stringify(
117
+ {
118
+ surface: surface.slug,
119
+ path: surface.path,
120
+ covers: surface.covers,
121
+ sha: SHA,
122
+ capturedAt: new Date().toISOString(),
123
+ baseURL: test.info().project.use.baseURL ?? null,
124
+ beforeBaseURL: BEFORE_BASE_URL ?? null,
125
+ ariaSnapshotBytes: Buffer.byteLength(ariaSnapshot, "utf8"),
126
+ evidenceKind: "playwright",
127
+ route: "ui-visual",
128
+ floor: ["aria-snapshot", "after-screenshot"],
129
+ beforeScreenshot: BEFORE_BASE_URL ? "before.png" : null,
130
+ },
131
+ null,
132
+ 2,
133
+ )}\n`,
134
+ "utf8",
135
+ );
136
+ });
137
+ }