@sweny-ai/core 0.1.77 → 0.1.78

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/dist/browser.d.ts +11 -5
  2. package/dist/browser.js +11 -11
  3. package/dist/claude.d.ts +16 -0
  4. package/dist/claude.js +98 -9
  5. package/dist/cli/config.d.ts +22 -0
  6. package/dist/cli/config.js +56 -9
  7. package/dist/cli/main.d.ts +1 -1
  8. package/dist/cli/main.js +56 -57
  9. package/dist/cli/marketplace.js +35 -9
  10. package/dist/cli/publish.d.ts +10 -0
  11. package/dist/cli/publish.js +22 -14
  12. package/dist/loader.d.ts +40 -0
  13. package/dist/loader.js +73 -0
  14. package/dist/mcp-catalog.d.ts +47 -0
  15. package/dist/mcp-catalog.js +304 -0
  16. package/dist/mcp.d.ts +6 -9
  17. package/dist/mcp.js +24 -314
  18. package/dist/schema.d.ts +183 -151
  19. package/dist/schema.js +49 -7
  20. package/dist/skills/custom-loader.d.ts +40 -0
  21. package/dist/skills/custom-loader.js +107 -32
  22. package/dist/skills/index.d.ts +13 -1
  23. package/dist/skills/index.js +12 -3
  24. package/dist/studio.js +4 -1
  25. package/dist/templates.d.ts +29 -8
  26. package/dist/templates.js +30 -20
  27. package/dist/types.d.ts +12 -0
  28. package/dist/verify.js +42 -4
  29. package/package.json +8 -4
  30. package/dist/__tests__/cascade.test.d.ts +0 -11
  31. package/dist/__tests__/cascade.test.js +0 -452
  32. package/dist/__tests__/claude.test.d.ts +0 -1
  33. package/dist/__tests__/claude.test.js +0 -427
  34. package/dist/__tests__/custom-loader.test.d.ts +0 -1
  35. package/dist/__tests__/custom-loader.test.js +0 -116
  36. package/dist/__tests__/executor.test.d.ts +0 -1
  37. package/dist/__tests__/executor.test.js +0 -1635
  38. package/dist/__tests__/integration/datadog.integration.test.d.ts +0 -1
  39. package/dist/__tests__/integration/datadog.integration.test.js +0 -23
  40. package/dist/__tests__/integration/e2e-workflow.integration.test.d.ts +0 -1
  41. package/dist/__tests__/integration/e2e-workflow.integration.test.js +0 -75
  42. package/dist/__tests__/integration/github.integration.test.d.ts +0 -1
  43. package/dist/__tests__/integration/github.integration.test.js +0 -37
  44. package/dist/__tests__/integration/harness.d.ts +0 -24
  45. package/dist/__tests__/integration/harness.js +0 -34
  46. package/dist/__tests__/integration/linear.integration.test.d.ts +0 -1
  47. package/dist/__tests__/integration/linear.integration.test.js +0 -15
  48. package/dist/__tests__/integration/sentry.integration.test.d.ts +0 -1
  49. package/dist/__tests__/integration/sentry.integration.test.js +0 -20
  50. package/dist/__tests__/integration/slack.integration.test.d.ts +0 -1
  51. package/dist/__tests__/integration/slack.integration.test.js +0 -22
  52. package/dist/__tests__/integration/sources.integration.test.d.ts +0 -1
  53. package/dist/__tests__/integration/sources.integration.test.js +0 -123
  54. package/dist/__tests__/publish.test.d.ts +0 -1
  55. package/dist/__tests__/publish.test.js +0 -180
  56. package/dist/__tests__/requires.test.d.ts +0 -1
  57. package/dist/__tests__/requires.test.js +0 -82
  58. package/dist/__tests__/retry.test.d.ts +0 -1
  59. package/dist/__tests__/retry.test.js +0 -213
  60. package/dist/__tests__/schema.test.d.ts +0 -1
  61. package/dist/__tests__/schema.test.js +0 -600
  62. package/dist/__tests__/skill-config-integration.test.d.ts +0 -1
  63. package/dist/__tests__/skill-config-integration.test.js +0 -204
  64. package/dist/__tests__/skills-index.test.d.ts +0 -1
  65. package/dist/__tests__/skills-index.test.js +0 -119
  66. package/dist/__tests__/skills.test.d.ts +0 -1
  67. package/dist/__tests__/skills.test.js +0 -565
  68. package/dist/__tests__/spec-conformance.test.d.ts +0 -18
  69. package/dist/__tests__/spec-conformance.test.js +0 -1084
  70. package/dist/__tests__/studio.test.d.ts +0 -1
  71. package/dist/__tests__/studio.test.js +0 -403
  72. package/dist/__tests__/templates.test.d.ts +0 -1
  73. package/dist/__tests__/templates.test.js +0 -49
  74. package/dist/__tests__/testing.test.d.ts +0 -1
  75. package/dist/__tests__/testing.test.js +0 -242
  76. package/dist/__tests__/verify.test.d.ts +0 -1
  77. package/dist/__tests__/verify.test.js +0 -517
  78. package/dist/__tests__/version-consistency.test.d.ts +0 -1
  79. package/dist/__tests__/version-consistency.test.js +0 -312
  80. package/dist/__tests__/workflow-builder.test.d.ts +0 -1
  81. package/dist/__tests__/workflow-builder.test.js +0 -110
  82. package/dist/__tests__/workflow-yaml.test.d.ts +0 -1
  83. package/dist/__tests__/workflow-yaml.test.js +0 -201
  84. package/dist/cli/__tests__/diagram.test.d.ts +0 -1
  85. package/dist/cli/__tests__/diagram.test.js +0 -225
  86. package/dist/cli/__tests__/report-cloud.test.d.ts +0 -1
  87. package/dist/cli/__tests__/report-cloud.test.js +0 -165
  88. package/dist/cli/__tests__/upgrade.test.d.ts +0 -1
  89. package/dist/cli/__tests__/upgrade.test.js +0 -317
  90. package/dist/cli/__tests__/version-check.test.d.ts +0 -1
  91. package/dist/cli/__tests__/version-check.test.js +0 -209
  92. package/dist/cli/config.test.d.ts +0 -1
  93. package/dist/cli/config.test.js +0 -200
  94. package/dist/cli/credentials.test.d.ts +0 -1
  95. package/dist/cli/credentials.test.js +0 -172
  96. package/dist/cli/e2e.test.d.ts +0 -1
  97. package/dist/cli/e2e.test.js +0 -690
  98. package/dist/cli/marketplace.test.d.ts +0 -1
  99. package/dist/cli/marketplace.test.js +0 -355
  100. package/dist/cli/new.test.d.ts +0 -1
  101. package/dist/cli/new.test.js +0 -1043
  102. package/dist/cli/output.test.d.ts +0 -1
  103. package/dist/cli/output.test.js +0 -180
  104. package/dist/cli/publish.test.d.ts +0 -1
  105. package/dist/cli/publish.test.js +0 -610
  106. package/dist/cli/renderer.test.d.ts +0 -1
  107. package/dist/cli/renderer.test.js +0 -302
  108. package/dist/executor.test.d.ts +0 -1
  109. package/dist/executor.test.js +0 -618
  110. package/dist/mcp.test.d.ts +0 -1
  111. package/dist/mcp.test.js +0 -735
  112. package/dist/mermaid.test.d.ts +0 -1
  113. package/dist/mermaid.test.js +0 -256
  114. package/dist/sources.test.d.ts +0 -1
  115. package/dist/sources.test.js +0 -265
  116. package/dist/sources.validation.test.d.ts +0 -12
  117. package/dist/sources.validation.test.js +0 -380
  118. package/dist/workflow-builder.test.d.ts +0 -1
  119. package/dist/workflow-builder.test.js +0 -123
