Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!-- mermaid-ai-skills:start -->

# Copilot Instructions

## Mermaid Diagrams

When the user asks to create, edit, or visualize a diagram, follow the
instructions in `.github/instructions/mermaid.instructions.md`.

<!-- mermaid-ai-skills:end -->
8 changes: 6 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
version: 2
updates:
- package-ecosystem: github-actions
cooldown:
default-days: 7
directory: /
target-branch: staging
schedule:
interval: daily
open-pull-requests-limit: 100
assignees:
- daveio
- synmux
groups:
all-dependencies:
patterns:
- "*"
- package-ecosystem: npm
cooldown:
default-days: 7
directory: /
target-branch: staging
schedule:
interval: daily
open-pull-requests-limit: 100
assignees:
- daveio
- synmux
groups:
all-dependencies:
patterns:
Expand Down
92 changes: 92 additions & 0 deletions .github/instructions/mermaid.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
applyTo: "**"
---

# Mermaid AI Skills

When the user asks to create, edit, or visualize any diagram, use the Mermaid
VS Code extension tools and commands described below.

## Workflow

1. Determine the diagram type and generate Mermaid syntax.
2. Write the diagram to a `.mmd` file in the project.
3. Validate syntax: correct first-line keyword, arrow types, balanced brackets.
4. Preview via the Mermaid extension — open the `.mmd` file (auto-preview) or run
**Mermaid: Preview Diagram** (`mermaidChart.preview`).

## LM Tools — call these for every diagram interaction

- `mermaid-diagram-validator` — validate Mermaid syntax before presenting any diagram
- `mermaid-diagram-preview` — render a live preview inside VS Code after generating
- `get-syntax-docs-mermaid` — fetch correct syntax docs for any diagram type

## VS Code Commands

Invoke via Command Palette or the VS Code command API (GitHub Copilot in VS Code only).
Do not invent command IDs. Prefer writing/editing `.mmd` files when a command is not needed.

### Diagram editing & preview

- **Preview** (`mermaidChart.preview`) — preview the active Mermaid editor (`.mmd` / `.mermaid` must be open).
- **Create Diagram** (`mermaidChart.createMermaidFile`) — creates a demo flowchart and opens preview side by side.
- **Repair Diagram** (`mermaidChart.repairDiagram`) — Mermaid AI repair for the active diagram; uses Mermaid AI credits — tell the user before running.
- **Improve Diagram** (`mermaidChart.improveDiagram`) — uses Copilot / LM API; suggests layout + styling variants for the active diagram.

### Generate diagrams (GitHub Copilot required)

- **Generate Diagram from Code** (`mermaidChart.generateDiagramFromCode`)
- **Generate Cloud Diagram** (`mermaidChart.generateCloudDiagram`)
- **Generate ER Diagram** (`mermaidChart.generateERDiagram`)
- **Generate Docker Diagram** (`mermaidChart.generateDockerDiagram`)
- **Open AI Chat** (`mermaidChart.openCopilotChat`)

### Mermaid cloud

- **Login** (`mermaidChart.login`) / **Logout** (`mermaidChart.logout`)
- **Connect Diagram** (`mermaidChart.connectDiagramToMermaidChart`) — link a local diagram to Mermaid.
- **Sync Diagram** (`mermaidChart.syncDiagramWithMermaid`) — only for diagrams already connected (frontmatter has `id:`). Example:
```yaml
---
id: cbd9e9ba-a2cb-47c5-a98e-8c28a753428d
---
```

### Review Mermaid Sync

For diagrams updated by the Mermaid GitHub Sync app (or pre-commit regenerate):

- **Review Mermaid Sync** (`mermaidChart.reviewAppCommits`) — start / open the review flow.
- **Regenerate with Mermaid AI** (`mermaidChart.regenerateDiagramWithMermaidAI`) — regenerate from source references.
Do not manually rewrite diagrams managed by this workflow. Accept/reject/diff UI actions stay in the extension UI.

### Install / update this pack

- **Mermaid: Install AI Skills…** (`mermaidChart.installAiSkills`)

## @mermaid-chart slash commands

| Command | Purpose |
| -------------------------------------- | ------------------------------------ |
| `/generate_diagram_from_code` | General diagram from any source file |
| `/generate_execution_sequence` | Sequence diagram from code flow |
| `/generate_er_diagram` | ER diagram from schema / models |
| `/generate_cloud_architecture_diagram` | Cloud / CI-CD architecture |
| `/generate_docker_diagram` | Architecture from Dockerfiles |
| `/generate_c4_topdown_architecture` | C4 top-down architecture |
| `/analyze_code_ownership` | Code ownership diagram |
| `/generate_dependency_diagram` | Dependency / security visualisation |

## Rules

1. Always call `mermaid-diagram-validator` before showing any diagram.
2. Always call `mermaid-diagram-preview` after generating a diagram.
3. Use `get-syntax-docs-mermaid` before generating an unfamiliar diagram type.
4. Prefer `@mermaid-chart` slash commands for complex generation.
5. Write diagrams to `.mmd` files; never return unvalidated Mermaid syntax.
6. Warn the user before Repair (Mermaid AI credits).
7. Cooperate with the Sync workflow — do not manually regenerate managed diagrams.

## Docs

More commands and features: https://marketplace.visualstudio.com/items?itemName=MermaidChart.vscode-mermaid-chart
11 changes: 9 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
name: ci
permissions: read-all
on:
push: null
pull_request: null
push: null
permissions:
actions: read
checks: write
contents: read
id-token: write
issues: write
pull-requests: write
security-events: write
Comment on lines +5 to +12
jobs:
lint:
runs-on: ubuntu-latest
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/devskim.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name: devskim
on:
push: null
pull_request: null
push: null
permissions:
actions: read
checks: write
contents: read
id-token: write
issues: write
Expand Down
8 changes: 4 additions & 4 deletions .trunk/trunk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ lint:
- pinact
- osv-scanner
enabled:
- oxlint@1.86.0
- oxlint@1.87.0
- grype@0.120.0
- shellcheck@0.11.0
- shfmt@3.14.1
- trunk-toolbox@0.7.0
- oxipng@10.2.1
- actionlint@1.7.12
- checkov@3.3.22
- checkov@3.3.23
- eslint@10.12.0
- git-diff-check
- markdownlint@0.49.1
- prettier@3.9.9
- taplo@0.10.0
- trufflehog@3.97.9
- trufflehog@3.98.0
- yamllint@1.38.0
ignore:
- linters:
Expand All @@ -59,4 +59,4 @@ actions:
- pnpm-install
tools:
enabled:
- oxfmt@0.71.0
- oxfmt@0.72.0
20 changes: 10 additions & 10 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"recommendations": [
"vue.volar",
"nuxt.mdc",
"meritek.nuxt-intellisense",
"nuxtr.nuxtr-vscode",
"trunk.io",
"anthropic.claude-code",
"chrislajoie.vscode-modelines",
"christian-kohler.npm-intellisense",
"firefox-devtools.vscode-firefox-debug",
"fill-labs.dependi",
"tamasfe.even-better-toml",
"firefox-devtools.vscode-firefox-debug",
"meritek.nuxt-intellisense",
"ms-azuretools.vscode-containers",
"ms-vscode-remote.remote-containers",
"chrislajoie.vscode-modelines",
"nuxt.mdc",
"nuxtr.nuxtr-vscode",
"pflannery.vscode-versionlens",
"redhat.vscode-yaml",
"ms-azuretools.vscode-containers",
"pflannery.vscode-versionlens"
"tamasfe.even-better-toml",
"trunk.io",
"vue.volar"
],
"unwantedRecommendations": ["ms-toolsai.jupyter"]
}
10 changes: 9 additions & 1 deletion app/components/AppHeader.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script setup lang="ts"></script>
<script setup lang="ts">
const { loggedIn } = useUserSession();
</script>

<template>
<nav>
Expand All @@ -13,6 +15,12 @@
<li>
<NuxtLink to="/list" class="link link-hover" active-class="menu-active">List</NuxtLink>
</li>
<li v-if="loggedIn">
<NuxtLink to="/login" class="link link-hover" active-class="menu-active">Login</NuxtLink>
</li>
<li v-else>
<NuxtLink to="/me" class="link link-hover" active-class="menu-active">Me</NuxtLink>
</li>
</ul>
</nav>
</template>
7 changes: 7 additions & 0 deletions app/layouts/blank.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<template>
<div
class="bg-linear-to-r from-sky-400 via-purple-500 to-pink-300 border-2 border-indigo-600 flex min-h-screen flex-row justify-center"
>
<div class="border-2 border-indigo-600 flex min-h-screen flex-column gap-6 max-w-240 w-full"><slot /></div>
</div>
</template>
4 changes: 4 additions & 0 deletions app/layouts/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: ["nuxt-auth-utils"],
Comment on lines +2 to +3
});
8 changes: 8 additions & 0 deletions app/middleware/authenticated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default defineNuxtRouteMiddleware(() => {
const { loggedIn } = useUserSession();

// redirect the user to the login screen if they're not authenticated
if (!loggedIn.value) {
return navigateTo("/login");
}
});
51 changes: 51 additions & 0 deletions app/pages/login-example.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script setup lang="ts">
declare module "nuxt/app" {
interface NuxtLayouts {
custom: unknown;
}
}
// ---cut---
definePageMeta({
layout: "blank",
});

