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.
- package/README.md +33 -0
- package/bin/create-backbone-template.js +5 -0
- package/package.json +30 -0
- package/src/create-backbone-template.js +204 -0
- package/template/.agents/skills/agent-browser/SKILL.md +55 -0
- package/template/.agents/skills/create-plan/SKILL.md +52 -0
- package/template/.agents/skills/create-plan/agents/openai.yaml +4 -0
- package/template/.agents/skills/create-pr-presentation/SKILL.md +86 -0
- package/template/.agents/skills/create-pr-presentation/agents/openai.yaml +4 -0
- package/template/.agents/skills/implement-plan/SKILL.md +26 -0
- package/template/.agents/skills/implement-plan/agents/openai.yaml +4 -0
- package/template/.agents/skills/review-plan/SKILL.md +38 -0
- package/template/.agents/skills/review-plan/agents/openai.yaml +4 -0
- package/template/.env.schema +30 -0
- package/template/.env.test +6 -0
- package/template/.oxlintrc.json +67 -0
- package/template/.vscode/extensions.json +3 -0
- package/template/.vscode/settings.json +23 -0
- package/template/AGENTS.md +55 -0
- package/template/Cargo.lock +2648 -0
- package/template/Cargo.toml +29 -0
- package/template/Justfile +140 -0
- package/template/README.md +72 -0
- package/template/TODO.md +1 -0
- package/template/_gitignore +12 -0
- package/template/buf.gen.yaml +7 -0
- package/template/buf.yaml +10 -0
- package/template/client/.oxfmtrc.json +8 -0
- package/template/client/.oxlintrc.json +57 -0
- package/template/client/README.md +19 -0
- package/template/client/_gitignore +5 -0
- package/template/client/index.html +12 -0
- package/template/client/package.json +47 -0
- package/template/client/packages/design-system/package.json +19 -0
- package/template/client/packages/design-system/src/index.ts +2 -0
- package/template/client/packages/design-system-basic/package.json +18 -0
- package/template/client/packages/design-system-basic/src/button.stories.tsx +50 -0
- package/template/client/packages/design-system-basic/src/button.tsx +26 -0
- package/template/client/packages/design-system-basic/src/empty-state.stories.tsx +18 -0
- package/template/client/packages/design-system-basic/src/empty-state.tsx +17 -0
- package/template/client/packages/design-system-basic/src/form-field.stories.tsx +15 -0
- package/template/client/packages/design-system-basic/src/form-field.tsx +10 -0
- package/template/client/packages/design-system-basic/src/form.stories.tsx +27 -0
- package/template/client/packages/design-system-basic/src/form.tsx +9 -0
- package/template/client/packages/design-system-basic/src/heading.stories.tsx +14 -0
- package/template/client/packages/design-system-basic/src/heading.tsx +25 -0
- package/template/client/packages/design-system-basic/src/index.tsx +15 -0
- package/template/client/packages/design-system-basic/src/inline.stories.tsx +13 -0
- package/template/client/packages/design-system-basic/src/inline.tsx +5 -0
- package/template/client/packages/design-system-basic/src/layout.stories.tsx +24 -0
- package/template/client/packages/design-system-basic/src/layout.tsx +14 -0
- package/template/client/packages/design-system-basic/src/loader.stories.tsx +8 -0
- package/template/client/packages/design-system-basic/src/loader.tsx +11 -0
- package/template/client/packages/design-system-basic/src/navigation.stories.tsx +16 -0
- package/template/client/packages/design-system-basic/src/navigation.tsx +18 -0
- package/template/client/packages/design-system-basic/src/notice.stories.tsx +13 -0
- package/template/client/packages/design-system-basic/src/notice.tsx +5 -0
- package/template/client/packages/design-system-basic/src/stack.stories.tsx +17 -0
- package/template/client/packages/design-system-basic/src/stack.tsx +5 -0
- package/template/client/packages/design-system-basic/src/styles.css +254 -0
- package/template/client/packages/design-system-basic/src/text-input.stories.tsx +13 -0
- package/template/client/packages/design-system-basic/src/text-input.tsx +5 -0
- package/template/client/packages/design-system-basic/src/text.stories.tsx +21 -0
- package/template/client/packages/design-system-basic/src/text.tsx +5 -0
- package/template/client/packages/design-system-contract/package.json +15 -0
- package/template/client/packages/design-system-contract/src/button.ts +10 -0
- package/template/client/packages/design-system-contract/src/empty-state.ts +9 -0
- package/template/client/packages/design-system-contract/src/form-field.ts +9 -0
- package/template/client/packages/design-system-contract/src/form.ts +9 -0
- package/template/client/packages/design-system-contract/src/heading.ts +9 -0
- package/template/client/packages/design-system-contract/src/index.ts +13 -0
- package/template/client/packages/design-system-contract/src/inline.ts +7 -0
- package/template/client/packages/design-system-contract/src/layout.ts +8 -0
- package/template/client/packages/design-system-contract/src/loader.ts +7 -0
- package/template/client/packages/design-system-contract/src/navigation.ts +13 -0
- package/template/client/packages/design-system-contract/src/notice.ts +8 -0
- package/template/client/packages/design-system-contract/src/stack.ts +8 -0
- package/template/client/packages/design-system-contract/src/text-input.ts +5 -0
- package/template/client/packages/design-system-contract/src/text.ts +9 -0
- package/template/client/packages/design-system-lint/fixtures/invalid/external-ui-import.tsx +5 -0
- package/template/client/packages/design-system-lint/fixtures/invalid/raw-dom-jsx.tsx +3 -0
- package/template/client/packages/design-system-lint/fixtures/invalid/two-violations.tsx +7 -0
- package/template/client/packages/design-system-lint/fixtures/valid/design-system-only.tsx +13 -0
- package/template/client/packages/design-system-lint/package.json +23 -0
- package/template/client/packages/design-system-lint/src/check-design-system-architecture.ts +22 -0
- package/template/client/packages/design-system-lint/src/design-system-architecture.ts +286 -0
- package/template/client/packages/design-system-lint/src/oxlint-plugin.ts +11 -0
- package/template/client/packages/design-system-lint/src/page-architecture.ts +382 -0
- package/template/client/packages/design-system-lint/src/rules.ts +111 -0
- package/template/client/packages/design-system-lint/test/design-system-architecture.test.ts +243 -0
- package/template/client/packages/design-system-lint/test/oxlint-fixtures.test.ts +159 -0
- package/template/client/packages/design-system-lint/test/page-architecture.test.ts +175 -0
- package/template/client/packages/design-system-lint/test/rules.test.ts +65 -0
- package/template/client/packages/design-system-lint/tsconfig.json +29 -0
- package/template/client/src/App.tsx +77 -0
- package/template/client/src/design-system-components.test.tsx +75 -0
- package/template/client/src/gen/helloworld/v1/helloworld_pb.ts +63 -0
- package/template/client/src/main.tsx +18 -0
- package/template/client/src/pages/hello/hello-page.stories.tsx +20 -0
- package/template/client/src/pages/hello/hello-page.test.tsx +90 -0
- package/template/client/src/pages/hello/hello-page.tsx +126 -0
- package/template/client/src/pages/page.ts +20 -0
- package/template/client/src/testing/create-preview-events.test.ts +36 -0
- package/template/client/src/testing/create-preview-events.ts +30 -0
- package/template/client/src/vite-env.d.ts +1 -0
- package/template/client/tsconfig.json +32 -0
- package/template/client/vite.config.ts +21 -0
- package/template/client/vite.ladle.config.ts +5 -0
- package/template/e2e/.gherkin-lintrc +20 -0
- package/template/e2e/.oxfmtrc.json +15 -0
- package/template/e2e/.oxlintrc.json +37 -0
- package/template/e2e/_gitignore +4 -0
- package/template/e2e/features/helloworld.feature +10 -0
- package/template/e2e/package.json +42 -0
- package/template/e2e/playwright.config.ts +16 -0
- package/template/e2e/support/app-gherkin.ts +4 -0
- package/template/e2e/support/fixtures.ts +236 -0
- package/template/e2e/support/gherkin-fixtures/duplicate-id.feature +9 -0
- package/template/e2e/support/gherkin-fixtures/duplicate-id.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/extra-implementation.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/extra-step.spec.ts +10 -0
- package/template/e2e/support/gherkin-fixtures/happy-path.spec.ts +4 -0
- package/template/e2e/support/gherkin-fixtures/missing-id.feature +4 -0
- package/template/e2e/support/gherkin-fixtures/missing-id.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/missing-implementation.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/missing-step.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/playwright.config.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/scenario-outline.feature +9 -0
- package/template/e2e/support/gherkin-fixtures/scenario-outline.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/step-mismatch.spec.ts +9 -0
- package/template/e2e/support/gherkin-fixtures/valid-implementations.ts +23 -0
- package/template/e2e/support/gherkin-fixtures/valid-scenarios.feature +26 -0
- package/template/e2e/support/gherkin.test.ts +184 -0
- package/template/e2e/support/gherkin.ts +321 -0
- package/template/e2e/support/oxlint-plugin.test.ts +328 -0
- package/template/e2e/support/oxlint-plugin.ts +485 -0
- package/template/e2e/tests/helloworld.spec.ts +39 -0
- package/template/e2e/tsconfig.json +26 -0
- package/template/e2e/tsconfig.oxlint-plugin.json +12 -0
- package/template/package.json +9 -0
- package/template/pnpm-lock.yaml +10723 -0
- package/template/pnpm-workspace.yaml +8 -0
- package/template/pr-slide/README.md +95 -0
- package/template/pr-slide/package.json +23 -0
- package/template/pr-slide/src/cli.js +262 -0
- package/template/pr-slide/src/generate-pr-deck.js +833 -0
- package/template/pr-slide/src/git-context.js +91 -0
- package/template/pr-slide/src/presentation-paths.js +9 -0
- package/template/pr-slide/src/presentations.js +53 -0
- package/template/pr-slide/test/generate-pr-deck.test.js +118 -0
- package/template/pr-slide/test/presentation-paths.test.js +14 -0
- package/template/pr-slide/test/presentations.test.js +50 -0
- package/template/proto/helloworld/v1/helloworld.proto +15 -0
- package/template/scripts/run-e2e.sh +10 -0
- package/template/server/Cargo.toml +26 -0
- package/template/server/build.rs +9 -0
- package/template/server/dylint/backbone_server_lints/.cargo/config.toml +6 -0
- package/template/server/dylint/backbone_server_lints/Cargo.lock +1581 -0
- package/template/server/dylint/backbone_server_lints/Cargo.toml +21 -0
- package/template/server/dylint/backbone_server_lints/README.md +5 -0
- package/template/server/dylint/backbone_server_lints/_gitignore +1 -0
- package/template/server/dylint/backbone_server_lints/rust-toolchain +3 -0
- package/template/server/dylint/backbone_server_lints/src/lib.rs +612 -0
- package/template/server/dylint/backbone_server_lints/ui/lib.rs +4 -0
- package/template/server/dylint/backbone_server_lints/ui/lib.stderr +10 -0
- package/template/server/dylint/backbone_server_lints/ui/long_file.rs +303 -0
- package/template/server/dylint/backbone_server_lints/ui/long_file.stderr +6 -0
- package/template/server/dylint/backbone_server_lints/ui/main.rs +59 -0
- package/template/server/dylint/backbone_server_lints/ui/main.stderr +85 -0
- package/template/server/migrations/20260520120000_create_projects.sql +12 -0
- package/template/server/migrations/20260524160000_create_hello_world_inputs.sql +12 -0
- package/template/server/src/config.rs +27 -0
- package/template/server/src/db/hello_world.rs +34 -0
- package/template/server/src/db/hello_world_tests.rs +11 -0
- package/template/server/src/db/mod.rs +39 -0
- package/template/server/src/lib.rs +10 -0
- package/template/server/src/main.rs +43 -0
- package/template/server/src/rpc/greeter/mod.rs +31 -0
- package/template/server/src/rpc/greeter/say_hello.rs +27 -0
- package/template/server/src/rpc/mod.rs +8 -0
- package/template/server/src/state.rs +13 -0
- 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,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,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"
|