From 920fc30a1272cc5c920414172f360ac50066055e Mon Sep 17 00:00:00 2001 From: TheRealToxicDev Date: Tue, 3 Feb 2026 17:55:06 -0700 Subject: [PATCH 1/5] Add GitHub workflows and fix import organization --- package.json | 3 +- src/components/MarkdownRenderer.tsx | 4 +-- src/components/landing/Header.tsx | 2 +- src/components/landing/Hero.tsx | 2 +- src/components/landing/QuickStart.tsx | 3 +- src/components/layouts/DocsLayout.tsx | 6 ++-- src/lib/useVersion.ts | 2 +- src/routes/docs/$.tsx | 42 ++++++++++++--------------- src/routes/features.tsx | 2 +- 9 files changed, 30 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 0621fae..54a1a64 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "test": "vitest run", "format": "biome format", "format:fix": "biome format --write", - "format:check": "biome format --check", + "format:check": "biome check", + "format:apply": "biome check --fix", "lint": "biome lint", "check": "biome check", "deploy": "npm run build && wrangler deploy" diff --git a/src/components/MarkdownRenderer.tsx b/src/components/MarkdownRenderer.tsx index 6508e69..dec51cb 100644 --- a/src/components/MarkdownRenderer.tsx +++ b/src/components/MarkdownRenderer.tsx @@ -1,5 +1,5 @@ -import { Check, Copy, AlertTriangle, Info, Lightbulb } from "lucide-react"; -import { useState, useCallback } from "react"; +import { AlertTriangle, Check, Copy, Info, Lightbulb } from "lucide-react"; +import { useCallback, useState } from "react"; import ReactMarkdown from "react-markdown"; import rehypeHighlight from "rehype-highlight"; import rehypeRaw from "rehype-raw"; diff --git a/src/components/landing/Header.tsx b/src/components/landing/Header.tsx index b2d295b..96da1a6 100644 --- a/src/components/landing/Header.tsx +++ b/src/components/landing/Header.tsx @@ -1,8 +1,8 @@ import { Github, Menu, Twitter, X } from "lucide-react"; import { useState } from "react"; +import { useVersion } from "../../lib/useVersion"; import { LogoIcon } from "../Logo"; import { Button } from "../ui/Button"; -import { useVersion } from "../../lib/useVersion"; export function Header() { const [mobileMenuOpen, setMobileMenuOpen] = useState(false); diff --git a/src/components/landing/Hero.tsx b/src/components/landing/Hero.tsx index f13a98b..782a053 100644 --- a/src/components/landing/Hero.tsx +++ b/src/components/landing/Hero.tsx @@ -1,6 +1,6 @@ import { AlertTriangle, ChevronRight, Github, Terminal } from "lucide-react"; -import { Button } from "../ui/Button"; import { useVersion } from "../../lib/useVersion"; +import { Button } from "../ui/Button"; export function Hero() { const { version } = useVersion(); diff --git a/src/components/landing/QuickStart.tsx b/src/components/landing/QuickStart.tsx index de29d25..5de5632 100644 --- a/src/components/landing/QuickStart.tsx +++ b/src/components/landing/QuickStart.tsx @@ -1,7 +1,6 @@ import * as Tabs from "@radix-ui/react-tabs"; import { Check, Copy, GitBranch, Globe, Terminal } from "lucide-react"; -import { useId } from "react"; -import { useState } from "react"; +import { useId, useState } from "react"; type TokenType = "command" | "flag" | "path" | "comment" | "string" | "text"; diff --git a/src/components/layouts/DocsLayout.tsx b/src/components/layouts/DocsLayout.tsx index c54dfea..6ff1f4d 100644 --- a/src/components/layouts/DocsLayout.tsx +++ b/src/components/layouts/DocsLayout.tsx @@ -1,8 +1,8 @@ -import { ChevronDown, Home, Menu, X, List, Search } from "lucide-react"; -import { useState, useEffect } from "react"; +import { ChevronDown, Home, List, Menu, Search, X } from "lucide-react"; +import { useEffect, useState } from "react"; +import { useVersion } from "../../lib/useVersion"; import { LogoIcon } from "../Logo"; import { Button } from "../ui/Button"; -import { useVersion } from "../../lib/useVersion"; interface LayoutProps { children: React.ReactNode; diff --git a/src/lib/useVersion.ts b/src/lib/useVersion.ts index 36e923f..87f5c55 100644 --- a/src/lib/useVersion.ts +++ b/src/lib/useVersion.ts @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useEffect, useState } from "react"; interface VersionInfo { version: string; diff --git a/src/routes/docs/$.tsx b/src/routes/docs/$.tsx index 57fd79a..3243c9b 100644 --- a/src/routes/docs/$.tsx +++ b/src/routes/docs/$.tsx @@ -3,40 +3,34 @@ import { createFileRoute } from "@tanstack/react-router"; const SITE_URL = "https://noslop.tech"; const DOCS_IMAGE = `${SITE_URL}/og-docs.png`; +import aiConfigurationMd from "../../../docs/ai/configuration.md?raw"; +import aiExamplesMd from "../../../docs/ai/examples.md?raw"; +import aiIndexMd from "../../../docs/ai/index.md?raw"; +import analysisGitMd from "../../../docs/analysis/git.md?raw"; +import analysisIndexMd from "../../../docs/analysis/index.md?raw"; +import analysisRepositoryMd from "../../../docs/analysis/repository.md?raw"; +import analysisWebMd from "../../../docs/analysis/web.md?raw"; +import cliCommandsMdNew from "../../../docs/cli/commands.md?raw"; +import cliDetectionStrategiesMd from "../../../docs/cli/detection-strategies.md?raw"; +import cliIndexMd from "../../../docs/cli/index.md?raw"; +import communityContributingMd from "../../../docs/community/contributing.md?raw"; +import communityIndexMd from "../../../docs/community/index.md?raw"; +import communitySecurityMd from "../../../docs/community/security.md?raw"; +import gettingStartedConfigurationMd from "../../../docs/getting-started/configuration.md?raw"; // Import all markdown files statically for Cloudflare Workers compatibility // Getting Started section import gettingStartedIndexMd from "../../../docs/getting-started/index.md?raw"; import gettingStartedInstallationMd from "../../../docs/getting-started/installation.md?raw"; -import gettingStartedQuickStartMd from "../../../docs/getting-started/quick-start.md?raw"; import gettingStartedQuickReferenceMd from "../../../docs/getting-started/quick-reference.md?raw"; -import gettingStartedConfigurationMd from "../../../docs/getting-started/configuration.md?raw"; - -import cliIndexMd from "../../../docs/cli/index.md?raw"; -import cliCommandsMdNew from "../../../docs/cli/commands.md?raw"; -import cliDetectionStrategiesMd from "../../../docs/cli/detection-strategies.md?raw"; - -import analysisIndexMd from "../../../docs/analysis/index.md?raw"; -import analysisRepositoryMd from "../../../docs/analysis/repository.md?raw"; -import analysisGitMd from "../../../docs/analysis/git.md?raw"; -import analysisWebMd from "../../../docs/analysis/web.md?raw"; - -import aiIndexMd from "../../../docs/ai/index.md?raw"; -import aiConfigurationMd from "../../../docs/ai/configuration.md?raw"; -import aiExamplesMd from "../../../docs/ai/examples.md?raw"; - -import integrationsIndexMd from "../../../docs/integrations/index.md?raw"; +import gettingStartedQuickStartMd from "../../../docs/getting-started/quick-start.md?raw"; import integrationsAgentSkillsMd from "../../../docs/integrations/agent-skills.md?raw"; +import integrationsIndexMd from "../../../docs/integrations/index.md?raw"; import integrationsWebhooksMd from "../../../docs/integrations/webhooks.md?raw"; - -import referenceIndexMd from "../../../docs/reference/index.md?raw"; import referenceAdvancedConfigMd from "../../../docs/reference/advanced-configuration.md?raw"; import referenceBuildDevMd from "../../../docs/reference/build-development.md?raw"; -import referenceTroubleshootingMd from "../../../docs/reference/troubleshooting.md?raw"; import referenceDisclaimerMd from "../../../docs/reference/disclaimer.md?raw"; - -import communityIndexMd from "../../../docs/community/index.md?raw"; -import communityContributingMd from "../../../docs/community/contributing.md?raw"; -import communitySecurityMd from "../../../docs/community/security.md?raw"; +import referenceIndexMd from "../../../docs/reference/index.md?raw"; +import referenceTroubleshootingMd from "../../../docs/reference/troubleshooting.md?raw"; import { DocsLayout } from "../../components/layouts/DocsLayout"; import { MarkdownRenderer } from "../../components/MarkdownRenderer"; diff --git a/src/routes/features.tsx b/src/routes/features.tsx index 8811fbd..01b8e09 100644 --- a/src/routes/features.tsx +++ b/src/routes/features.tsx @@ -16,10 +16,10 @@ import { Webhook, Zap, } from "lucide-react"; +import { useState } from "react"; import { LogoIcon } from "../components/Logo"; import { Footer } from "../components/landing/Footer"; import { useVersion } from "../lib/useVersion"; -import { useState } from "react"; const coreFeatures = [ { From a509cd0184892283c0091e49ef4160c21784a794 Mon Sep 17 00:00:00 2001 From: TheRealToxicDev Date: Tue, 3 Feb 2026 18:31:29 -0700 Subject: [PATCH 2/5] fix up chagelog page issues --- src/routes/changelog.tsx | 193 ++++++++++++++++++++++++++++++--------- 1 file changed, 150 insertions(+), 43 deletions(-) diff --git a/src/routes/changelog.tsx b/src/routes/changelog.tsx index 73aacec..95b2dcc 100644 --- a/src/routes/changelog.tsx +++ b/src/routes/changelog.tsx @@ -8,6 +8,7 @@ import { Download, ExternalLink, GitCommit, + GithubIcon, Loader2, Plus, Tag, @@ -46,37 +47,92 @@ function parseReleaseBody(body: string): ParsedSection[] { const sections: ParsedSection[] = []; const normalized = body.replace(/\r\n/g, "\n"); - // Parse sections within the release body - const sectionRegex = - /### (Added|Changed|Fixed|Technical Details|Usage Examples|Known Limitations)\n([\s\S]*?)(?=###|$)/g; - const sectionMatches = [...normalized.matchAll(sectionRegex)]; + // Split by section headers (### Header) + const sectionSplit = normalized.split(/^### /m); - for (const sectionMatch of sectionMatches) { - const sectionTitle = sectionMatch[1]; - const sectionContent = sectionMatch[2].trim(); + // First element is before any header, skip it + for (let i = 1; i < sectionSplit.length; i++) { + const part = sectionSplit[i]; + const lines = part.split("\n"); + const firstLine = lines[0]; + + // Extract section title from first line + let sectionTitle = firstLine; + let sectionContent = lines.slice(1).join("\n").trim(); let type: ParsedSection["type"] = "other"; - if (sectionTitle === "Added") type = "added"; - else if (sectionTitle === "Changed") type = "changed"; - else if (sectionTitle === "Fixed") type = "fixed"; - else if (sectionTitle === "Technical Details") type = "technical"; + if (firstLine === "Added") { + type = "added"; + } else if (firstLine === "Changed") { + type = "changed"; + } else if (firstLine === "Fixed") { + type = "fixed"; + } else if (firstLine === "Technical Details") { + type = "technical"; + } - // Parse items - look for bullet points or sub-sections + // Parse items - look for bullet points, numbered items, or sub-sections const items: string[] = []; - const lines = sectionContent.split("\n"); + const contentLines = sectionContent.split("\n"); + let currentItem = ""; + let currentSubsection = ""; + + for (const line of contentLines) { + // Skip completely empty lines + if (!line.trim()) continue; - for (const line of lines) { - if (line.startsWith("- ") || line.startsWith("* ")) { + // Sub-section headers (#### ) + if (line.startsWith("#### ")) { if (currentItem) items.push(currentItem.trim()); - currentItem = line.slice(2); - } else if (line.startsWith("#### ")) { + currentSubsection = line.slice(5); // Remove "#### " + currentItem = ""; // Reset, don't create item yet + continue; + } + + // Top-level bullets (not indented) + if ( + (line.startsWith("- ") || line.startsWith("* ")) && + !line.startsWith(" ") + ) { + if (currentItem) items.push(currentItem.trim()); + const bulletText = line.slice(2); + // If we have a subsection, include it with the first item + if (currentSubsection && currentItem === "") { + currentItem = `**${currentSubsection}**\n${bulletText}`; + currentSubsection = ""; // Consumed + } else { + currentItem = bulletText; + } + } + // Numbered items (1., 2., etc.) not indented + else if (/^\d+\.\s/.test(line) && !line.startsWith(" ")) { if (currentItem) items.push(currentItem.trim()); - currentItem = `**${line.slice(5)}**`; - } else if (line.trim() && currentItem) { - currentItem += ` ${line.trim()}`; + const numberedText = line.replace(/^\d+\.\s/, ""); + // If we have a subsection, include it with the first item + if (currentSubsection && currentItem === "") { + currentItem = `**${currentSubsection}**\n${numberedText}`; + currentSubsection = ""; // Consumed + } else { + currentItem = numberedText; + } + } + // Sub-items (indented bullets or numbered) + else if ( + line.startsWith(" - ") || + line.startsWith(" * ") || + /^ \d+\.\s/.test(line) + ) { + if (currentItem) { + currentItem += `\n${line.trim()}`; + } + } + // Continuation lines (non-empty, not starting with special chars) + else if (line.trim() && currentItem) { + currentItem += `\n${line.trim()}`; } } + if (currentItem) items.push(currentItem.trim()); if (items.length > 0) { @@ -116,7 +172,7 @@ function getSectionColor(type: string) { } function ReleaseSection({ section }: { section: ParsedSection }) { - const [expanded, setExpanded] = useState(section.type === "added"); + const [expanded, setExpanded] = useState(false); return (
@@ -148,20 +204,25 @@ function ReleaseSection({ section }: { section: ParsedSection }) { {section.items.map((item) => (
- $1', - ) - .replace( - /`(.*?)`/g, - '$1', - ), - }} - /> +
+ {item.split("\n").map((line, idx) => ( +
0 ? "ml-2 text-white/60" : ""} + dangerouslySetInnerHTML={{ + __html: line + .replace( + /\*\*(.*?)\*\*/g, + '$1', + ) + .replace( + /`(.*?)`/g, + '$1', + ), + }} + /> + ))} +
))}
@@ -223,7 +284,7 @@ function ReleaseCard({ Latest )} - {release.prerelease && ( + {release.prerelease && ( Pre-release @@ -315,6 +376,13 @@ function ChangelogPage() { const [releases, setReleases] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [page, setPage] = useState(1); + const itemsPerPage = 10; + const totalPages = Math.ceil(releases.length / itemsPerPage); + const paginatedReleases = releases.slice( + (page - 1) * itemsPerPage, + page * itemsPerPage, + ); useEffect(() => { async function fetchReleases() { @@ -379,8 +447,7 @@ function ChangelogPage() { rel="noopener noreferrer" className="text-sm text-white/50 hover:text-white transition-colors flex items-center gap-1" > - GitHub - +
@@ -425,7 +492,7 @@ function ChangelogPage() { releases
-
+
Latest:{" "} {releases[0]?.tag_name} @@ -465,19 +532,59 @@ function ChangelogPage() { )} {!loading && !error && releases.length > 0 && ( + <>
- {releases.map((release, idx) => ( + {paginatedReleases.map((release, idx) => ( ))}
+ + {/* Pagination */} + {totalPages > 1 && ( +
+ + + {Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => ( + + ))} + + +
+ )} + )} - {/* End of timeline */} - {!loading && !error && releases.length > 0 && ( + {/* End of timeline - only show on last page */} + {!loading && !error && releases.length > 0 && page === totalPages && (
From d206427ad0c383c951f4b1d5836b337a6ee94bf2 Mon Sep 17 00:00:00 2001 From: TheRealToxicDev Date: Tue, 3 Feb 2026 20:07:22 -0700 Subject: [PATCH 3/5] fix missing icons on features and examples pages --- src/routes/changelog.tsx | 4 ++-- src/routes/examples.tsx | 13 ++++++++++++- src/routes/features.tsx | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/routes/changelog.tsx b/src/routes/changelog.tsx index 95b2dcc..ef1381b 100644 --- a/src/routes/changelog.tsx +++ b/src/routes/changelog.tsx @@ -196,7 +196,7 @@ function ReleaseSection({ section }: { section: ParsedSection }) { ) : ( - )} + )} {expanded && ( @@ -204,7 +204,7 @@ function ReleaseSection({ section }: { section: ParsedSection }) { {section.items.map((item) => (
-
+
{item.split("\n").map((line, idx) => (
Date: Wed, 4 Feb 2026 11:43:48 -0700 Subject: [PATCH 4/5] refactor(docs): move planned security changes to .todo --- .todo/SECURITY.md | 9 +++++++++ docs/community/security.md | 17 ----------------- 2 files changed, 9 insertions(+), 17 deletions(-) create mode 100644 .todo/SECURITY.md diff --git a/.todo/SECURITY.md b/.todo/SECURITY.md new file mode 100644 index 0000000..89b4aaf --- /dev/null +++ b/.todo/SECURITY.md @@ -0,0 +1,9 @@ +## Planned Security Updates + +### v0.3.0 +- [ ] **Release Signing**: GPG signatures for releases (v0.3.0) +- [ ] **Audit Logging**: Security event logging (v0.3.0) +- [ ] **SBOM**: Software Bill of Materials (v0.3.0) + +### v0.4.0 +- [ ] **RBAC**: Role-based access control for webhook API (v0.4.0) \ No newline at end of file diff --git a/docs/community/security.md b/docs/community/security.md index 2b53eba..9c73729 100644 --- a/docs/community/security.md +++ b/docs/community/security.md @@ -411,23 +411,6 @@ The webhook server is a public HTTP endpoint. Risks: - Set worker limits - Monitor resource usage -## Security Features - -### Current - -- **HMAC Signature Verification**: GitHub and GitLab webhooks -- **Input Validation**: Sanitized repository URLs and paths -- **Resource Limits**: Configurable worker pools -- **Secure Defaults**: AI disabled by default, localhost binding -- **Environment Variables**: Secrets via env vars, not files - -### Planned - -🔄 **Release Signing**: GPG signatures for releases (v0.3.0) -🔄 **RBAC**: Role-based access control for webhook API (v0.4.0) -🔄 **Audit Logging**: Security event logging (v0.3.0) -🔄 **SBOM**: Software Bill of Materials (v0.3.0) - ## Compliance ### Open Source License From 1e45e78a3d947b6cf94c203aeedc129151de00ae Mon Sep 17 00:00:00 2001 From: TheRealToxicDev Date: Wed, 4 Feb 2026 11:46:35 -0700 Subject: [PATCH 5/5] rem(workflow): remove deploy action as cloudflare can handle this --- .github/workflows/deploy.yml | 33 --------------------------------- wrangler.jsonc | 6 ++++++ 2 files changed, 6 insertions(+), 33 deletions(-) delete mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 5d7cd84..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Deploy to Cloudflare Workers - -on: - push: - branches: - - master - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Install Bun - uses: oven-sh/setup-bun@v1 - with: - bun-version: latest - - - name: Install dependencies - run: bun install - - - name: Build - run: bun run build - - - name: Deploy to Cloudflare Workers - run: bun run deploy - env: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} diff --git a/wrangler.jsonc b/wrangler.jsonc index 473bccf..e367a73 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -13,5 +13,11 @@ "vars": { "ENVIRONMENT": "production" + }, + "observability": { + "logs": { + "enabled": true, + "invocation_logs": true + } } }