const email = ref("");
const password = ref("");

async function handleLogin() {
try {
console.log("Start Fetch");
if (email?.value && password?.value) {
const res = await $fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: { email: email.value, password: password.value },
});
console.log("Fetch Complete");
console.log(res);
Comment on lines +19 to +25
} else console.log("Login Failed, empty input");
} catch (error) {
console.error("Login failed:", error);
}
}
</script>

<template>
<main class="flex-1 py-12">
<div class="bg-base-200 flex flex-col items-center justify-center gap-4 mt-4">
<h1 class="text-xl my-8">Login to your account</h1>
<form class="w-full" @submit.prevent="handleLogin">
<fieldset class="fieldset border-base-300 border rounded-box w-full p-4 flex flex-col justify-stretch gap-4">
<legend class="sr-only">Login Page</legend>

<UiInput v-model="email" label="Email" placeholder="email@example.com" />
<UiInput v-model="password" label="Password" type="password" placeholder="password" />

<UiButton is-submit type="primary" class="mt-8">Login</UiButton>
</fieldset>
</form>
<span class="text-secondary-content text-sm">or</span>
<UiButton to="/register" type="secondary">New? Create an account</UiButton>
</div>
</main>
</template>
44 changes: 25 additions & 19 deletions app/pages/login.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
<script setup lang="ts">
const email = ref("");
const password = ref("");
const { fetch: refreshSession } = useUserSession();
const credentials = reactive({
email: "",
password: "",
});

async function handleLogin() {
try {
console.log("Start Fetch");
if (email?.value && password?.value) {
if (credentials.email && credentials.password) {
const res = await $fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: { email: email.value, password: password.value },
body: credentials,
});
console.log("Fetch Complete");
console.log(res);
// Refresh the session on client-side and redirect to the home page
await refreshSession();
await navigateTo("/me");
} else console.log("Login Failed, empty input");
} catch (error) {
console.error("Login failed:", error);
Expand All @@ -21,21 +27,21 @@ async function handleLogin() {
</script>

<template>
<div class="flex flex-col items-center justify-center gap-4 mt-4">
<h1 class="text-xl my-8">Login to your account</h1>
<form class="w-full" @submit.prevent="handleLogin">
<fieldset
class="fieldset bg-base-200 border-base-300 border rounded-box w-full p-4 flex flex-col justify-stretch gap-4"
>
<legend class="sr-only">Login Page</legend>
<main class="flex-1 py-12">
<div class="bg-base-200 flex flex-col items-center justify-center gap-4 mt-4">
<h1 class="text-xl my-8">Login to your account</h1>
<form class="w-full" @submit.prevent="handleLogin">
<fieldset class="fieldset border-base-300 border rounded-box w-full p-4 flex flex-col justify-stretch gap-4">
<legend class="sr-only">Login Page</legend>

<UiInput v-model="email" label="Email" placeholder="email@example.com" />
<UiInput v-model="password" label="Password" type="password" placeholder="password" />
<UiInput v-model="credentials.email" label="Email" placeholder="email@example.com" />
<UiInput v-model="credentials.password" label="Password" type="password" placeholder="password" />

<UiButton is-submit type="primary" class="mt-8">Login</UiButton>
</fieldset>
</form>
<span class="text-secondary-content text-xs">or</span>
<UiButton to="/register" type="secondary">New? Create an account</UiButton>
</div>
<UiButton is-submit type="primary" class="mt-8">Login</UiButton>
</fieldset>
</form>
<span class="text-secondary-content text-sm">or</span>
<UiButton to="/register" type="secondary">New? Create an account</UiButton>
</div>
</main>
</template>
Loading
Loading