Skip to content

feat(blog): add blog section with Nuxt Content and Valibot schemas#90

Open
RedStar071 wants to merge 4 commits intomainfrom
feat/blog-section
Open

feat(blog): add blog section with Nuxt Content and Valibot schemas#90
RedStar071 wants to merge 4 commits intomainfrom
feat/blog-section

Conversation

@RedStar071
Copy link
Copy Markdown
Member

@RedStar071 RedStar071 commented Mar 27, 2026

  • Review open comments
  • Fix content.config.ts date field to use pipe(string(), isoDate()) instead of bare string()
  • Reply to comment about Valibot choice (#4025968658)
  • Reply to comment about date validation fix (#4150402422)

📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

- Add @nuxt/content module with Valibot-based collection schema
- Create blog listing page (app/pages/blog/index.vue) with UBlogPosts
- Create blog post page (app/pages/blog/[slug].vue) with TOC and surround
- Migrate wolfstar-v7 post from blog.wolfstar.rocks
- Add Blog link to header and footer navigation
- Configure blog route rules for prerendering and SEO
Copilot AI review requested due to automatic review settings March 27, 2026 14:16
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for wolfstar-rocks-et34281 ready!

Name Link
🔨 Latest commit 011e3c0
🔍 Latest deploy log https://app.netlify.com/projects/wolfstar-rocks-et34281/deploys/69c9493986e6990008329da0
😎 Deploy Preview https://deploy-preview-90.wolfstar.rocks
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 81 (🔴 down 1 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 94 (no change from production)
PWA: 90 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

Adds a blog system: Nuxt Content integration, collection schema, blog index and dynamic post pages, header/footer navigation updates, composables (blog, clipboard), types, a sample post, UI component for social links, CSS content source, and dependency/config updates.

Changes

Cohort / File(s) Summary
Navigation
app/composables/useFooter.ts, app/composables/useHeader.ts
Replaced external footer Blog link with internal /blog; added Blog entry to header desktopLinks and mobileLinks.
Blog Pages
app/pages/blog/index.vue, app/pages/blog/[slug].vue
Added blog index and dynamic post page components: async content fetching, 404 handling, SEO/Open Graph setup, post rendering (ContentRenderer), TOC, surroundings (prev/next), and copy-link/social intent builders.
Content Config & Post
content.config.ts, content/blog/wolfstar-v7.md
Added Nuxt Content config with Valibot schema for blog collection and a new markdown post wolfstar-v7.md.
Composables & Types
app/composables/useBlog.ts, app/composables/useClipboard.ts, app/types/blog.ts
New useBlog composable (articles fetch + refresh), useClipboard wrapper (copy + optional toast), and BlogArticle type alias for Nuxt Content items.
Components
app/components/SocialLinks.vue
New presentational component rendering social link buttons (Discord, GitHub).
Project Config & Assets
nuxt.config.ts, package.json, app/assets/css/main.css
Added @nuxt/content module and routeRules for /blog, added dependencies (@nuxt/content, better-sqlite3, @valibot/to-json-schema), and added content source directive to CSS for Tailwind scanning.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser
    participant NuxtPage as Nuxt Page
    participant NuxtContent as `@nuxt/content`
    participant Files as Content Filesystem

    User->>Browser: navigate to /blog or /blog/[slug]
    Browser->>NuxtPage: mount page component
    NuxtPage->>NuxtContent: queryCollection("blog") / queryCollection(...).path(...)
    NuxtContent->>Files: read matching markdown files
    Files-->>NuxtContent: return post(s) + metadata
    NuxtContent-->>NuxtPage: deliver data (article, surrounds, list)
    NuxtPage->>NuxtPage: compute SEO, TOC, social links
    NuxtPage->>Browser: render HTML (list or article + TOC + controls)
    Browser-->>User: display blog page
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • lorypelli

Poem

🐰 I hopped through files and planted a log,

Routes and pages, a neat little blog,
Clipboard ready, links all in place,
Posts lined up tidy, each in its space,
Hop, share, and read — a cozy code-gnome jog.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main changes: adding a blog section with @nuxt/content integration and Valibot schema validation, which matches the primary objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/blog-section
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/blog-section

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sentry
Copy link
Copy Markdown

sentry bot commented Mar 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.38%. Comparing base (5a5000c) to head (e958783).
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main      #90   +/-   ##
=======================================
  Coverage   67.38%   67.38%           
=======================================
  Files          79       79           
  Lines        1907     1907           
  Branches      568      568           
=======================================
  Hits         1285     1285           
  Misses        492      492           
  Partials      130      130           
Files with missing lines Coverage Δ
app/composables/useFooter.ts 100.00% <ø> (ø)
app/composables/useHeader.ts 100.00% <ø> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 27, 2026

Merging this PR will not alter performance

✅ 44 untouched benchmarks


Comparing feat/blog-section (e958783) with main (5a5000c)

Open in CodSpeed

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a first-party blog section to the Nuxt 4 dashboard app by integrating @nuxt/content (v3) with Valibot collection schemas and Nuxt UI blog/page components, migrating initial content and wiring navigation + prerender rules.

Changes:

  • Added Nuxt Content + supporting dependencies and configured the blog content collection schema (content.config.ts).
  • Implemented /blog listing and /blog/[slug] post pages using Nuxt UI blog/page components, TOC, and surround navigation.
  • Added a migrated blog post and updated header/footer navigation + route rules for prerendering.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
package.json Adds @nuxt/content, better-sqlite3, and Valibot JSON schema support dependency.
nuxt.config.ts Registers @nuxt/content and prerender route rules for blog routes.
content/blog/wolfstar-v7.md Adds migrated blog content with structured frontmatter.
content.config.ts Defines the blog collection and frontmatter schema using Valibot.
app/pages/blog/index.vue Implements blog listing with UBlogPosts/UBlogPost and SEO meta.
app/pages/blog/[slug].vue Implements blog post page with renderer, TOC, surround, author chips, and OG image.
app/composables/useHeader.ts Adds “Blog” to desktop + mobile navigation.
app/composables/useFooter.ts Changes Blog footer link from external URL to internal /blog.

Comment on lines +58 to +61
{
label: "Blog",
to: "/blog",
},
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useHeader was updated to include a new "Blog" link in both desktopLinks and mobileLinks, but the existing useHeader composable tests don’t assert that this link is present. Add a small test assertion for the new label/path to prevent accidental regression of the navigation.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines 22 to 26
class: "link-hover",
icon: "ph:newspaper-clipping-duotone",
label: "Blog",
to: "https://blog.wolfstar.rocks",
to: "/blog",
ui: { linkLeadingIcon: "bg-primary" },
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useFooter now routes the Blog link internally (/blog), but the existing useFooter tests only check that the column/labels exist, not that the Blog link points to the correct destination. Add an assertion for the Blog entry’s to so future refactors don’t accidentally revert to the external blog URL.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines 122 to +123
"@types/node": "24.12.0",
"@valibot/to-json-schema": "^1.6.0",
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@valibot/to-json-schema is added under devDependencies, but pnpm-lock indicates it is a peer dependency of @nuxt/content. If the production environment installs with --prod (or otherwise omits devDependencies), the app/build can fail at runtime or build time. Move it to dependencies (or ensure it’s installed in production) to make the Nuxt Content setup reliable.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/composables/useFooter.ts (1)

21-27: ⚠️ Potential issue | 🟡 Minor

Update app.config.ts Blog link to match the new internal route.

The Blog link in useFooter.ts was changed to /blog, but app/app.config.ts still references the external URL https://blog.wolfstar.rocks. Since Footer.vue uses useAppConfig() to fetch footer configuration from app.config.ts, the external URL will still be used in the rendered footer. Update app.config.ts line 26 to use to: "/blog" instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/composables/useFooter.ts` around lines 21 - 27, The footer config in
app.config.ts still points the Blog entry to the external URL
"https://blog.wolfstar.rocks" while useFooter.ts and the app's internal route
expect to use the internal route "/blog"; open app.config.ts and update the Blog
item’s `to` property to `"/blog"` so it matches useFooter.ts and the footer
rendered by Footer.vue via useAppConfig(); ensure the Blog entry's key/name
matches the one in useFooter.ts (icon/label) so the correct item is replaced.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/pages/blog/`[slug].vue:
- Around line 50-68: Replace the unstable index key on the author buttons by
using a stable unique identifier from each author (e.g., use author.id or
author.to instead of index) in the v-for on UButton (targeting the post.authors
array and the UButton component), and add rel="noopener noreferrer" to the
UButton props for external links (alongside target="_blank") to prevent
tabnabbing and meet security guidelines.
- Around line 75-78: UContentSurround is rendered unconditionally while
USeparator uses a guard; update the template so UContentSurround is only
rendered when surround has content (same condition as USeparator, e.g.
surround?.length). Locate the block with USeparator and UContentSurround and
wrap or add the same truthy guard around UContentSurround so both components are
rendered consistently when surround is non-empty.

In `@app/pages/blog/index.vue`:
- Around line 2-4: The blog listing query currently fetches all documents from
the "blog" collection via useAsyncData and queryCollection("blog") without
excluding drafts; update the query chain used in the useAsyncData call (the
anonymous loader passed to useAsyncData that calls
queryCollection("blog").order("date", "DESC").all()) to include a where filter
that excludes entries with draft: true (i.e., add a .where(...) before
.order/.all so only posts where draft is false or draft is not true are
returned).

---

Outside diff comments:
In `@app/composables/useFooter.ts`:
- Around line 21-27: The footer config in app.config.ts still points the Blog
entry to the external URL "https://blog.wolfstar.rocks" while useFooter.ts and
the app's internal route expect to use the internal route "/blog"; open
app.config.ts and update the Blog item’s `to` property to `"/blog"` so it
matches useFooter.ts and the footer rendered by Footer.vue via useAppConfig();
ensure the Blog entry's key/name matches the one in useFooter.ts (icon/label) so
the correct item is replaced.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1b7311af-eb95-4728-997d-6340c2f763f3

📥 Commits

Reviewing files that changed from the base of the PR and between 5a5000c and bb84d15.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • app/composables/useFooter.ts
  • app/composables/useHeader.ts
  • app/pages/blog/[slug].vue
  • app/pages/blog/index.vue
  • content.config.ts
  • content/blog/wolfstar-v7.md
  • nuxt.config.ts
  • package.json

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

♻️ Duplicate comments (2)
app/pages/blog/[slug].vue (2)

124-126: ⚠️ Potential issue | 🟡 Minor

Guard UContentSurround with the same condition as USeparator.

Line 124 is conditional, but Line 126 renders unconditionally.

♻️ Proposed fix
-	<USeparator v-if="surround?.length" />
-
-	<UContentSurround :surround="surround" />
+	<template v-if="surround?.length">
+		<USeparator />
+		<UContentSurround :surround="surround" />
+	</template>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/pages/blog/`[slug].vue around lines 124 - 126, UContentSurround is
rendered unconditionally while USeparator uses v-if="surround?.length", so guard
UContentSurround with the same condition to avoid rendering when surround is
empty/undefined; update the template around UContentSurround (the
UContentSurround tag) to include v-if="surround?.length" or wrap both USeparator
and UContentSurround in a parent element that has v-if="surround?.length" so
both USeparator and UContentSurround render only when surround has content.

87-88: ⚠️ Potential issue | 🟡 Minor

Replace index key with a stable author key.

Using index as :key is unstable for reordered lists.

♻️ Proposed fix
-	<UUser
-		v-for="(author, index) in article.authors"
-		:key="index"
+	<UUser
+		v-for="author in article.authors"
+		:key="author.to || author.name"

Based on learnings: "Always use stable keys in lists to help virtual DOM diffing; avoid using array indices as keys unless the list is static."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/pages/blog/`[slug].vue around lines 87 - 88, The v-for loop uses the
array index as the key (v-for="(author, index) in article.authors"
:key="index"), which is unstable; replace the index with a stable unique
identifier from each author object (e.g., :key="author.id" or :key="author.slug"
or :key="author.email") and if author objects lack such a field, add/derive a
stable unique property on each author before rendering (e.g., assign a UUID or
use a deterministic slug) so that the virtual DOM diffing for the
article.authors list uses a consistent key.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/composables/useBlog.ts`:
- Line 27: Remove the commented-out "featuredArticle" line in the useBlog
composable; if this feature is planned, replace the comment with a short TODO
referencing an issue number or create an issue and add a TODO comment, otherwise
simply delete the "// featuredArticle," token in the file (useBlog,
export/composable where the comment appears).
- Line 10: Remove the commented-out select call (/* .select('title', 'date',
'image', 'description', 'path', 'authors', 'category') */) from the useBlog
composable so dead/commented code is not left in the repo; if you intend to keep
this as a planned optimization, create a tracking ticket and reference that
ticket ID in a short comment instead of leaving the full commented line in the
function (look for the select call in useBlog.ts to locate the exact spot).
- Around line 6-14: The blog query in the async function using
queryCollection("blog") doesn't exclude drafts, so update the query to filter
out frontmatter drafts by either adding a where clause for draft (e.g.,
.where("draft", "!=", true) on the queryCollection("blog") chain) or, if the
query API doesn't support that operator, apply an additional filter in the
.then((res) => res.filter(...)) step to exclude articles where article.draft ===
true; target the async function that returns queryCollection("blog") so draft
posts are not returned to the caller.

In `@app/composables/useClipboard.ts`:
- Around line 23-28: The copy function has a typo in the parameter name and does
not handle failures from _copy(); rename optionsOptions to a concise options (or
toastOptions) parameter, make copy async, await the Promise returned by
_copy(source), and wrap the await in a try/catch so clipboard errors (e.g.,
permission denied) are caught; on success keep calling toast.add(options) if
provided, and on failure call toast.add or processLogger.error with a clear
error message referencing the failure inside the catch. Ensure you update the
function signature and any callers of copy accordingly.
- Around line 3-16: The type name toastOptions uses camelCase; rename it to
PascalCase (ToastOptions) and update all references in this file (and any
imports/usages) to the new name; specifically change the declaration of
toastOptions to ToastOptions and update any variables, function signatures, or
generic/type annotations that reference toastOptions (e.g., in
useClipboard-related functions) so the codebase follows the PascalCase type
naming convention.

In `@app/pages/blog/`[slug].vue:
- Around line 27-29: The page title format used in the useSeoMeta call needs to
follow the repository convention "Unique page - section - site"; update the
titleTemplate passed to useSeoMeta (the titleTemplate property in the useSeoMeta
invocation) to use that dash-separated format instead of "%s · Wolfstar Blog",
keeping title as the dynamic part so the title value is inserted into the new
template.
- Around line 45-47: The copied URL is malformed because the template literal in
copyLink() uses {article.value?.path || "/"} instead of a proper ${...}
expression; update the string construction in copyLink() to use
${article.value?.path || "/"} so the path is interpolated correctly (reference
the copyLink function and article.value?.path) and ensure the final string is a
valid URL before calling copy().
- Line 138: The template references an undefined prop `:links="links"` passed to
the UPageLinks component; declare and populate `links` in the component's script
or replace the reference with the existing `article.body.toc.links`. Update the
script (in the <script setup>) to define a reactive/const `links` (e.g., from
`article.body.toc.links`) or change the template to
`:links="article.body.toc.links"` so UPageLinks receives a valid value; ensure
the symbol names UPageLinks, links, and article.body.toc.links are used
consistently.
- Around line 38-42: The call to defineOgImageComponent uses a non-registered
component name and an invalid prop: change defineOgImageComponent("Docs", {...})
to use the registered component name "Default" and remove the unsupported
headline prop; pass only valid OGImageProps (colorMode, title, description,
icon, siteName, theme) so update the object to include only those keys (e.g.,
title and description) when invoking defineOgImageComponent.

In `@app/pages/blog/index.vue`:
- Line 7: The component destructures fetchList from useBlog() but never uses it;
either call fetchList() when the page mounts (e.g., invoke fetchList inside the
component's setup/onMounted lifecycle to refresh articles) or remove fetchList
from the destructuring to eliminate the unused variable; locate the
destructuring line with "const { articles, fetchList } = useBlog()" and either
add the lifecycle call to fetchList or change it to "const { articles } =
useBlog()".

In `@content.config.ts`:
- Line 27: The current schema defines the field named "date" using string(),
which allows malformed dates; update the schema entry for the "date" property in
the content config (the object that contains date: string()) to use Valibot's
stricter date validators — e.g., replace string() with pipe(string(), isoDate())
or use date() if you want a native Date object; reference the symbols string(),
pipe(), isoDate(), and date() when making the change so the "date" field
enforces ISO date validation.
- Around line 24-25: The schema in content.config.ts currently declares image as
optional(string()), but the frontmatter and consumers expect an Image object
with src and alt; update the schema to define image as an optional object
matching the Image shape (e.g., object({ src: string(), alt: optional(string())
})) so article.image.src and article.image.alt used in wolfstar-v7.md and
app/pages/blog/index.vue have the correct types and structure.

In `@content/blog/wolfstar-v7.md`:
- Line 34: Introduce "Artiel" before the sentence that mentions it: add a
section header like "Utility bots - Artiel" (matching the style of "Moderation
bots - WolfStar" and "Notification bots - Staryl") and a one- or two-sentence
intro describing what Artiel is and its purpose, then keep the existing line
"Artiel inherits all animal, fun, game, and meme commands from WolfStar" under
that section; ensure the new header and intro use the same formatting and tone
as the other bot sections.

---

Duplicate comments:
In `@app/pages/blog/`[slug].vue:
- Around line 124-126: UContentSurround is rendered unconditionally while
USeparator uses v-if="surround?.length", so guard UContentSurround with the same
condition to avoid rendering when surround is empty/undefined; update the
template around UContentSurround (the UContentSurround tag) to include
v-if="surround?.length" or wrap both USeparator and UContentSurround in a parent
element that has v-if="surround?.length" so both USeparator and UContentSurround
render only when surround has content.
- Around line 87-88: The v-for loop uses the array index as the key
(v-for="(author, index) in article.authors" :key="index"), which is unstable;
replace the index with a stable unique identifier from each author object (e.g.,
:key="author.id" or :key="author.slug" or :key="author.email") and if author
objects lack such a field, add/derive a stable unique property on each author
before rendering (e.g., assign a UUID or use a deterministic slug) so that the
virtual DOM diffing for the article.authors list uses a consistent key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 315e7d5f-4386-4075-a48d-9b91a7f92d68

📥 Commits

Reviewing files that changed from the base of the PR and between bb84d15 and a30ec05.

📒 Files selected for processing (9)
  • app/assets/css/main.css
  • app/composables/useBlog.ts
  • app/composables/useClipboard.ts
  • app/pages/blog/[slug].vue
  • app/pages/blog/index.vue
  • app/types/blog.ts
  • content.config.ts
  • content/blog/wolfstar-v7.md
  • nuxt.config.ts

Comment on lines +6 to +14
async () => {
return (
queryCollection("blog")
.where("extension", "=", "md")
/* .select('title', 'date', 'image', 'description', 'path', 'authors', 'category') */
.order("date", "DESC")
.all()
.then((res) => res.filter((article) => article.path !== "/blog"))
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add filter to exclude draft posts.

The query fetches all blog posts without filtering out drafts. Posts with draft: true in frontmatter will appear in the public listing. This was previously flagged in blog/index.vue, but since the query originates here, the fix should be applied in this composable.

🔒 Proposed fix to filter draft posts
 			return (
 				queryCollection("blog")
 					.where("extension", "=", "md")
+					.where("draft", "=", false)
 					/* .select('title', 'date', 'image', 'description', 'path', 'authors', 'category') */
 					.order("date", "DESC")
 					.all()
 					.then((res) => res.filter((article) => article.path !== "/blog"))
 			);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async () => {
return (
queryCollection("blog")
.where("extension", "=", "md")
/* .select('title', 'date', 'image', 'description', 'path', 'authors', 'category') */
.order("date", "DESC")
.all()
.then((res) => res.filter((article) => article.path !== "/blog"))
);
async () => {
return (
queryCollection("blog")
.where("extension", "=", "md")
.where("draft", "=", false)
/* .select('title', 'date', 'image', 'description', 'path', 'authors', 'category') */
.order("date", "DESC")
.all()
.then((res) => res.filter((article) => article.path !== "/blog"))
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/composables/useBlog.ts` around lines 6 - 14, The blog query in the async
function using queryCollection("blog") doesn't exclude drafts, so update the
query to filter out frontmatter drafts by either adding a where clause for draft
(e.g., .where("draft", "!=", true) on the queryCollection("blog") chain) or, if
the query API doesn't support that operator, apply an additional filter in the
.then((res) => res.filter(...)) step to exclude articles where article.draft ===
true; target the async function that returns queryCollection("blog") so draft
posts are not returned to the caller.

return (
queryCollection("blog")
.where("extension", "=", "md")
/* .select('title', 'date', 'image', 'description', 'path', 'authors', 'category') */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove commented-out code.

Per coding guidelines, commented-out code should not be left without associated tickets. Either remove this line or create a tracking issue if field selection optimization is planned.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/composables/useBlog.ts` at line 10, Remove the commented-out select call
(/* .select('title', 'date', 'image', 'description', 'path', 'authors',
'category') */) from the useBlog composable so dead/commented code is not left
in the repo; if you intend to keep this as a planned optimization, create a
tracking ticket and reference that ticket ID in a short comment instead of
leaving the full commented line in the function (look for the select call in
useBlog.ts to locate the exact spot).


return {
articles,
// featuredArticle,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove commented-out code.

The featuredArticle comment should be removed if not implemented, or tracked via an issue if planned.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/composables/useBlog.ts` at line 27, Remove the commented-out
"featuredArticle" line in the useBlog composable; if this feature is planned,
replace the comment with a short TODO referencing an issue number or create an
issue and add a TODO comment, otherwise simply delete the "// featuredArticle,"
token in the file (useBlog, export/composable where the comment appears).

Comment on lines +3 to +16
type toastOptions = {
title?: string;
description?: string;
icon?: string;
color?:
| "primary"
| "secondary"
| "info"
| "success"
| "warning"
| "error"
| "important"
| "neutral";
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Use PascalCase for type names.

As per coding guidelines, types and interfaces should use PascalCase.

♻️ Proposed fix
-type toastOptions = {
+type ToastOptions = {
 	title?: string;
 	description?: string;
 	icon?: string;
 	color?:
 		| "primary"
 		| "secondary"
 		| "info"
 		| "success"
 		| "warning"
 		| "error"
 		| "important"
 		| "neutral";
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/composables/useClipboard.ts` around lines 3 - 16, The type name
toastOptions uses camelCase; rename it to PascalCase (ToastOptions) and update
all references in this file (and any imports/usages) to the new name;
specifically change the declaration of toastOptions to ToastOptions and update
any variables, function signatures, or generic/type annotations that reference
toastOptions (e.g., in useClipboard-related functions) so the codebase follows
the PascalCase type naming convention.

throw createError({ statusCode: 404, statusMessage: "Page not found", fatal: true });
}

const { articles, fetchList } = useBlog();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

fetchList is destructured but never called.

The fetchList function is imported from useBlog() but is not invoked anywhere in this component. If articles need to be refreshed on navigation (e.g., when returning to this page), consider calling fetchList() or remove the unused destructuring.

♻️ Option 1: Call fetchList on mount
 const { articles, fetchList } = useBlog();
+
+await fetchList();
♻️ Option 2: Remove unused import
-const { articles, fetchList } = useBlog();
+const { articles } = useBlog();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { articles, fetchList } = useBlog();
const { articles } = useBlog();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/pages/blog/index.vue` at line 7, The component destructures fetchList
from useBlog() but never uses it; either call fetchList() when the page mounts
(e.g., invoke fetchList inside the component's setup/onMounted lifecycle to
refresh articles) or remove fetchList from the destructuring to eliminate the
unused variable; locate the destructuring line with "const { articles, fetchList
} = useBlog()" and either add the lifecycle call to fetchList or change it to
"const { articles } = useBlog()".

schema: object({
image: optional(string()),
authors: array(Author),
date: string(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using a date type for the date field.

The date field is validated as a plain string(). While this works, Valibot provides pipe(string(), isoDate()) or similar transforms for stricter date validation, which could catch malformed dates at build time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content.config.ts` at line 27, The current schema defines the field named
"date" using string(), which allows malformed dates; update the schema entry for
the "date" property in the content config (the object that contains date:
string()) to use Valibot's stricter date validators — e.g., replace string()
with pipe(string(), isoDate()) or use date() if you want a native Date object;
reference the symbols string(), pipe(), isoDate(), and date() when making the
change so the "date" field enforces ISO date validation.

They are simply better, easier, and create a more scalable architecture.
::

Artiel inherits all animal, fun, game, and meme commands from WolfStar.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

"Artiel" is referenced without prior introduction.

This line mentions "Artiel inherits all animal, fun, game, and meme commands" but Artiel hasn't been introduced earlier in the post. Consider adding a section header or brief introduction for Artiel similar to the "Moderation bots - WolfStar" and "Notification bots - Staryl" sections.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/blog/wolfstar-v7.md` at line 34, Introduce "Artiel" before the
sentence that mentions it: add a section header like "Utility bots - Artiel"
(matching the style of "Moderation bots - WolfStar" and "Notification bots -
Staryl") and a one- or two-sentence intro describing what Artiel is and its
purpose, then keep the existing line "Artiel inherits all animal, fun, game, and
meme commands from WolfStar" under that section; ensure the new header and intro
use the same formatting and tone as the other bot sections.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (2)
app/pages/blog/index.vue (1)

7-7: ⚠️ Potential issue | 🟠 Major

useBlog() still exposes drafts on the public index.

The current query in app/composables/useBlog.ts orders posts but never excludes draft: true, so the first draft added to the collection will show up on /blog.

🔒 Proposed fix in app/composables/useBlog.ts
 				queryCollection("blog")
 					.where("extension", "=", "md")
+					.where("draft", "=", false)
 					.order("date", "DESC")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/pages/blog/index.vue` at line 7, The public blog index is showing draft
posts because useBlog() (specifically the fetchList/articles query in the
useBlog composable) does not filter out items with draft: true; update the query
used by fetchList (and any related data-fetching functions inside useBlog) to
explicitly exclude drafts (e.g., add a filter for draft === false or draft not
true) so only non-draft posts are returned to the public /blog index. Ensure the
change is applied where articles are derived/fetched so both initial load and
subsequent fetchList calls honor the draft filter.
content.config.ts (1)

26-27: ⚠️ Potential issue | 🟠 Major

Use the shared Image schema for post cover images.

Keeping image as a bare string means posts cannot provide alt text, so the UI has to invent a generic alternative for every cover image. Reusing Image here lets frontmatter carry a meaningful text alternative instead.

♻️ Proposed fix
 			schema: object({
-				image: optional(string()),
+				image: optional(Image),
 				authors: array(Author),

Update the blog frontmatter and consumers to read image.src / image.alt as part of the same change.

As per coding guidelines, "Informative images and graphics must have meaningful alternatives using alt text for img or role='img' and aria-label/aria-labelledby for SVG."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content.config.ts` around lines 26 - 27, The frontmatter schema currently
defines image as optional(string()), which prevents carrying alt text; replace
that field with the shared Image schema (use the Image symbol) so frontmatter
exposes image.src and image.alt, and then update all consumers that read the
post frontmatter to access image.src and image.alt instead of the bare image
string (adjust any parsing/usage code that referenced image as a string to
handle image?.src and image?.alt).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/components/SocialLinks.vue`:
- Around line 3-24: The two UButton instances (icon="i-simple-icons-discord" and
icon="i-simple-icons-github") have incorrect accessible labels and missing rel
attributes; update the inner sr-only span text to reflect the actual
destinations (e.g., "WolfStar on Discord" and "WolfStar on GitHub") and add
rel="noopener noreferrer" to each UButton that uses target="_blank" to prevent
window.opener security issues and meet accessibility/coding guidelines.

In `@app/pages/blog/`[slug].vue:
- Around line 17-19: The route currently only throws a 404 when article.value is
null/undefined; update the guard in blog/[slug].vue to also treat drafted posts
as not found by checking article.value.draft (e.g., if
isNullOrUndefined(article.value) || article.value.draft) and then call
createError({ statusCode: 404, statusMessage: "Article not found", fatal: true
}) the same way; reference the existing isNullOrUndefined check, the
article.value object, and the createError call so the same behavior applies for
draft: true.
- Around line 114-121: The date parsing using new Date(article.date) is
vulnerable to timezone shifts; change the rendering to parse the YYYY-MM-DD
string as UTC (e.g., split article.date into year, month, day and use new
Date(Date.UTC(year, month-1, day))) before calling toLocaleDateString, and apply
the same fix where article.date is used in both the blog detail time element
(the time element rendering article.date in the [slug].vue template) and the
blog listing (the time rendering article.date in index.vue) so the displayed
date is UTC-safe across time zones.

In `@content/blog/wolfstar-v7.md`:
- Around line 6-10: The post's frontmatter defines authors[].avatar with only a
src, but the Author schema in content.config.ts models avatar as an Image
requiring both src and alt; add a descriptive avatar.alt string for the author
entry (e.g., "RedStar avatar") so the authors[].avatar object includes both src
and alt and stays compliant with the Image/Author schema.

---

Duplicate comments:
In `@app/pages/blog/index.vue`:
- Line 7: The public blog index is showing draft posts because useBlog()
(specifically the fetchList/articles query in the useBlog composable) does not
filter out items with draft: true; update the query used by fetchList (and any
related data-fetching functions inside useBlog) to explicitly exclude drafts
(e.g., add a filter for draft === false or draft not true) so only non-draft
posts are returned to the public /blog index. Ensure the change is applied where
articles are derived/fetched so both initial load and subsequent fetchList calls
honor the draft filter.

In `@content.config.ts`:
- Around line 26-27: The frontmatter schema currently defines image as
optional(string()), which prevents carrying alt text; replace that field with
the shared Image schema (use the Image symbol) so frontmatter exposes image.src
and image.alt, and then update all consumers that read the post frontmatter to
access image.src and image.alt instead of the bare image string (adjust any
parsing/usage code that referenced image as a string to handle image?.src and
image?.alt).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e1795aca-edd5-4875-bb0b-c70fd25c07ba

📥 Commits

Reviewing files that changed from the base of the PR and between a30ec05 and e958783.

📒 Files selected for processing (5)
  • app/components/SocialLinks.vue
  • app/pages/blog/[slug].vue
  • app/pages/blog/index.vue
  • content.config.ts
  • content/blog/wolfstar-v7.md

Comment on lines +3 to +24
<UButton
icon="i-simple-icons-discord"
to="https://join.wolfstar.rocks"
,
target="_blank"
variant="ghost"
color="neutral"
size="xs"
>
<span class="sr-only">Nuxt on Discord</span>
</UButton>
<UButton
icon="i-simple-icons-github"
to="https://github.com/wolfstar-project"
,
target="_blank"
variant="ghost"
color="neutral"
size="xs"
>
<span class="sr-only">Nuxt on GitHub</span>
</UButton>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Correct the link labels and add rel on the external buttons.

These controls point to WolfStar destinations, but the current accessible names still announce “Nuxt”. Also, target="_blank" should be paired with rel="noopener noreferrer".

♻️ Proposed fix
 		<UButton
 			icon="i-simple-icons-discord"
 			to="https://join.wolfstar.rocks"
-			,
 			target="_blank"
+			rel="noopener noreferrer"
 			variant="ghost"
 			color="neutral"
 			size="xs"
 		>
-			<span class="sr-only">Nuxt on Discord</span>
+			<span class="sr-only">Join WolfStar on Discord</span>
 		</UButton>
 		<UButton
 			icon="i-simple-icons-github"
 			to="https://github.com/wolfstar-project"
-			,
 			target="_blank"
+			rel="noopener noreferrer"
 			variant="ghost"
 			color="neutral"
 			size="xs"
 		>
-			<span class="sr-only">Nuxt on GitHub</span>
+			<span class="sr-only">WolfStar on GitHub</span>
 		</UButton>
As per coding guidelines, "Ensure correct accessible name, role, value, states, and properties for all interactive elements."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/SocialLinks.vue` around lines 3 - 24, The two UButton
instances (icon="i-simple-icons-discord" and icon="i-simple-icons-github") have
incorrect accessible labels and missing rel attributes; update the inner sr-only
span text to reflect the actual destinations (e.g., "WolfStar on Discord" and
"WolfStar on GitHub") and add rel="noopener noreferrer" to each UButton that
uses target="_blank" to prevent window.opener security issues and meet
accessibility/coding guidelines.

Comment on lines +17 to +19
if (isNullOrUndefined(article.value)) {
throw createError({ statusCode: 404, statusMessage: "Article not found", fatal: true });
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Treat drafted posts as not found on the detail route.

The schema includes draft, but this guard only handles missing entries. A known slug with draft: true will still render here, and the PR explicitly prerenders /blog/**.

🔒 Proposed fix
-if (isNullOrUndefined(article.value)) {
+if (isNullOrUndefined(article.value) || article.value.draft) {
 	throw createError({ statusCode: 404, statusMessage: "Article not found", fatal: true });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/pages/blog/`[slug].vue around lines 17 - 19, The route currently only
throws a 404 when article.value is null/undefined; update the guard in
blog/[slug].vue to also treat drafted posts as not found by checking
article.value.draft (e.g., if isNullOrUndefined(article.value) ||
article.value.draft) and then call createError({ statusCode: 404, statusMessage:
"Article not found", fatal: true }) the same way; reference the existing
isNullOrUndefined check, the article.value object, and the createError call so
the same behavior applies for draft: true.

Comment on lines +114 to +121
<span class="text-muted"
>&middot;&nbsp;&nbsp;<time>{{
new Date(article.date).toLocaleDateString("en", {
year: "numeric",
month: "short",
day: "numeric",
})
}}</time></span
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -type f -name "[slug].vue" 2>/dev/null | head -5

Repository: wolfstar-project/wolfstar.rocks

Length of output: 57


🏁 Script executed:

git ls-files app/pages/blog/ | head -20

Repository: wolfstar-project/wolfstar.rocks

Length of output: 125


🏁 Script executed:

head -150 app/pages/blog/[slug].vue | tail -50

Repository: wolfstar-project/wolfstar.rocks

Length of output: 1428


🏁 Script executed:

cat -n app/pages/blog/[slug].vue | sed -n '110,125p'

Repository: wolfstar-project/wolfstar.rocks

Length of output: 563


🏁 Script executed:

cat -n app/pages/blog/index.vue | grep -A 10 -B 10 "article.date\|toLocaleDateString"

Repository: wolfstar-project/wolfstar.rocks

Length of output: 770


🏁 Script executed:

rg "new Date\(article\.date\)" app/

Repository: wolfstar-project/wolfstar.rocks

Length of output: 240


🏁 Script executed:

rg "toLocaleDateString" app/ -B 2 -A 2

Repository: wolfstar-project/wolfstar.rocks

Length of output: 638


Fix date interpretation timezone issue in both blog files.

new Date("2024-02-25") is interpreted as midnight UTC, causing the date to display as the previous day for visitors in western U.S. time zones. Apply the UTC-safe formatting fix to both app/pages/blog/[slug].vue (lines 114-121) and app/pages/blog/index.vue (lines 39-45).

🕒 UTC-safe formatting
 <script setup lang="ts">
+const BLOG_DATE_FORMAT = new Intl.DateTimeFormat("en", {
+	year: "numeric",
+	month: "short",
+	day: "numeric",
+	timeZone: "UTC",
+});
 </script>
@@
-								new Date(article.date).toLocaleDateString("en", {
-									year: "numeric",
-									month: "short",
-									day: "numeric",
-								})
+								BLOG_DATE_FORMAT.format(new Date(`${article.date}T00:00:00Z`))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/pages/blog/`[slug].vue around lines 114 - 121, The date parsing using new
Date(article.date) is vulnerable to timezone shifts; change the rendering to
parse the YYYY-MM-DD string as UTC (e.g., split article.date into year, month,
day and use new Date(Date.UTC(year, month-1, day))) before calling
toLocaleDateString, and apply the same fix where article.date is used in both
the blog detail time element (the time element rendering article.date in the
[slug].vue template) and the blog listing (the time rendering article.date in
index.vue) so the displayed date is UTC-safe across time zones.

Comment on lines +6 to +10
authors:
- name: RedStar
to: https://github.com/RedStar071
avatar:
src: https://github.com/RedStar071.png
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add the missing avatar.alt field.

content.config.ts models authors[].avatar as an Image, so once avatar is present it needs both src and alt. This entry only provides src, which leaves the post data out of sync with the declared collection schema.

🛠️ Proposed fix
 authors:
     - name: RedStar
       to: https://github.com/RedStar071
       avatar:
           src: https://github.com/RedStar071.png
+          alt: Avatar of RedStar
Based on learnings, "The Author schema requires a `name` field and optionally includes an `avatar` field which must be an `Image` object with `src` and `alt` properties."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
authors:
- name: RedStar
to: https://github.com/RedStar071
avatar:
src: https://github.com/RedStar071.png
authors:
- name: RedStar
to: https://github.com/RedStar071
avatar:
src: https://github.com/RedStar071.png
alt: Avatar of RedStar
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/blog/wolfstar-v7.md` around lines 6 - 10, The post's frontmatter
defines authors[].avatar with only a src, but the Author schema in
content.config.ts models avatar as an Image requiring both src and alt; add a
descriptive avatar.alt string for the author entry (e.g., "RedStar avatar") so
the authors[].avatar object includes both src and alt and stays compliant with
the Image/Author schema.

Copy link
Copy Markdown
Member

@lorypelli lorypelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you decide to use Valibot instead of Zod or Arktype?

@RedStar071
Copy link
Copy Markdown
Member Author

why did you decide to use Valibot instead of Zod or Arktype?

Valibot its faster and lighter than zod

@RedStar071
Copy link
Copy Markdown
Member Author

@copilot Verify each finding against the current code and only fix it if needed.

In @content.config.ts at line 27, The current schema defines the field named
"date" using string(), which allows malformed dates; update the schema entry for
the "date" property in the content config (the object that contains date:
string()) to use Valibot's stricter date validators — e.g., replace string()
with pipe(string(), isoDate()) or use date() if you want a native Date object;
reference the symbols string(), pipe(), isoDate(), and date() when making the
change so the "date" field enforces ISO date validation.

…tring(), isoDate())

Agent-Logs-Url: https://github.com/wolfstar-project/wolfstar.rocks/sessions/71837fb6-15bb-4970-ab21-4af436819dd9

Co-authored-by: RedStar071 <76824516+RedStar071@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 29, 2026

why did you decide to use Valibot instead of Zod or Arktype?

Valibot was already a production dependency in package.json (used elsewhere in the project) and it's a natural fit for @nuxt/content v3's collection schema API. Compared to Zod it's significantly smaller (~8KB vs ~60KB) with no runtime overhead from class instantiation, and compared to ArkType it has a simpler, more readable API for defining content schemas. Since the project already had it as a dependency, it avoided adding a new library.

@copilot Verify each finding against the current code and only fix it if needed.

In @content.config.ts at line 27, The current schema defines the field named
...

Verified — the date field was using bare string(). Updated in commit 011e3c0 to pipe(string(), isoDate()), which enforces ISO 8601 date format (e.g. 2024-02-25) at schema validation time. The existing blog post's date is valid ISO format so no content changes were needed.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • checkpoint.prisma.io
    • Triggering command: /opt/hostedtoolcache/node/24.14.0/x64/bin/node /opt/hostedtoolcache/node/24.14.0/x64/bin/node /home/REDACTED/work/wolfstar.rocks/wolfstar.rocks/node_modules/.pnpm/prisma@6.19.2_magicast@0.5.2_typescript@5.9.3/node_modules/prisma/build/child {&#34;product&#34;:&#34;prisma&#34;,&#34;version&#34;:&#34;6.19.2&#34;,&#34;cli_install_type&#34;:&#34;local&#34;,&#34;information&#34;:&#34;&#34;,&#34;local_timestamp&#34;:&#34;2026-03-29T15:45:26Z&#34;,&#34;project_hash&#34;:&#34;8cee999f&#34;,&#34;cli_path&#34;:&#34;/home/REDACTED/work/wolfstar.rocks/wolfstar.rocks/node_modules/.pnpm/prisma@6.19.2_magicast@0.5 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants