Skip to content
Merged
22 changes: 19 additions & 3 deletions docs/website/content/docs/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ schemaType: TechArticle

## Overview

QVAC CLI is provided through the `@qvac/cli` npm package and requires `@qvac/sdk` to be installed alongside it in your project. At the moment, it provides the following functionality:
QVAC CLI is provided through the `@qvac/cli` npm package. The CLI itself is installed globally so the `qvac` command is available on your `PATH`; `@qvac/sdk` is installed in your project so the CLI can resolve and run it. At the moment, it provides the following functionality:
- OpenAI-compatible HTTP server
- SDK bundling
- System requirements check
Expand All @@ -16,10 +16,18 @@ QVAC CLI is provided through the `@qvac/cli` npm package and requires `@qvac/sdk

<Steps>
<Step>
Install the SDK and CLI in your project:
Install the CLI globally so the `qvac` command is available on your `PATH`:

```bash
npm install @qvac/sdk @qvac/cli
npm install -g @qvac/cli
```
</Step>

<Step>
Install the SDK as a dependency of the project where you'll run the CLI:

```bash
npm install @qvac/sdk
```

See [Installation](/sdk/getting-started/installation) for environment-specific instructions of the SDK.
Expand All @@ -40,6 +48,14 @@ qvac --help

</Steps>

<Callout type="success">
**Tip:** if you cannot install the CLI globally, you can run it with `npx` instead:

```bash
npx --package "@qvac/cli" qvac --help
```
</Callout>

## OpenAI-compatible HTTP server

QVAC CLI provides an HTTP server that is compatible with the [OpenAI REST API](https://developers.openai.com/api/reference/overview), enabling broad integration with the AI ecosystem. It internally translates HTTP requests into SDK calls. As a result, any system compatible with the OpenAI REST API can point to `http://localhost:11434/v1/` and work without changes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ The following script shows how to provide tool definitions to `completion()`, co
<Tab value="js" label="JavaScript" default>
<WrapCode>

```js file=<rootDir>/packages/sdk/dist/examples/llamacpp-native-tools.js title="completion-tool-call.js" lineNumbers
```js file=<rootDir>/packages/sdk/dist/examples/tools/llamacpp-native-tools.js title="completion-tool-call.js" lineNumbers
```
</WrapCode>
</Tab>

<Tab value="ts" label="TypeScript">
<WrapCode>

```ts file=<rootDir>/packages/sdk/examples/llamacpp-native-tools.ts title="completion-tool-call.ts" lineNumbers
```ts file=<rootDir>/packages/sdk/examples/tools/llamacpp-native-tools.ts title="completion-tool-call.ts" lineNumbers
```
</WrapCode>
</Tab>
Expand Down
46 changes: 46 additions & 0 deletions docs/website/content/docs/troubleshooting.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: Troubleshooting
description: Resolve common issues when using QVAC.
schemaType: HowTo
tocMaxDepth: 2
---

## CLI error: command not found

### Situation

You ran a `qvac` command (e.g., `qvac doctor`) and the shell responded with:

```
zsh: command not found: qvac
```

(On bash: `bash: qvac: command not found`.)

### Cause

The `qvac` binary is shipped by the `@qvac/cli` npm package. It is only added to your shell `PATH` when `@qvac/cli` is installed globally. Without a global install, the binary is not discoverable by name from your shell.

### Solution

Install `@qvac/cli` globally:

```bash
npm install -g @qvac/cli
```

Then re-run your command. For example:

```bash
qvac doctor
```

<Callout type="success">
**Tip:** If you cannot install the CLI globally, you can run it with `npx` instead:

```bash
npx --package "@qvac/cli" qvac doctor
```
</Callout>

