create-backbone-template 0.1.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 (182) hide show
  1. package/README.md +33 -0
  2. package/bin/create-backbone-template.js +5 -0
  3. package/package.json +30 -0
  4. package/src/create-backbone-template.js +204 -0
  5. package/template/.agents/skills/agent-browser/SKILL.md +55 -0
  6. package/template/.agents/skills/create-plan/SKILL.md +52 -0
  7. package/template/.agents/skills/create-plan/agents/openai.yaml +4 -0
  8. package/template/.agents/skills/create-pr-presentation/SKILL.md +86 -0
  9. package/template/.agents/skills/create-pr-presentation/agents/openai.yaml +4 -0
  10. package/template/.agents/skills/implement-plan/SKILL.md +26 -0
  11. package/template/.agents/skills/implement-plan/agents/openai.yaml +4 -0
  12. package/template/.agents/skills/review-plan/SKILL.md +38 -0
  13. package/template/.agents/skills/review-plan/agents/openai.yaml +4 -0
  14. package/template/.env.schema +30 -0
  15. package/template/.env.test +6 -0
  16. package/template/.oxlintrc.json +67 -0
  17. package/template/.vscode/extensions.json +3 -0
  18. package/template/.vscode/settings.json +23 -0
  19. package/template/AGENTS.md +55 -0
  20. package/template/Cargo.lock +2648 -0
  21. package/template/Cargo.toml +29 -0
  22. package/template/Justfile +140 -0
  23. package/template/README.md +72 -0
  24. package/template/TODO.md +1 -0
  25. package/template/_gitignore +12 -0
  26. package/template/buf.gen.yaml +7 -0
  27. package/template/buf.yaml +10 -0
  28. package/template/client/.oxfmtrc.json +8 -0
  29. package/template/client/.oxlintrc.json +57 -0
  30. package/template/client/README.md +19 -0
  31. package/template/client/_gitignore +5 -0
  32. package/template/client/index.html +12 -0
  33. package/template/client/package.json +47 -0
  34. package/template/client/packages/design-system/package.json +19 -0
  35. package/template/client/packages/design-system/src/index.ts +2 -0
  36. package/template/client/packages/design-system-basic/package.json +18 -0
  37. package/template/client/packages/design-system-basic/src/button.stories.tsx +50 -0
  38. package/template/client/packages/design-system-basic/src/button.tsx +26 -0
  39. package/template/client/packages/design-system-basic/src/empty-state.stories.tsx +18 -0
  40. package/template/client/packages/design-system-basic/src/empty-state.tsx +17 -0
  41. package/template/client/packages/design-system-basic/src/form-field.stories.tsx +15 -0
  42. package/template/client/packages/design-system-basic/src/form-field.tsx +10 -0
  43. package/template/client/packages/design-system-basic/src/form.stories.tsx +27 -0
  44. package/template/client/packages/design-system-basic/src/form.tsx +9 -0
  45. package/template/client/packages/design-system-basic/src/heading.stories.tsx +14 -0
  46. package/template/client/packages/design-system-basic/src/heading.tsx +25 -0
  47. package/template/client/packages/design-system-basic/src/index.tsx +15 -0
  48. package/template/client/packages/design-system-basic/src/inline.stories.tsx +13 -0
  49. package/template/client/packages/design-system-basic/src/inline.tsx +5 -0
  50. package/template/client/packages/design-system-basic/src/layout.stories.tsx +24 -0
  51. package/template/client/packages/design-system-basic/src/layout.tsx +14 -0
  52. package/template/client/packages/design-system-basic/src/loader.stories.tsx +8 -0
  53. package/template/client/packages/design-system-basic/src/loader.tsx +11 -0
  54. package/template/client/packages/design-system-basic/src/navigation.stories.tsx +16 -0
  55. package/template/client/packages/design-system-basic/src/navigation.tsx +18 -0
  56. package/template/client/packages/design-system-basic/src/notice.stories.tsx +13 -0
  57. package/template/client/packages/design-system-basic/src/notice.tsx +5 -0
  58. package/template/client/packages/design-system-basic/src/stack.stories.tsx +17 -0
  59. package/template/client/packages/design-system-basic/src/stack.tsx +5 -0
  60. package/template/client/packages/design-system-basic/src/styles.css +254 -0
  61. package/template/client/packages/design-system-basic/src/text-input.stories.tsx +13 -0
  62. package/template/client/packages/design-system-basic/src/text-input.tsx +5 -0
  63. package/template/client/packages/design-system-basic/src/text.stories.tsx +21 -0
  64. package/template/client/packages/design-system-basic/src/text.tsx +5 -0
  65. package/template/client/packages/design-system-contract/package.json +15 -0
  66. package/template/client/packages/design-system-contract/src/button.ts +10 -0
  67. package/template/client/packages/design-system-contract/src/empty-state.ts +9 -0
  68. package/template/client/packages/design-system-contract/src/form-field.ts +9 -0
  69. package/template/client/packages/design-system-contract/src/form.ts +9 -0
  70. package/template/client/packages/design-system-contract/src/heading.ts +9 -0
  71. package/template/client/packages/design-system-contract/src/index.ts +13 -0
  72. package/template/client/packages/design-system-contract/src/inline.ts +7 -0
  73. package/template/client/packages/design-system-contract/src/layout.ts +8 -0
  74. package/template/client/packages/design-system-contract/src/loader.ts +7 -0
  75. package/template/client/packages/design-system-contract/src/navigation.ts +13 -0
  76. package/template/client/packages/design-system-contract/src/notice.ts +8 -0
  77. package/template/client/packages/design-system-contract/src/stack.ts +8 -0
  78. package/template/client/packages/design-system-contract/src/text-input.ts +5 -0
  79. package/template/client/packages/design-system-contract/src/text.ts +9 -0
  80. package/template/client/packages/design-system-lint/fixtures/invalid/external-ui-import.tsx +5 -0
  81. package/template/client/packages/design-system-lint/fixtures/invalid/raw-dom-jsx.tsx +3 -0
  82. package/template/client/packages/design-system-lint/fixtures/invalid/two-violations.tsx +7 -0
  83. package/template/client/packages/design-system-lint/fixtures/valid/design-system-only.tsx +13 -0
  84. package/template/client/packages/design-system-lint/package.json +23 -0
  85. package/template/client/packages/design-system-lint/src/check-design-system-architecture.ts +22 -0
  86. package/template/client/packages/design-system-lint/src/design-system-architecture.ts +286 -0
  87. package/template/client/packages/design-system-lint/src/oxlint-plugin.ts +11 -0
  88. package/template/client/packages/design-system-lint/src/page-architecture.ts +382 -0
  89. package/template/client/packages/design-system-lint/src/rules.ts +111 -0
  90. package/template/client/packages/design-system-lint/test/design-system-architecture.test.ts +243 -0
  91. package/template/client/packages/design-system-lint/test/oxlint-fixtures.test.ts +159 -0
  92. package/template/client/packages/design-system-lint/test/page-architecture.test.ts +175 -0
  93. package/template/client/packages/design-system-lint/test/rules.test.ts +65 -0
  94. package/template/client/packages/design-system-lint/tsconfig.json +29 -0
  95. package/template/client/src/App.tsx +77 -0
  96. package/template/client/src/design-system-components.test.tsx +75 -0
  97. package/template/client/src/gen/helloworld/v1/helloworld_pb.ts +63 -0
  98. package/template/client/src/main.tsx +18 -0
  99. package/template/client/src/pages/hello/hello-page.stories.tsx +20 -0
  100. package/template/client/src/pages/hello/hello-page.test.tsx +90 -0
  101. package/template/client/src/pages/hello/hello-page.tsx +126 -0
  102. package/template/client/src/pages/page.ts +20 -0
  103. package/template/client/src/testing/create-preview-events.test.ts +36 -0
  104. package/template/client/src/testing/create-preview-events.ts +30 -0
  105. package/template/client/src/vite-env.d.ts +1 -0
  106. package/template/client/tsconfig.json +32 -0
  107. package/template/client/vite.config.ts +21 -0
  108. package/template/client/vite.ladle.config.ts +5 -0
  109. package/template/e2e/.gherkin-lintrc +20 -0
  110. package/template/e2e/.oxfmtrc.json +15 -0
  111. package/template/e2e/.oxlintrc.json +37 -0
  112. package/template/e2e/_gitignore +4 -0
  113. package/template/e2e/features/helloworld.feature +10 -0
  114. package/template/e2e/package.json +42 -0
  115. package/template/e2e/playwright.config.ts +16 -0
  116. package/template/e2e/support/app-gherkin.ts +4 -0
  117. package/template/e2e/support/fixtures.ts +236 -0
  118. package/template/e2e/support/gherkin-fixtures/duplicate-id.feature +9 -0
  119. package/template/e2e/support/gherkin-fixtures/duplicate-id.spec.ts +7 -0
  120. package/template/e2e/support/gherkin-fixtures/extra-implementation.spec.ts +7 -0
  121. package/template/e2e/support/gherkin-fixtures/extra-step.spec.ts +10 -0
  122. package/template/e2e/support/gherkin-fixtures/happy-path.spec.ts +4 -0
  123. package/template/e2e/support/gherkin-fixtures/missing-id.feature +4 -0
  124. package/template/e2e/support/gherkin-fixtures/missing-id.spec.ts +7 -0
  125. package/template/e2e/support/gherkin-fixtures/missing-implementation.spec.ts +7 -0
  126. package/template/e2e/support/gherkin-fixtures/missing-step.spec.ts +7 -0
  127. package/template/e2e/support/gherkin-fixtures/playwright.config.ts +7 -0
  128. package/template/e2e/support/gherkin-fixtures/scenario-outline.feature +9 -0
  129. package/template/e2e/support/gherkin-fixtures/scenario-outline.spec.ts +7 -0
  130. package/template/e2e/support/gherkin-fixtures/step-mismatch.spec.ts +9 -0
  131. package/template/e2e/support/gherkin-fixtures/valid-implementations.ts +23 -0
  132. package/template/e2e/support/gherkin-fixtures/valid-scenarios.feature +26 -0
  133. package/template/e2e/support/gherkin.test.ts +184 -0
  134. package/template/e2e/support/gherkin.ts +321 -0
  135. package/template/e2e/support/oxlint-plugin.test.ts +328 -0
  136. package/template/e2e/support/oxlint-plugin.ts +485 -0
  137. package/template/e2e/tests/helloworld.spec.ts +39 -0
  138. package/template/e2e/tsconfig.json +26 -0
  139. package/template/e2e/tsconfig.oxlint-plugin.json +12 -0
  140. package/template/package.json +9 -0
  141. package/template/pnpm-lock.yaml +10723 -0
  142. package/template/pnpm-workspace.yaml +8 -0
  143. package/template/pr-slide/README.md +95 -0
  144. package/template/pr-slide/package.json +23 -0
  145. package/template/pr-slide/src/cli.js +262 -0
  146. package/template/pr-slide/src/generate-pr-deck.js +833 -0
  147. package/template/pr-slide/src/git-context.js +91 -0
  148. package/template/pr-slide/src/presentation-paths.js +9 -0
  149. package/template/pr-slide/src/presentations.js +53 -0
  150. package/template/pr-slide/test/generate-pr-deck.test.js +118 -0
  151. package/template/pr-slide/test/presentation-paths.test.js +14 -0
  152. package/template/pr-slide/test/presentations.test.js +50 -0
  153. package/template/proto/helloworld/v1/helloworld.proto +15 -0
  154. package/template/scripts/run-e2e.sh +10 -0
  155. package/template/server/Cargo.toml +26 -0
  156. package/template/server/build.rs +9 -0
  157. package/template/server/dylint/backbone_server_lints/.cargo/config.toml +6 -0
  158. package/template/server/dylint/backbone_server_lints/Cargo.lock +1581 -0
  159. package/template/server/dylint/backbone_server_lints/Cargo.toml +21 -0
  160. package/template/server/dylint/backbone_server_lints/README.md +5 -0
  161. package/template/server/dylint/backbone_server_lints/_gitignore +1 -0
  162. package/template/server/dylint/backbone_server_lints/rust-toolchain +3 -0
  163. package/template/server/dylint/backbone_server_lints/src/lib.rs +612 -0
  164. package/template/server/dylint/backbone_server_lints/ui/lib.rs +4 -0
  165. package/template/server/dylint/backbone_server_lints/ui/lib.stderr +10 -0
  166. package/template/server/dylint/backbone_server_lints/ui/long_file.rs +303 -0
  167. package/template/server/dylint/backbone_server_lints/ui/long_file.stderr +6 -0
  168. package/template/server/dylint/backbone_server_lints/ui/main.rs +59 -0
  169. package/template/server/dylint/backbone_server_lints/ui/main.stderr +85 -0
  170. package/template/server/migrations/20260520120000_create_projects.sql +12 -0
  171. package/template/server/migrations/20260524160000_create_hello_world_inputs.sql +12 -0
  172. package/template/server/src/config.rs +27 -0
  173. package/template/server/src/db/hello_world.rs +34 -0
  174. package/template/server/src/db/hello_world_tests.rs +11 -0
  175. package/template/server/src/db/mod.rs +39 -0
  176. package/template/server/src/lib.rs +10 -0
  177. package/template/server/src/main.rs +43 -0
  178. package/template/server/src/rpc/greeter/mod.rs +31 -0
  179. package/template/server/src/rpc/greeter/say_hello.rs +27 -0
  180. package/template/server/src/rpc/mod.rs +8 -0
  181. package/template/server/src/state.rs +13 -0
  182. package/template/skills-lock.json +11 -0
