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
58 changes: 56 additions & 2 deletions .github/workflows/site-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ concurrency:

jobs:
build:
timeout-minutes: 10
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
Comment thread
rh-hemartin marked this conversation as resolved.
Comment thread
rh-hemartin marked this conversation as resolved.
submodules: true
fetch-tags: true
fetch-depth: 0

Comment thread
rh-hemartin marked this conversation as resolved.
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
with:
Expand All @@ -52,8 +54,38 @@ jobs:
- name: Install JS dependencies
run: npm ci

# Caches are immutable: save is a no-op if the primary key already exists.
# Unique time-based key + restore-keys is the documented way to persist an
# updated tree; restore-keys then takes the most recently created prefix
# match (the last main save, which has the most tagged versions).
# Save only on main, and only when mvb wrote new per-tag artifacts.
- name: Compute mvb cache key
id: mvb-key
run: echo "key=lando-mvb-$(date -u +%Y%m%d%H%M%S)" >> "$GITHUB_OUTPUT"

- uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
Comment thread
rh-hemartin marked this conversation as resolved.
with:
key: ${{ steps.mvb-key.outputs.key }}
restore-keys: |
lando-mvb-
path: docs/.vitepress/cache/@lando/mvb

- name: Snapshot restored mvb cache
id: mvb-before
env:
MVB_CACHE: docs/.vitepress/cache/@lando/mvb
run: |
set -euo pipefail
mkdir -p "$MVB_CACHE"
hash=$(find "$MVB_CACHE" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort | sha256sum | awk '{print $1}')
echo "hash=${hash}" >> "$GITHUB_OUTPUT"

- name: Build documentation site
run: npm run docs:build
run: |
git submodule update --init
npx mvb docs
env:
VPL_MVB_BRANCH: ${{ github.event.pull_request.head.sha || github.sha }}

- name: Prepare deploy bundle
run: |
Expand All @@ -72,3 +104,25 @@ jobs:
name: site
path: _bundle/
retention-days: 5

- name: Detect new mvb version artifacts
id: mvb-after
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env:
MVB_CACHE: docs/.vitepress/cache/@lando/mvb
BEFORE: ${{ steps.mvb-before.outputs.hash }}
run: |
set -euo pipefail
mkdir -p "$MVB_CACHE"
hash=$(find "$MVB_CACHE" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort | sha256sum | awk '{print $1}')
if [[ "$hash" != "$BEFORE" ]]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi

- uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.mvb-after.outputs.changed == 'true'
with:
key: ${{ steps.mvb-key.outputs.key }}
path: docs/.vitepress/cache/@lando/mvb
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[submodule "experiments"]
path = experiments
url = git@github.com:fullsend-ai/experiments.git
url = https://github.com/fullsend-ai/experiments.git
branch = main
[submodule "eval/.agent-eval-harness"]
path = eval/.agent-eval-harness
Expand Down
5 changes: 4 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ cloudflare_site/
*.py
hack/
internal/
docs/
docs/*
!docs/.vitepress/
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
docs/.vitepress/dist/
docs/.vitepress/cache/
web/public/
3 changes: 2 additions & 1 deletion .stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": ["stylelint-config-standard", "stylelint-config-html/vue"],
"rules": {
"custom-property-pattern": null,
"selector-class-pattern": null
"selector-class-pattern": null,
"property-no-vendor-prefix": [true, { "ignoreProperties": ["-webkit-background-clip", "-webkit-backdrop-filter"] }]
}
}
43 changes: 37 additions & 6 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineConfig } from "vitepress";
import { defineConfig } from "@lando/vitepress-theme-default-plus/config";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
Expand All @@ -15,6 +15,10 @@ import {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const docsDir = path.resolve(__dirname, "..");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] runtime-mechanism

The version variable reads .version from package.json, which has no version field in the repo. The ?? "dev" fallback always triggers for local and PR CI builds. The mechanism is intentional: mvb injects the version into package.json during tagged-release sub-builds in a temp checkout, and doc-site.md documents this behavior.

const version =
Comment thread
rh-hemartin marked this conversation as resolved.
Comment thread
rh-hemartin marked this conversation as resolved.
Comment thread
rh-hemartin marked this conversation as resolved.
JSON.parse(fs.readFileSync(path.resolve(__dirname, "..", "..", "package.json"), "utf-8"))
.version ?? "dev";

function getMarkdownFiles(dir: string, base: string): { text: string; link: string }[] {
const fullDir = path.resolve(docsDir, dir);
if (!fs.existsSync(fullDir)) return [];
Expand Down Expand Up @@ -188,14 +192,18 @@ export default defineConfig({
},

srcExclude: ["**/agents/icons/**", "**/testing/**"],

ignoreDeadLinks: true,

themeConfig: {
logo: "/img/logo.png",
logoLink: { link: "https://fullsend.sh", target: "_self" },
siteTitle: "Fullsend",

multiVersionBuild: {
satisfies: ">=0.37.0",
build: "stable",
},

nav: [
{ text: "Docs", link: "/guides/getting-started/", activeMatch: "^/(?!cli/)" },
{ text: "CLI Reference", link: "/cli/", activeMatch: "/cli/" },
Expand Down Expand Up @@ -382,6 +390,26 @@ export default defineConfig({
],
},

sidebarEnder: {
text: version,
collapsed: true,
items: [
{
text: "Other Doc Versions",
items: [
{ rel: "mvb", text: "stable", target: "_blank", link: "/stable/" },
{ rel: "mvb", text: "edge", target: "_blank", link: "/edge/" },
{ rel: "mvb", text: "dev", target: "_blank", link: "/dev/" },
{ text: "<strong>see all versions</strong>", link: "/v/" },
],
},
{
text: "Other Releases",
link: "https://github.com/fullsend-ai/fullsend/releases",
},
],
},

socialLinks: [{ icon: "github", link: "https://github.com/fullsend-ai/fullsend" }],

editLink: {
Expand All @@ -393,7 +421,10 @@ export default defineConfig({
provider: "local",
options: {
scopes: [
{ label: "Guides", prefixes: ["/docs/guides/", "/docs/agents/", "/docs/cli/", "/docs/runtimes"] },
{
label: "Guides",
prefixes: ["/docs/guides/", "/docs/agents/", "/docs/cli/", "/docs/runtimes"],
},
{
label: "Design Docs",
prefixes: ["/docs/problems/", "/docs/ADRs/", "/docs/normative/", "/docs/spikes/"],
Expand Down Expand Up @@ -458,15 +489,15 @@ export default defineConfig({
shikiSetup: async (shiki) => {
await shiki.loadLanguage("toml");
},

preConfig: (md) => {
const defaultParse = md.parse.bind(md);
md.parse = (src: string, env: Record<string, unknown>) => {
const rel = (env?.relativePath as string) ?? "";
Comment thread
rh-hemartin marked this conversation as resolved.
if (rel === "v/index.md") return defaultParse(src, env);
return defaultParse(escapeVueSyntax(src), env);
};
},
// Auto-add v-pre to inline code so `{{ }}` inside backticks is safe.
// Recommended by VitePress maintainer brc-dd:
// https://github.com/vuejs/vitepress/discussions/3724
config: (md) => {
Comment thread
rh-hemartin marked this conversation as resolved.
const defaultCodeInline = md.renderer.rules.code_inline!;
md.renderer.rules.code_inline = (tokens, idx, options, env, self) => {
Expand Down
23 changes: 23 additions & 0 deletions docs/.vitepress/lando-theme.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
declare module "@lando/vitepress-theme-default-plus/config" {
import type { UserConfig } from "vitepress";

interface VPLThemeConfig {
sidebarEnder?: unknown;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] weak-type-declarations

sidebarEnder and multiVersionBuild are typed as unknown in the declaration file, plus a catch-all [key: string]: unknown index signature. This provides minimal type safety for the VPL theme config extensions.

Suggested fix: Define the shapes of sidebarEnder and multiVersionBuild to match their usage in config.ts.

multiVersionBuild?: unknown;
[key: string]: unknown;
}

export function defineConfig(config: UserConfig<VPLThemeConfig>): UserConfig<VPLThemeConfig>;
}

declare module "@lando/vitepress-theme-default-plus" {
import type { Theme } from "vitepress";
const theme: Theme;
export default theme;
}

declare module "*.vue" {
import type { DefineComponent } from "vue";
const component: DefineComponent;
export default component;
}
2 changes: 1 addition & 1 deletion docs/.vitepress/search.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "vitepress";
declare module "vitepress" {
namespace DefaultTheme {
interface LocalSearchOptions {
scopes?: { label: string; prefixes: string[] }[];
scopes?: { label: string; prefixes: string[]; others?: boolean }[];
}
}
}
72 changes: 36 additions & 36 deletions docs/.vitepress/theme/components/Mermaid.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<script setup lang="ts">
Comment thread
rh-hemartin marked this conversation as resolved.
import { ref, onMounted, onUnmounted } from 'vue'
import EnlargeDialog from './EnlargeDialog.vue'
import { ref, onMounted, onUnmounted } from "vue";
import EnlargeDialog from "./EnlargeDialog.vue";

const props = defineProps<{
graph: string
id: string
}>()
graph: string;
id: string;
}>();

const svg = ref<string | null>(null)
const error = ref<string | null>(null)
const naturalWidth = ref<number | null>(null)
const enlarge = ref<InstanceType<typeof EnlargeDialog> | null>(null)
let observer: MutationObserver | null = null
let lastTheme: string | null = null
let rendering = false
let renderSeq = 0
const svg = ref<string | null>(null);
const error = ref<string | null>(null);
const naturalWidth = ref<number | null>(null);
const enlarge = ref<InstanceType<typeof EnlargeDialog> | null>(null);
let observer: MutationObserver | null = null;
let lastTheme: string | null = null;
let rendering = false;
let renderSeq = 0;

// The inline diagram is scaled to the content column (mermaid sets
// width: 100%; max-width: <viewBox width>), which makes wide flowcharts
Expand All @@ -23,35 +23,35 @@ let renderSeq = 0
// click anywhere on the figure opens it too, and the diagram text stays
// selectable because the figure itself is not a button.
async function renderChart() {
if (rendering) return
rendering = true
const seq = ++renderSeq
if (rendering) return;
rendering = true;
const seq = ++renderSeq;
try {
const mermaid = (await import('mermaid')).default
const isDark = document.documentElement.classList.contains('dark')
const theme = isDark ? 'dark' : 'default'
const mermaid = (await import("mermaid")).default;
const isDark = document.documentElement.classList.contains("dark");
const theme = isDark ? "dark" : "default";
if (theme !== lastTheme) {
mermaid.initialize({
securityLevel: 'strict',
securityLevel: "strict",
startOnLoad: false,
theme,
})
lastTheme = theme
});
lastTheme = theme;
}
const { svg: rendered } = await mermaid.render(
`${props.id}-${seq}`,
decodeURIComponent(props.graph),
)
svg.value = rendered
error.value = null
const viewBox = rendered.match(/viewBox="([^"]+)"/)
const width = viewBox ? parseFloat(viewBox[1].split(/\s+/)[2]) : NaN
naturalWidth.value = Number.isFinite(width) ? width : null
);
svg.value = rendered;
error.value = null;
const viewBox = rendered.match(/viewBox="([^"]+)"/);
const width = viewBox ? parseFloat(viewBox[1].split(/\s+/)[2]) : NaN;
naturalWidth.value = Number.isFinite(width) ? width : null;
} catch (e) {
error.value = e instanceof Error ? e.message : 'Failed to render diagram'
svg.value = null
error.value = e instanceof Error ? e.message : "Failed to render diagram";
svg.value = null;
} finally {
rendering = false
rendering = false;
}
}

Expand All @@ -67,12 +67,12 @@ function onFigureClick(e: MouseEvent) {
}

onMounted(async () => {
await renderChart()
observer = new MutationObserver(() => renderChart())
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })
})
await renderChart();
observer = new MutationObserver(() => renderChart());
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
});

onUnmounted(() => observer?.disconnect())
onUnmounted(() => observer?.disconnect());
</script>

<template>
Expand Down
18 changes: 9 additions & 9 deletions docs/.vitepress/theme/components/ReadingProgress.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { ref, onMounted, onUnmounted } from "vue";

const width = ref(0)
const width = ref(0);

function onScroll() {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement
const total = scrollHeight - clientHeight
width.value = total > 0 ? (scrollTop / total) * 100 : 0
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
const total = scrollHeight - clientHeight;
width.value = total > 0 ? (scrollTop / total) * 100 : 0;
}

onMounted(() => {
window.addEventListener('scroll', onScroll, { passive: true })
})
window.addEventListener("scroll", onScroll, { passive: true });
});

onUnmounted(() => {
window.removeEventListener('scroll', onScroll)
})
window.removeEventListener("scroll", onScroll);
});
</script>

<template>
Expand Down
Loading
Loading