See [CLI → Usage](/cli#usage) for the full setup, including installing `@qvac/sdk` in your project.
1 change: 1 addition & 0 deletions docs/website/source.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const docs = defineDocs({
version: z.string().optional(),
ogImage: z.string().optional(),
schemaType: z.enum(SCHEMA_TYPES).optional(),
tocMaxDepth: z.number().int().min(2).max(5).optional(),
}),
postprocess: {
includeProcessedMarkdown: true,
Expand Down
7 changes: 5 additions & 2 deletions docs/website/src/app/(docs)/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ export default async function Page(props: PageProps<'/[[...slug]]'>) {
})
: null;

// Filter ToC to include H2 through H5 (depth 2, 3, 4, and 5)
const filteredToc = page.data.toc?.filter(item => item.depth >= 2 && item.depth <= 5) || [];
// Filter ToC to include H2 through H5 by default. A page can opt into a
// shallower ToC by setting `tocMaxDepth` in its frontmatter (e.g. `2` to
// index only H2 headings).
const tocMaxDepth = page.data.tocMaxDepth ?? 5;
const filteredToc = page.data.toc?.filter(item => item.depth >= 2 && item.depth <= tocMaxDepth) || [];

const isHomePage = !params.slug || params.slug.length === 0;
const jsonLdBlocks = buildDocsJsonLd(page, params.slug ?? [], isHomePage);
Expand Down
28 changes: 25 additions & 3 deletions docs/website/src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { MetadataRoute } from 'next';
import { source } from '@/lib/source';
import { allowDocsIndexingAtBuildTime } from '@/lib/docs-indexing';
import {
DOCS_SITE_ORIGIN,
buildCanonicalDocsUrl,
isArchivedVersionSlug,
} from '@/lib/docs-open-graph';
Expand All @@ -15,8 +16,11 @@ export const dynamic = 'force-static';
*
* Indexing policy — mirrors `robots.ts`:
* - Production (`DOCS_ALLOW_INDEXING=true`): emit one entry per latest page.
* - Preview / local / PR builds (default): emit an empty sitemap so non-canonical
* deploys don't advertise any URLs even if the file is fetched directly.
* - Preview / local / PR builds (default): emit a semantically-empty sitemap
* (two duplicate entries for the canonical site root) so non-canonical
* deploys don't advertise any internal URL even if the file is fetched
* directly. See the in-function comment for why two entries (and not zero
* or one) are required.
*
* Non-canonical bundles (`dev` preview + `vX.Y.Z` back-versions) are excluded
* entirely. Those pages still render so the in-page version selector keeps
Expand All @@ -29,7 +33,25 @@ export const dynamic = 'force-static';
* ignored, so they would only add noise.
*/
export default function sitemap(): MetadataRoute.Sitemap {
if (!allowDocsIndexingAtBuildTime()) return [];
if (!allowDocsIndexingAtBuildTime()) {
// Non-canonical deploys (preview / PR / staging): we don't want to
// advertise any internal URL, but the post-build link checker
// (`@vahor/next-broken-links`, invoked from `package.json`) parses
// `out/sitemap.xml` with fast-xml-parser default settings and crashes
// when `<urlset>` has zero `<url>` children — `urlset.url` is
// `undefined`, and its `for (... of urlset.url)` then throws
// `TypeError: x.urlset.url is not iterable`.
//
// Emitting two duplicate entries for the canonical site root is
// semantically equivalent to "empty" for crawlers (the homepage is
// implicit by visiting the deploy at all, and identical entries are
// deduplicated) while forcing fast-xml-parser to materialize
// `urlset.url` as an array — it only coerces to an array when there
// are 2+ children; a single child becomes an object, which is also
// not iterable. Verified empirically against fast-xml-parser 5.5.9.
const root = `${DOCS_SITE_ORIGIN}/`;
return [{ url: root }, { url: root }];
}

return source
.getPages()
Expand Down
6 changes: 6 additions & 0 deletions docs/website/src/lib/custom-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ export const customTree: Node[] = [
type: 'page',
icon: resolveIcon('Stethoscope'),
},
{
name: 'Troubleshooting',
url: '/troubleshooting',
type: 'page',
icon: resolveIcon('Bug'),
},
{
name: 'HTTP server',
url: '/http-server',
Expand Down
Loading