@@ -1 +0,0 @@
1
- export {};
@@ -1,355 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
- import * as fs from "node:fs";
3
- import * as path from "node:path";
4
- import * as os from "node:os";
5
- import { fetchMarketplaceWorkflow, fetchMarketplaceIndex, computeProviderMismatch, buildAdaptPrompt, adaptWorkflowInteractive, installMarketplaceWorkflow, MARKETPLACE_RAW_BASE, } from "./marketplace.js";
6
- vi.mock("@clack/prompts", () => ({
7
- select: vi.fn(),
8
- text: vi.fn(),
9
- spinner: () => ({ start: vi.fn(), stop: vi.fn() }),
10
- log: { message: vi.fn(), error: vi.fn() },
11
- isCancel: (v) => v === Symbol.for("cancel"),
12
- }));
13
- vi.mock("../workflow-builder.js", () => ({
14
- refineWorkflow: vi.fn(),
15
- }));
16
- describe("fetchMarketplaceWorkflow", () => {
17
- let fetchSpy;
18
- beforeEach(() => {
19
- fetchSpy = vi.spyOn(globalThis, "fetch").mockImplementation(async () => {
20
- return new Response("id: pr-review\nname: PR Review\n", { status: 200 });
21
- });
22
- });
23
- afterEach(() => fetchSpy.mockRestore());
24
- it("fetches workflow YAML from raw GitHub", async () => {
25
- const result = await fetchMarketplaceWorkflow("pr-review");
26
- expect(result.id).toBe("pr-review");
27
- expect(result.yaml).toContain("id: pr-review");
28
- expect(fetchSpy).toHaveBeenCalledWith(`${MARKETPLACE_RAW_BASE}/workflows/pr-review.yml`);
29
- });
30
- });
31
- describe("fetchMarketplaceWorkflow errors", () => {
32
- let fetchSpy;
33
- afterEach(() => fetchSpy?.mockRestore());
34
- it("throws not-found on 404", async () => {
35
- fetchSpy = vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response("", { status: 404 }));
36
- await expect(fetchMarketplaceWorkflow("missing")).rejects.toMatchObject({
37
- kind: "not-found",
38
- message: expect.stringContaining("missing"),
39
- });
40
- });
41
- it("throws rate-limit on 403 with X-RateLimit-Remaining: 0", async () => {
42
- fetchSpy = vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response("", {
43
- status: 403,
44
- headers: { "X-RateLimit-Remaining": "0", "X-RateLimit-Reset": "1234567890" },
45
- }));
46
- await expect(fetchMarketplaceWorkflow("pr-review")).rejects.toMatchObject({
47
- kind: "rate-limit",
48
- retryAfter: 1234567890,
49
- });
50
- });
51
- it("throws network error when fetch rejects", async () => {
52
- fetchSpy = vi.spyOn(globalThis, "fetch").mockImplementation(async () => {
53
- throw new TypeError("fetch failed");
54
- });
55
- await expect(fetchMarketplaceWorkflow("pr-review")).rejects.toMatchObject({
56
- kind: "network",
57
- });
58
- });
59
- });
60
- describe("fetchMarketplaceIndex", () => {
61
- afterEach(() => vi.restoreAllMocks());
62
- it("fetches and parses index.json", async () => {
63
- const body = JSON.stringify([
64
- { id: "pr-review", name: "PR Review", description: "Reviews PRs", skills: ["github"] },
65
- { id: "issue-triage", name: "Issue Triage", description: "Triages issues", skills: ["github"] },
66
- ]);
67
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(body, { status: 200 }));
68
- const entries = await fetchMarketplaceIndex();
69
- expect(entries).toHaveLength(2);
70
- expect(entries[0]).toMatchObject({ id: "pr-review", name: "PR Review" });
71
- });
72
- it("throws not-found when index.json is missing", async () => {
73
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response("", { status: 404 }));
74
- await expect(fetchMarketplaceIndex()).rejects.toMatchObject({ kind: "not-found" });
75
- });
76
- });
77
- const testSkills = [
78
- { id: "linear", name: "Linear", description: "", category: "tasks", config: {}, tools: [] },
79
- {
80
- id: "github-issues",
81
- name: "GitHub Issues",
82
- description: "",
83
- category: "tasks",
84
- config: {},
85
- tools: [],
86
- },
87
- { id: "github", name: "GitHub", description: "", category: "git", config: {}, tools: [] },
88
- {
89
- id: "datadog",
90
- name: "Datadog",
91
- description: "",
92
- category: "observability",
93
- config: {},
94
- tools: [],
95
- },
96
- { id: "sentry", name: "Sentry", description: "", category: "observability", config: {}, tools: [] },
97
- ];
98
- describe("computeProviderMismatch", () => {
99
- it("returns empty array when all workflow skills match config", () => {
100
- const mismatches = computeProviderMismatch(["github", "github-issues"], { "source-control-provider": "github", "issue-tracker-provider": "github-issues" }, testSkills);
101
- expect(mismatches).toEqual([]);
102
- });
103
- it("detects tasks mismatch (workflow=linear, config=github-issues)", () => {
104
- const mismatches = computeProviderMismatch(["linear"], { "issue-tracker-provider": "github-issues" }, testSkills);
105
- expect(mismatches).toEqual([
106
- {
107
- category: "tasks",
108
- configKey: "issue-tracker-provider",
109
- workflowSkill: "linear",
110
- userProvider: "github-issues",
111
- },
112
- ]);
113
- });
114
- it("detects observability mismatch and ignores general-category skills", () => {
115
- const mismatches = computeProviderMismatch(["datadog"], { "observability-provider": "sentry" }, testSkills);
116
- expect(mismatches).toEqual([
117
- {
118
- category: "observability",
119
- configKey: "observability-provider",
120
- workflowSkill: "datadog",
121
- userProvider: "sentry",
122
- },
123
- ]);
124
- });
125
- it("skips mismatch when the user has no provider set for that role", () => {
126
- const mismatches = computeProviderMismatch(["linear"], {}, testSkills);
127
- expect(mismatches).toEqual([]);
128
- });
129
- it("ignores workflow skills not in the available skill registry", () => {
130
- const mismatches = computeProviderMismatch(["unknown-skill"], { "issue-tracker-provider": "github-issues" }, testSkills);
131
- expect(mismatches).toEqual([]);
132
- });
133
- });
134
- describe("buildAdaptPrompt", () => {
135
- it("describes single mismatch", () => {
136
- const prompt = buildAdaptPrompt([
137
- {
138
- category: "tasks",
139
- configKey: "issue-tracker-provider",
140
- workflowSkill: "linear",
141
- userProvider: "github-issues",
142
- },
143
- ]);
144
- expect(prompt).toContain("linear");
145
- expect(prompt).toContain("github-issues");
146
- expect(prompt).toContain("issue-tracker");
147
- expect(prompt.toLowerCase()).toContain("rewrite");
148
- });
149
- it("describes multiple mismatches", () => {
150
- const prompt = buildAdaptPrompt([
151
- {
152
- category: "tasks",
153
- configKey: "issue-tracker-provider",
154
- workflowSkill: "linear",
155
- userProvider: "github-issues",
156
- },
157
- {
158
- category: "observability",
159
- configKey: "observability-provider",
160
- workflowSkill: "datadog",
161
- userProvider: "sentry",
162
- },
163
- ]);
164
- expect(prompt).toContain("linear");
165
- expect(prompt).toContain("datadog");
166
- expect(prompt).toContain("sentry");
167
- });
168
- });
169
- describe("adaptWorkflowInteractive", () => {
170
- beforeEach(() => vi.clearAllMocks());
171
- const sampleWorkflow = {
172
- id: "pr-review",
173
- name: "PR Review",
174
- description: "",
175
- entry: "start",
176
- nodes: { start: { name: "Start", instruction: "x", skills: [] } },
177
- edges: [],
178
- };
179
- it("returns the workflow when user accepts on first render", async () => {
180
- const p = await import("@clack/prompts");
181
- p.select.mockResolvedValueOnce("accept");
182
- const claudeStub = { run: vi.fn() };
183
- const result = await adaptWorkflowInteractive(sampleWorkflow, {
184
- claude: claudeStub,
185
- skills: [],
186
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
187
- });
188
- expect(result).toEqual(sampleWorkflow);
189
- });
190
- it("returns null when user cancels", async () => {
191
- const p = await import("@clack/prompts");
192
- p.select.mockResolvedValueOnce("cancel");
193
- const claudeStub = { run: vi.fn() };
194
- const result = await adaptWorkflowInteractive(sampleWorkflow, {
195
- claude: claudeStub,
196
- skills: [],
197
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
198
- });
199
- expect(result).toBeNull();
200
- });
201
- it("calls refineWorkflow when user picks 'refine'", async () => {
202
- const p = await import("@clack/prompts");
203
- const wb = await import("../workflow-builder.js");
204
- p.select.mockResolvedValueOnce("refine").mockResolvedValueOnce("accept");
205
- p.text.mockResolvedValueOnce("make it better");
206
- wb.refineWorkflow.mockResolvedValueOnce(sampleWorkflow);
207
- const claudeStub = { run: vi.fn() };
208
- const result = await adaptWorkflowInteractive(sampleWorkflow, {
209
- claude: claudeStub,
210
- skills: [],
211
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
212
- });
213
- expect(wb.refineWorkflow).toHaveBeenCalledWith(sampleWorkflow, "make it better", expect.any(Object));
214
- expect(result).toEqual(sampleWorkflow);
215
- });
216
- });
217
- describe("installMarketplaceWorkflow", () => {
218
- const tmpDirs = [];
219
- afterEach(() => {
220
- for (const d of tmpDirs)
221
- fs.rmSync(d, { recursive: true, force: true });
222
- tmpDirs.length = 0;
223
- vi.restoreAllMocks();
224
- });
225
- function tmp() {
226
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), "sweny-install-"));
227
- tmpDirs.push(dir);
228
- return dir;
229
- }
230
- const sampleYaml = "id: pr-review\nname: PR Review\ndescription: Review PRs\nentry: start\n" +
231
- "nodes:\n start:\n name: Start\n instruction: hi\n skills: [github]\nedges: []\n";
232
- it("installs workflow as-is when no mismatch and no .sweny.yml", async () => {
233
- const cwd = tmp();
234
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(sampleYaml, { status: 200 }));
235
- const result = await installMarketplaceWorkflow("pr-review", {
236
- cwd,
237
- availableSkills: testSkills,
238
- claude: null,
239
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
240
- });
241
- expect(result.installed).toBe(true);
242
- expect(result.adapted).toBe(false);
243
- expect(fs.existsSync(path.join(cwd, ".sweny.yml"))).toBe(true);
244
- expect(fs.existsSync(path.join(cwd, ".sweny", "workflows", "pr-review.yml"))).toBe(true);
245
- });
246
- it("warns and installs as-is when mismatch detected but no agent", async () => {
247
- const cwd = tmp();
248
- fs.writeFileSync(path.join(cwd, ".sweny.yml"), "issue-tracker-provider: github-issues\n");
249
- const yamlWithLinear = sampleYaml.replace("[github]", "[linear]");
250
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(yamlWithLinear, { status: 200 }));
251
- const warnings = [];
252
- const result = await installMarketplaceWorkflow("pr-review", {
253
- cwd,
254
- availableSkills: testSkills,
255
- claude: null,
256
- logger: {
257
- debug: () => { },
258
- info: () => { },
259
- warn: (m) => warnings.push(m),
260
- error: () => { },
261
- },
262
- });
263
- expect(result.installed).toBe(true);
264
- expect(result.adapted).toBe(false);
265
- expect(result.mismatches).toHaveLength(1);
266
- expect(warnings.some((w) => w.includes("linear"))).toBe(true);
267
- });
268
- it("throws with not-found kind when workflow missing", async () => {
269
- const cwd = tmp();
270
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response("", { status: 404 }));
271
- await expect(installMarketplaceWorkflow("nope", {
272
- cwd,
273
- availableSkills: testSkills,
274
- claude: null,
275
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
276
- })).rejects.toMatchObject({ kind: "not-found" });
277
- });
278
- // ── I1: pre-computed provider inference ────────────────────────────────
279
- it("uses inferredSourceControl instead of skill-based inference for .sweny.yml", async () => {
280
- // Workflow references github skill, but caller says the remote is gitlab.
281
- // The written .sweny.yml must say gitlab, not github.
282
- const cwd = tmp();
283
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(sampleYaml, { status: 200 }));
284
- await installMarketplaceWorkflow("pr-review", {
285
- cwd,
286
- availableSkills: testSkills,
287
- claude: null,
288
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
289
- inferredSourceControl: "gitlab",
290
- inferredIssueTracker: "github-issues",
291
- inferredObservability: null,
292
- });
293
- const swenyYml = fs.readFileSync(path.join(cwd, ".sweny.yml"), "utf-8");
294
- expect(swenyYml).toContain("source-control-provider: gitlab");
295
- // skill-based fallback would have written "github" — verify it did NOT
296
- expect(swenyYml).not.toContain("source-control-provider: github");
297
- });
298
- it("falls back to skill-based inference when inferredSourceControl is absent", async () => {
299
- // Workflow references github skill, no pre-computed values → should infer github
300
- const cwd = tmp();
301
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(sampleYaml, { status: 200 }));
302
- await installMarketplaceWorkflow("pr-review", {
303
- cwd,
304
- availableSkills: testSkills,
305
- claude: null,
306
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
307
- });
308
- const swenyYml = fs.readFileSync(path.join(cwd, ".sweny.yml"), "utf-8");
309
- expect(swenyYml).toContain("source-control-provider: github");
310
- });
311
- // ── I2: overwrite protection ────────────────────────────────────────────
312
- it("returns alreadyExists=true without overwriting when overwrite is false (default)", async () => {
313
- const cwd = tmp();
314
- // Pre-create the workflow file with distinct content
315
- const wfDir = path.join(cwd, ".sweny", "workflows");
316
- fs.mkdirSync(wfDir, { recursive: true });
317
- const wfPath = path.join(wfDir, "pr-review.yml");
318
- fs.writeFileSync(wfPath, "# original content\n", "utf-8");
319
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(sampleYaml, { status: 200 }));
320
- const result = await installMarketplaceWorkflow("pr-review", {
321
- cwd,
322
- availableSkills: testSkills,
323
- claude: null,
324
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
325
- // overwrite: false is the default — omitting it intentionally
326
- });
327
- expect(result.installed).toBe(false);
328
- expect(result.alreadyExists).toBe(true);
329
- expect(result.workflowPath).toBe(wfPath);
330
- // File must be unchanged
331
- expect(fs.readFileSync(wfPath, "utf-8")).toBe("# original content\n");
332
- });
333
- it("overwrites existing workflow file when overwrite is true", async () => {
334
- const cwd = tmp();
335
- // Pre-create the workflow file with stale content
336
- const wfDir = path.join(cwd, ".sweny", "workflows");
337
- fs.mkdirSync(wfDir, { recursive: true });
338
- const wfPath = path.join(wfDir, "pr-review.yml");
339
- fs.writeFileSync(wfPath, "# stale content\n", "utf-8");
340
- vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(sampleYaml, { status: 200 }));
341
- const result = await installMarketplaceWorkflow("pr-review", {
342
- cwd,
343
- availableSkills: testSkills,
344
- claude: null,
345
- logger: { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } },
346
- overwrite: true,
347
- });
348
- expect(result.installed).toBe(true);
349
- expect(result.alreadyExists).toBeUndefined();
350
- // File must contain the new content
351
- const written = fs.readFileSync(wfPath, "utf-8");
352
- expect(written).toContain("PR Review");
353
- expect(written).not.toContain("stale content");
354
- });
355
- });
@@ -1 +0,0 @@
1
- export {};