Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
# OTel instruments
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module owns the OpenTelemetry instrument bundle emitted by the
`vm.Context` sandbox host. Instruments are bound lazily against the
current global `MeterProvider` so packages downstream may install a
real exporter (Prometheus, OTLP, in-memory test reader) and observe
the bundle without restarting the process. The bundle is cached after
first build so the hot proxy path never reaches the meter registry
twice.
## Features
- Four named instruments: a boot histogram, two refusal counters
(`eval_rejected_total`, `module_import_rejected_total`), and the
shared `plugin.permission_denied_total` counter whose name matches
`api-sandbox-permissions` so dashboards aggregate cleanly.
- Lazy binding via `getSandboxVmInstruments()` so tests may install a
fresh `MeterProvider` and then call `resetSandboxVmInstruments()` to
drop the cache.
- All metric names are namespaced under `sandbox_vm.*` (except the
cross-package denial counter), making them easy to filter at the
collector.
## Usage: Basic
```ts
import { getSandboxVmInstruments } from "@suaveplan/api-sandbox-vm/otel/instruments";
const instruments = getSandboxVmInstruments();
instruments.evalRejectedTotal.add(1, { kind: "direct" });
```
## Usage: Advanced
Install a real in-memory provider for assertions:
```ts
import {
AggregationTemporality,
InMemoryMetricExporter,
MeterProvider,
PeriodicExportingMetricReader,
} from "@opentelemetry/sdk-metrics";
import { metrics } from "@opentelemetry/api";
import {
getSandboxVmInstruments,
resetSandboxVmInstruments,
} from "@suaveplan/api-sandbox-vm/otel/instruments";
const exporter = new InMemoryMetricExporter(AggregationTemporality.DELTA);
const reader = new PeriodicExportingMetricReader({
exporter,
exportIntervalMillis: 1_000,
});
const provider = new MeterProvider({ readers: [reader] });
metrics.setGlobalMeterProvider(provider);
resetSandboxVmInstruments();
const instruments = getSandboxVmInstruments();
instruments.permissionDeniedTotal.add(1, {
plugin: "demo",
capability: "fetch",
});
await reader.forceFlush();
const collected = exporter.getMetrics();
```
## API Reference
- `getSandboxVmInstruments(): SandboxVmInstruments` — return the
lazily-built instrument bundle. Calling multiple times returns the
same frozen reference until `resetSandboxVmInstruments()` is invoked.
- `resetSandboxVmInstruments(): void` — drop the cache; the next
`getSandboxVmInstruments()` call re-binds against the (possibly new)
global `MeterProvider`.
- `interface SandboxVmInstruments` — fully-typed instrument bundle.
## Implementation Notes
The module never reads any environment variable at import time and
never side-effects the global `MeterProvider`. Caching uses a
module-private `let` rather than a `WeakMap` because the lifecycle of
the bundle is naturally process-scoped (there is no second
`MeterProvider` instance to dispatch to unless the consumer resets the
cache deliberately). The `permission_denied_total` counter
intentionally uses the same name as the one in
`api-sandbox-permissions`; both packages contribute to the same OTLP
series so the consumer sees one denial total regardless of whether the
decision was made in this package's default checker or in the richer
implementation.