@@ -0,0 +1,91 @@
1
+ import { execFileSync } from "node:child_process";
2
+
3
+ import { classifyChangedFiles, inferPurpose } from "./generate-pr-deck.js";
4
+
5
+ export function collectGitContext(options = {}) {
6
+ const repoRoot = git(process.cwd(), ["rev-parse", "--show-toplevel"]);
7
+ const branch = git(repoRoot, ["branch", "--show-current"]) || "HEAD";
8
+ const base =
9
+ options.base ?? detectBase(repoRoot, ["main", "master", "origin/main", "origin/master"]);
10
+ const mergeBase = base ? maybeGit(repoRoot, ["merge-base", "HEAD", base]) : "";
11
+ const committed = mergeBase ? diffNames(repoRoot, [mergeBase + "..HEAD"]) : [];
12
+ const staged = diffNames(repoRoot, ["--cached"]);
13
+ const unstaged = diffNames(repoRoot, []);
14
+ const untracked = gitLines(repoRoot, ["ls-files", "--others", "--exclude-standard"]);
15
+ const changedFiles = unique([...committed, ...staged, ...unstaged, ...untracked])
16
+ .filter((file) => !file.startsWith(".agents/pr-presentation/"))
17
+ .sort();
18
+ const latestSubject = maybeGit(repoRoot, ["log", "-1", "--pretty=%s"]);
19
+ const title = options.title ?? titleFromBranch(branch, latestSubject);
20
+ const purpose = options.purpose ?? inferPurpose(changedFiles);
21
+
22
+ return {
23
+ repoRoot,
24
+ title,
25
+ purpose,
26
+ branch,
27
+ base: base ?? "working tree",
28
+ generatedAt: new Date(),
29
+ sections: classifyChangedFiles(changedFiles),
30
+ changedFiles,
31
+ };
32
+ }
33
+
34
+ function detectBase(repoRoot, candidates) {
35
+ for (const candidate of candidates) {
36
+ if (maybeGit(repoRoot, ["rev-parse", "--verify", candidate])) {
37
+ return candidate;
38
+ }
39
+ }
40
+
41
+ return undefined;
42
+ }
43
+
44
+ function diffNames(repoRoot, args) {
45
+ const output = maybeGit(repoRoot, ["diff", "--name-only", ...args]);
46
+
47
+ return output ? output.split("\n").filter(Boolean) : [];
48
+ }
49
+
50
+ function gitLines(repoRoot, args) {
51
+ const output = maybeGit(repoRoot, args);
52
+
53
+ return output ? output.split("\n").filter(Boolean) : [];
54
+ }
55
+
56
+ function titleFromBranch(branch, fallback) {
57
+ if (branch && branch !== "HEAD") {
58
+ return branch
59
+ .replace(/^[^/]+\//, "")
60
+ .split(/[-_]/)
61
+ .filter(Boolean)
62
+ .map((part) => part[0].toUpperCase() + part.slice(1))
63
+ .join(" ");
64
+ }
65
+
66
+ return fallback || "Current PR";
67
+ }
68
+
69
+ function git(cwd, args) {
70
+ try {
71
+ return execFileSync("git", args, { cwd, encoding: "utf8" }).trim();
72
+ } catch (error) {
73
+ if (typeof error.stdout === "string" && error.stdout.trim()) {
74
+ return error.stdout.trim();
75
+ }
76
+
77
+ throw error;
78
+ }
79
+ }
80
+
81
+ function maybeGit(cwd, args) {
82
+ try {
83
+ return git(cwd, args);
84
+ } catch {
85
+ return "";
86
+ }
87
+ }
88
+
89
+ function unique(values) {
90
+ return [...new Set(values)];
91
+ }
@@ -0,0 +1,9 @@
1
+ export function branchToPresentationDirName(branch) {
2
+ const slug = branch
3
+ .trim()
4
+ .replace(/^refs\/heads\//, "")
5
+ .replace(/[^a-zA-Z0-9._-]+/g, "-")
6
+ .replace(/^-+|-+$/g, "");
7
+
8
+ return slug || "detached-head";
9
+ }
@@ -0,0 +1,53 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+
4
+ export function listPresentations(root) {
5
+ if (!existsSync(root)) {
6
+ return [];
7
+ }
8
+
9
+ return readdirSync(root)
10
+ .filter((name) => statSync(join(root, name)).isDirectory())
11
+ .map((name) => presentationFromDirectory(root, name))
12
+ .filter((presentation) => presentation !== undefined)
13
+ .sort((left, right) => left.name.localeCompare(right.name));
14
+ }
15
+
16
+ export function resolvePresentationSlidesPath(root, name) {
17
+ const slidesPath = resolve(root, name, "slides.md");
18
+
19
+ if (!existsSync(slidesPath)) {
20
+ throw new Error(`Presentation "${name}" does not exist at ${slidesPath}`);
21
+ }
22
+
23
+ return slidesPath;
24
+ }
25
+
26
+ function presentationFromDirectory(root, name) {
27
+ const slidesPath = join(root, name, "slides.md");
28
+
29
+ if (!existsSync(slidesPath)) {
30
+ return undefined;
31
+ }
32
+
33
+ const manifest = readManifest(join(root, name, "manifest.json"));
34
+
35
+ return {
36
+ name,
37
+ title: manifest.title || name,
38
+ branch: manifest.branch || "",
39
+ slidesPath,
40
+ };
41
+ }
42
+
43
+ function readManifest(path) {
44
+ if (!existsSync(path)) {
45
+ return {};
46
+ }
47
+
48
+ try {
49
+ return JSON.parse(readFileSync(path, "utf8"));
50
+ } catch {
51
+ return {};
52
+ }
53
+ }
@@ -0,0 +1,118 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { buildDeck } from "../src/generate-pr-deck.js";
4
+
5
+ describe("buildDeck", () => {
6
+ it("turns structural PR context into a presentation-shaped Slidev deck", () => {
7
+ const markdown = buildDeck({
8
+ title: "Hello world persistence",
9
+ purpose: "Teams can verify the starter path from browser to database.",
10
+ branch: "feature/hello-history",
11
+ base: "main",
12
+ generatedAt: new Date("2026-05-22T12:00:00.000Z"),
13
+ sections: {
14
+ pages: [
15
+ {
16
+ label: "Hello page",
17
+ detail: "Keeps the starter screen focused on the hello-world flow.",
18
+ image: "./assets/hello-page.png",
19
+ },
20
+ ],
21
+ behaviors: [
22
+ {
23
+ label: "The happy path gets a spotlight",
24
+ detail: "e2e/features/helloworld.feature",
25
+ },
26
+ ],
27
+ designSystem: [
28
+ {
29
+ label: "Starter component examples",
30
+ detail: "Keeps design-system examples free of product-specific copy.",
31
+ },
32
+ ],
33
+ backend: [
34
+ {
35
+ label: "Greeter service",
36
+ detail: "Records submitted names before returning a greeting.",
37
+ },
38
+ ],
39
+ database: [
40
+ {
41
+ label: "Create Hello World Inputs",
42
+ detail: "server/migrations/20260524160000_create_hello_world_inputs.sql",
43
+ migrationSummary: [
44
+ "Creates `hello_world_inputs`.",
45
+ "Stores each submitted hello-world input.",
46
+ ],
47
+ },
48
+ ],
49
+ protos: [
50
+ {
51
+ label: "Hello World",
52
+ detail: "proto/helloworld/v1/helloworld.proto",
53
+ protoServices: [
54
+ {
55
+ name: "GreeterService",
56
+ rpcs: [
57
+ {
58
+ description: "returns a greeting for the submitted name.",
59
+ name: "SayHello",
60
+ },
61
+ ],
62
+ },
63
+ ],
64
+ },
65
+ ],
66
+ },
67
+ changedFiles: [
68
+ "client/src/pages/hello/hello-page.tsx",
69
+ "e2e/tests/helloworld.spec.ts",
70
+ "proto/helloworld/v1/helloworld.proto",
71
+ ],
72
+ });
73
+
74
+ expect(markdown).toContain("class=\"retro-stage");
75
+ expect(markdown).toContain("Prepared for the Review Committee");
76
+ expect(markdown).toContain("WINDOW 3.1-ish");
77
+ expect(markdown).toContain("<h1>Hello world persistence</h1>");
78
+ expect(markdown).toContain("## User-Facing Page Changes");
79
+ expect(markdown).toContain("./assets/hello-page.png");
80
+ expect(markdown).toContain("deck-screenshot");
81
+ expect(markdown).toContain("Hello page");
82
+ expect(markdown).toContain("## Features");
83
+ expect(markdown).toContain("Feature specification");
84
+ expect(markdown).not.toContain("<v-clicks>");
85
+ expect(markdown).toContain("Evidence");
86
+ expect(markdown).toContain("<h1>Technical Implementation</h1>");
87
+ expect(markdown).toContain("## GreeterService");
88
+ expect(markdown).toContain("We added this service with these RPCs:");
89
+ expect(markdown).toContain("SayHello");
90
+ expect(markdown).toContain("## Create Hello World Inputs");
91
+ expect(markdown).toContain("Creates `hello_world_inputs`.");
92
+ expect(markdown).toContain("client/src/pages/hello/hello-page.tsx");
93
+ });
94
+
95
+ it("keeps empty structural buckets presentation-ready", () => {
96
+ const markdown = buildDeck({
97
+ title: "Tiny docs polish",
98
+ purpose: "The docs read more clearly.",
99
+ branch: "docs/polish",
100
+ base: "main",
101
+ generatedAt: new Date("2026-05-22T12:00:00.000Z"),
102
+ sections: {
103
+ pages: [],
104
+ behaviors: [],
105
+ designSystem: [],
106
+ backend: [],
107
+ database: [],
108
+ protos: [],
109
+ },
110
+ changedFiles: [],
111
+ });
112
+
113
+ expect(markdown).toContain("No page-level UI changes detected yet.");
114
+ expect(markdown).toContain("No backend implementation changes detected yet.");
115
+ expect(markdown).toContain("No focused changed-file list was provided.");
116
+ expect(markdown).toContain("class=\"empty-desk\"");
117
+ });
118
+ });
@@ -0,0 +1,14 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { branchToPresentationDirName } from "../src/presentation-paths.js";
4
+
5
+ describe("branchToPresentationDirName", () => {
6
+ it("turns branch names into one filesystem-safe presentation directory", () => {
7
+ expect(branchToPresentationDirName("feat/hello-history")).toBe("feat-hello-history");
8
+ expect(branchToPresentationDirName("refs/heads/fix/hello copy")).toBe("fix-hello-copy");
9
+ });
10
+
11
+ it("falls back when Git is not on a named branch", () => {
12
+ expect(branchToPresentationDirName(" ")).toBe("detached-head");
13
+ });
14
+ });
@@ -0,0 +1,50 @@
1
+ import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+
5
+ import { describe, expect, it } from "vitest";
6
+
7
+ import {
8
+ listPresentations,
9
+ resolvePresentationSlidesPath,
10
+ } from "../src/presentations.js";
11
+
12
+ describe("presentations", () => {
13
+ it("lists directories that contain slides with manifest metadata", () => {
14
+ const root = mkdtempSync(join(tmpdir(), "pr-slide-"));
15
+ mkdirSync(join(root, "feat-one"));
16
+ mkdirSync(join(root, "fix-two"));
17
+ mkdirSync(join(root, "empty"));
18
+ writeFileSync(join(root, "feat-one", "slides.md"), "# One\n");
19
+ writeFileSync(
20
+ join(root, "feat-one", "manifest.json"),
21
+ JSON.stringify({ title: "Feature One", branch: "feat/one" }),
22
+ );
23
+ writeFileSync(join(root, "fix-two", "slides.md"), "# Two\n");
24
+
25
+ expect(listPresentations(root)).toEqual([
26
+ {
27
+ name: "feat-one",
28
+ title: "Feature One",
29
+ branch: "feat/one",
30
+ slidesPath: join(root, "feat-one", "slides.md"),
31
+ },
32
+ {
33
+ name: "fix-two",
34
+ title: "fix-two",
35
+ branch: "",
36
+ slidesPath: join(root, "fix-two", "slides.md"),
37
+ },
38
+ ]);
39
+ });
40
+
41
+ it("resolves a named presentation to its Slidev entry", () => {
42
+ const root = mkdtempSync(join(tmpdir(), "pr-slide-"));
43
+ mkdirSync(join(root, "feat-one"));
44
+ writeFileSync(join(root, "feat-one", "slides.md"), "# One\n");
45
+
46
+ expect(resolvePresentationSlidesPath(root, "feat-one")).toBe(
47
+ join(root, "feat-one", "slides.md"),
48
+ );
49
+ });
50
+ });
@@ -0,0 +1,15 @@
1
+ syntax = "proto3";
2
+
3
+ package helloworld.v1;
4
+
5
+ service GreeterService {
6
+ rpc SayHello(SayHelloRequest) returns (SayHelloResponse);
7
+ }
8
+
9
+ message SayHelloRequest {
10
+ string name = 1;
11
+ }
12
+
13
+ message SayHelloResponse {
14
+ string greeting = 1;
15
+ }
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ eval "$(APP_ENV=test pnpm exec varlock load --format shell --compact)"
5
+
6
+ if [[ "${BACKBONE_SKIP_GENERATE:-}" != "1" ]]; then
7
+ just generate
8
+ fi
9
+
10
+ "$@"
@@ -0,0 +1,26 @@
1
+ [package]
2
+ name = "server"
3
+ version = "0.1.0"
4
+ edition.workspace = true
5
+ rust-version.workspace = true
6
+ license.workspace = true
7
+
8
+ [lints]
9
+ workspace = true
10
+
11
+ [dependencies]
12
+ anyhow = "1"
13
+ axum = "0.8"
14
+ buffa = { version = "0.5", features = ["json"] }
15
+ buffa-types = { version = "0.5", features = ["json"] }
16
+ connectrpc = { version = "0.4", features = ["axum"] }
17
+ http-body = "1"
18
+ serde = { version = "1", features = ["derive"] }
19
+ sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "sqlite", "migrate", "macros"] }
20
+ tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "signal"] }
21
+ tower-http = { version = "0.6", features = ["cors", "trace"] }
22
+ tracing = "0.1"
23
+ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
24
+
25
+ [build-dependencies]
26
+ connectrpc-build = "0.4"
@@ -0,0 +1,9 @@
1
+ fn main() -> Result<(), Box<dyn std::error::Error>> {
2
+ connectrpc_build::Config::new()
3
+ .files(&["../proto/helloworld/v1/helloworld.proto"])
4
+ .includes(&["../proto"])
5
+ .include_file("_connectrpc.rs")
6
+ .compile()?;
7
+
8
+ Ok(())
9
+ }
@@ -0,0 +1,6 @@
1
+ [target.'cfg(all())']
2
+ rustflags = ["-C", "linker=dylint-link"]
3
+
4
+ # For Rust versions 1.74.0 and onward, the following alternative can be used
5
+ # (see https://github.com/rust-lang/cargo/pull/12535):
6
+ # linker = "dylint-link"