vde-open 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -6
- package/dist/cli.js +11 -16
- package/dist/daemon.js +2 -2
- package/dist/{html-static-BDV6MgA7.js → html-static-C_wwQAJx.js} +67 -0
- package/dist/{main-DwpMMOjm.js → main-BH6i8EXC.js} +92 -176
- package/dist/{print-Cfa1Ytrj.js → print-vae7mHCU.js} +1 -1
- package/dist/{render-BX3arVZj.js → render-BJa4uW0H.js} +1 -1
- package/dist/{search-index-B7DqaWh6.js → search-index-BoGly_y4.js} +12 -14
- package/dist/web/assets/index-CVYtIVot.js +163 -0
- package/dist/web/assets/index-_RRuuJtK.css +2 -0
- package/dist/web/index.html +2 -2
- package/dist/workers/parse-worker.js +3 -3
- package/dist/workers/search-worker.js +1 -1
- package/docs/agent-usage.md +1 -0
- package/package.json +3 -2
- package/skills/vde-open/SKILL.md +5 -3
- package/dist/web/assets/index-Cnw68UWf.css +0 -2
- package/dist/web/assets/index-DIyamSNh.js +0 -163
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[日本語](README.ja.md)
|
|
4
4
|
|
|
5
|
-
A local document viewer for agents and people who work from the same material. Open Markdown and
|
|
5
|
+
A local document viewer for agents and people who work from the same material. Open Markdown, HTML, and image files, read them in a management UI in the browser, and let an agent search and read the same documents from the CLI. An agent can also ask a person questions, and the person submits the answers from the management UI.
|
|
6
6
|
|
|
7
7
|
- Agents can search and read only the documents you opened.
|
|
8
8
|
- When you save a document, the management UI updates automatically.
|
|
@@ -28,7 +28,7 @@ To install from a clone of this repository (Node.js 24.21.0 is pinned in `mise.t
|
|
|
28
28
|
pnpm install --frozen-lockfile
|
|
29
29
|
pnpm build
|
|
30
30
|
pnpm test:pack # builds artifacts/vde-open-<version>.tgz and verifies an install in a separate directory
|
|
31
|
-
bun add -g "$PWD/artifacts/vde-open-0.1.
|
|
31
|
+
bun add -g "$PWD/artifacts/vde-open-0.1.11.tgz" # bun add -g needs an absolute path
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## `vde-open` and `vo`
|
|
@@ -45,7 +45,7 @@ Installing never overwrites or removes an existing `vo` (another tool's command,
|
|
|
45
45
|
```bash
|
|
46
46
|
vo open README.md docs/design.md # open documents (starts the daemon if needed)
|
|
47
47
|
vo open docs -w # open a directory and follow new documents
|
|
48
|
-
vo ui # open the management UI (
|
|
48
|
+
vo ui # open the management UI (no authentication)
|
|
49
49
|
vo list --json # list open documents
|
|
50
50
|
vo search "authentication design" --json # search open documents
|
|
51
51
|
vo read <documentId> --section sec_0003 --json # read a section
|
|
@@ -53,6 +53,8 @@ vo close docs/design.md # remove from the list (the file is not
|
|
|
53
53
|
vo daemon stop # stop the daemon
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
The management UI does not require authentication. The URL printed by `vo ui --print-url` can be copied to another browser or tab on the same machine while the daemon is running. URLs that select a document work directly too. Both listeners bind to `127.0.0.1`; viewing from another machine is not supported.
|
|
57
|
+
|
|
56
58
|
For how agents search, read, and ask questions, see [docs/agent-usage.md](docs/agent-usage.md).
|
|
57
59
|
|
|
58
60
|
## Agent skill
|
|
@@ -95,6 +97,20 @@ Markdown is rendered with TanStack Markdown 1.0.0. It is not fully compatible wi
|
|
|
95
97
|
- Code is highlighted only for JS, JSX, TS, TSX, JSON, YAML, HTML, CSS, Bash, and Markdown. Code larger than 256 KiB and other languages are not highlighted.
|
|
96
98
|
- Documents that cannot be parsed within 2 seconds, or that have more than 100,000 elements or more than 64 levels of nesting, are shown as source.
|
|
97
99
|
|
|
100
|
+
## Image files
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
vo diagram.png # open an image directly
|
|
104
|
+
vo open photo.jpg animation.gif --focus # open images and switch the view
|
|
105
|
+
vo open images -w # also open images added later
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Recognized extensions include PNG/APNG, JPEG (`jpg`, `jpeg`, `jpe`, `jif`, `jfif`, `pjpeg`, `pjp`), GIF, WebP, AVIF, SVG, BMP, ICO/CUR, JPEG XL, TIFF, and HEIC/HEIF. Images initially fit the view; "Actual size" shows the original dimensions with scrolling. Saving the file updates the view. Pausing updates keeps the displayed revision. You can open the same image's management UI URL in another browser on the same machine.
|
|
109
|
+
|
|
110
|
+
The browser decodes the original file without conversion. Supported formats depend on the browser and OS. Unsupported or damaged images show an error. SVG is displayed as an image; scripts and external references cannot run.
|
|
111
|
+
|
|
112
|
+
Images are searchable by title and path (`vo search diagram --mode path`). Text extraction, `vo read`, and PDF export are for Markdown and HTML; images have no OCR. The existing 10 MiB per-file limit also applies to images.
|
|
113
|
+
|
|
98
114
|
## Exporting to PDF
|
|
99
115
|
|
|
100
116
|
"Export PDF" in the header of a document saves the shown revision as a PDF, without a print dialog.
|
|
@@ -131,7 +147,7 @@ The person answers in the answer panel of the management UI. The answers are sub
|
|
|
131
147
|
| Symptom | What to do |
|
|
132
148
|
|---|---|
|
|
133
149
|
| `vo` runs a different command | Use `vde-open`, or check the order of `PATH` |
|
|
134
|
-
|
|
|
150
|
+
| An earlier URL stops working after the daemon restarts | Open the current URL with `vo ui` (the port may change on restart) |
|
|
135
151
|
| Exit code 8 (cannot connect to or start the daemon) | Check with `vo daemon status`, and look for leftover files with `vo doctor` |
|
|
136
152
|
| Images or CSS are not shown | Open "Differences from the original document" and register them with `--assets-root` or `--asset` |
|
|
137
153
|
| Search does not find a document | Check with `vo list --json` that the document is open and its `searchState` is `ready` |
|
|
@@ -143,7 +159,7 @@ The person answers in the answer panel of the management UI. The answers are sub
|
|
|
143
159
|
|---|---|
|
|
144
160
|
| Linux and macOS on CI (GitHub Actions `ubuntu-latest` and `macos-latest`, Node.js 24.21.0) | Verified (format, lint, typecheck, unit/integration, build, pack, e2e; `.github/workflows/ci.yml`) |
|
|
145
161
|
| Windows on CI (`windows-latest`, Node.js 24.21.0) | Verified: build, pack smoke (install, both bins, IPC, starting and stopping the daemon, JSON output, the UI and workers), and the daemon and document integration tests. The other unit and integration tests and the e2e tests are not run on Windows |
|
|
146
|
-
| Browsers | Chromium (Playwright's Chrome Headless Shell): the full suite is verified. Firefox and WebKit (Playwright 1.63.0): the view isolation, CSP, HTML bridge, and
|
|
162
|
+
| Browsers | Chromium (Playwright's Chrome Headless Shell): the full suite is verified. Firefox and WebKit (Playwright 1.63.0): the view isolation, CSP, HTML bridge, and direct URL tests (`pnpm test:e2e:cross`) are verified. Other UI interactions in Firefox and WebKit (search, answer panel, narrow screens, a list of 1,000 documents) are not verified |
|
|
147
163
|
| PDF export | macOS (development machine): verified with Google Chrome 154 and Microsoft Edge 154. Linux on CI: verified with the runner's Google Chrome (e2e). Windows: printing with a real browser is not verified (the pack smoke test checks rendering the print document) |
|
|
148
164
|
|
|
149
165
|
More details: [docs/performance.md](docs/performance.md) (measurements), [docs/architecture.md](docs/architecture.md) and [docs/security-model.md](docs/security-model.md) (design). Development records (in Japanese): [docs/implementation-status.md](docs/implementation-status.md), [docs/dependency-validation.md](docs/dependency-validation.md), and [docs/adr/](docs/adr/).
|
|
@@ -162,7 +178,7 @@ cd ../..
|
|
|
162
178
|
pnpm build:watch
|
|
163
179
|
```
|
|
164
180
|
|
|
165
|
-
`build:watch` rebuilds when the sources, the build configuration, or the packaged files change; a failed build keeps the last successful output. The next linked CLI invocation uses the new build, but the watcher does not restart your daemon: run `vo daemon restart`, then `vo ui`. Restarting keeps registered documents and saved answers, but changes the UI address and invalidates earlier
|
|
181
|
+
`build:watch` rebuilds when the sources, the build configuration, or the packaged files change; a failed build keeps the last successful output. The next linked CLI invocation uses the new build, but the watcher does not restart your daemon: run `vo daemon restart`, then `vo ui`. Restarting keeps registered documents and saved answers, but changes the UI address and invalidates earlier render grants and interactive HTML permissions.
|
|
166
182
|
|
|
167
183
|
For frequent UI changes, use `pnpm dev` instead. It runs the daemon from source with a separate `.dev-home` and serves the UI with Vite HMR. It does not rebuild the linked CLI or restart the backend when its source changes. To run CLI commands against it, set `VDE_OPEN_HOME` to the absolute path of `.dev-home` (for example, `VDE_OPEN_HOME="$PWD/.dev-home" vo list` from the repository root).
|
|
168
184
|
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as decodeStateFile, D as daemonEntryPath, E as resolveStateRoot, O as referencedBlobs, S as renameWithRetry, T as resolveRuntimeLocation, a as DAEMON_LOCK_NAME, b as proofMatches, c as readIpcKey, d as inspectOwner, f as readCurrentLock, g as encodeFrame, h as FrameDecoder, i as requirePrivateDirectoryIfExists, k as version, l as readPointer, m as systemProcessProbe, n as ensurePrivateDirectory, o as POINTER_FILE, p as releaseLock, r as inspectPrivateDirectory, s as START_LOCK_NAME, t as startDaemon, u as acquireLock, v as computeProof, w as currentPathEnvironment, x as removeWithRetry, y as createNonce } from "./main-
|
|
3
|
-
import { A as successEnvelope, C as VdeError, D as ExitCode, E as isVdeError, O as envelopeSchema, T as isErrorCode, Y as LIMITS, k as errorEnvelope, w as exitCodeForError } from "./search-index-
|
|
2
|
+
import { C as decodeStateFile, D as daemonEntryPath, E as resolveStateRoot, O as referencedBlobs, S as renameWithRetry, T as resolveRuntimeLocation, a as DAEMON_LOCK_NAME, b as proofMatches, c as readIpcKey, d as inspectOwner, f as readCurrentLock, g as encodeFrame, h as FrameDecoder, i as requirePrivateDirectoryIfExists, k as version, l as readPointer, m as systemProcessProbe, n as ensurePrivateDirectory, o as POINTER_FILE, p as releaseLock, r as inspectPrivateDirectory, s as START_LOCK_NAME, t as startDaemon, u as acquireLock, v as computeProof, w as currentPathEnvironment, x as removeWithRetry, y as createNonce } from "./main-BH6i8EXC.js";
|
|
3
|
+
import { A as successEnvelope, C as VdeError, D as ExitCode, E as isVdeError, O as envelopeSchema, T as isErrorCode, Y as LIMITS, k as errorEnvelope, w as exitCodeForError } from "./search-index-BoGly_y4.js";
|
|
4
4
|
import fs, { fstatSync } from "node:fs";
|
|
5
5
|
import { lstat, readFile, readdir, stat as stat$1, writeFile } from "node:fs/promises";
|
|
6
6
|
import path, { join, resolve } from "node:path";
|
|
@@ -3815,23 +3815,22 @@ async function runCli(rawArgv, context) {
|
|
|
3815
3815
|
}
|
|
3816
3816
|
};
|
|
3817
3817
|
const openBrowser = async (connection) => {
|
|
3818
|
-
const { data } = unwrap(await connection.request("
|
|
3819
|
-
if (await browser.open(data.
|
|
3818
|
+
const { data } = unwrap(await connection.request("daemon.status", {}));
|
|
3819
|
+
if (await browser.open(data.uiUrl ?? "")) return [];
|
|
3820
3820
|
return [{
|
|
3821
3821
|
code: "W_BROWSER_OPEN_FAILED",
|
|
3822
3822
|
message: "The browser could not be opened. Open the URL shown by `vde-open ui --print-url` in your browser.",
|
|
3823
3823
|
details: { uiUrl: data.uiUrl }
|
|
3824
3824
|
}];
|
|
3825
3825
|
};
|
|
3826
|
-
const showUi = async (printUrl) => {
|
|
3826
|
+
const showUi = async (printUrl, json = false) => {
|
|
3827
3827
|
const connection = await control.ensure();
|
|
3828
3828
|
try {
|
|
3829
3829
|
if (printUrl) {
|
|
3830
|
-
const { data } = unwrap(await connection.request("
|
|
3831
|
-
context.
|
|
3832
|
-
context.stdout(`${data.bootstrapUrl}\n`);
|
|
3830
|
+
const { data } = unwrap(await connection.request("daemon.status", {}));
|
|
3831
|
+
if (!json) context.stdout(`${data.uiUrl ?? ""}\n`);
|
|
3833
3832
|
return { data: {
|
|
3834
|
-
uiUrl: data.uiUrl,
|
|
3833
|
+
uiUrl: data.uiUrl ?? "",
|
|
3835
3834
|
opened: false
|
|
3836
3835
|
} };
|
|
3837
3836
|
}
|
|
@@ -3849,7 +3848,7 @@ async function runCli(rawArgv, context) {
|
|
|
3849
3848
|
}
|
|
3850
3849
|
};
|
|
3851
3850
|
const program = new Command();
|
|
3852
|
-
program.name(PROGRAM_NAME).description("Local CLI that shows
|
|
3851
|
+
program.name(PROGRAM_NAME).description("Local CLI that shows Markdown, HTML, and images in the browser and lets agents search documents and read text").version(CLI_VERSION, "-V, --version", "Show the version").helpOption("-h, --help", "Show help").addHelpText("after", "\n`vo` is the same command as `vde-open`. Passing a file directly is treated as `open` (for example: vo a.md).\nRunning with no arguments opens the management UI in the browser.").exitOverride().configureOutput({
|
|
3853
3852
|
writeOut: context.stdout,
|
|
3854
3853
|
writeErr: context.stderr
|
|
3855
3854
|
}).action(async () => {
|
|
@@ -4051,12 +4050,8 @@ async function runCli(rawArgv, context) {
|
|
|
4051
4050
|
watchCommand.command("remove").description("Remove a watch rule. Open documents stay open").argument("<watchId>", "Watch rule ID").option("--json", "Output the result as JSON", false).action(async (watchId, options) => {
|
|
4052
4051
|
await execute("watch.remove", options.json, () => viaDaemon("watch.remove", { watchId }), renderRules);
|
|
4053
4052
|
});
|
|
4054
|
-
program.command("ui").description("Open the management UI in the browser").option("--print-url", "Print
|
|
4055
|
-
|
|
4056
|
-
fail(new VdeError("E_INVALID_ARGUMENT", "--print-url cannot be combined with --json because its output contains a secret."), true);
|
|
4057
|
-
return;
|
|
4058
|
-
}
|
|
4059
|
-
await execute("ui", options.json, () => showUi(options.printUrl), () => "");
|
|
4053
|
+
program.command("ui").description("Open the management UI in the browser").option("--print-url", "Print the UI URL instead of opening the browser", false).option("--json", "Output the result as JSON", false).action(async (options) => {
|
|
4054
|
+
await execute("ui", options.json, () => showUi(options.printUrl, options.json), () => "");
|
|
4060
4055
|
});
|
|
4061
4056
|
const renderStatus = (status) => status.state === "running" ? `running pid=${String(status.pid)} open documents: ${String(status.openDocuments)} ${status.uiUrl ?? ""}` : "stopped";
|
|
4062
4057
|
const daemon = program.command("daemon").description("Start, inspect, and stop the daemon");
|
package/dist/daemon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { k as version, t as startDaemon, w as currentPathEnvironment } from "./main-
|
|
2
|
-
import { E as isVdeError } from "./search-index-
|
|
1
|
+
import { k as version, t as startDaemon, w as currentPathEnvironment } from "./main-BH6i8EXC.js";
|
|
2
|
+
import { E as isVdeError } from "./search-index-BoGly_y4.js";
|
|
3
3
|
//#region src/daemon.ts
|
|
4
4
|
function notifyParent(message) {
|
|
5
5
|
if (!process.send) return;
|
|
@@ -8090,6 +8090,10 @@ const ASSET_TYPES = {
|
|
|
8090
8090
|
mime: "image/png",
|
|
8091
8091
|
role: "image"
|
|
8092
8092
|
},
|
|
8093
|
+
apng: {
|
|
8094
|
+
mime: "image/apng",
|
|
8095
|
+
role: "image"
|
|
8096
|
+
},
|
|
8093
8097
|
jpg: {
|
|
8094
8098
|
mime: "image/jpeg",
|
|
8095
8099
|
role: "image"
|
|
@@ -8098,6 +8102,26 @@ const ASSET_TYPES = {
|
|
|
8098
8102
|
mime: "image/jpeg",
|
|
8099
8103
|
role: "image"
|
|
8100
8104
|
},
|
|
8105
|
+
jpe: {
|
|
8106
|
+
mime: "image/jpeg",
|
|
8107
|
+
role: "image"
|
|
8108
|
+
},
|
|
8109
|
+
jif: {
|
|
8110
|
+
mime: "image/jpeg",
|
|
8111
|
+
role: "image"
|
|
8112
|
+
},
|
|
8113
|
+
jfif: {
|
|
8114
|
+
mime: "image/jpeg",
|
|
8115
|
+
role: "image"
|
|
8116
|
+
},
|
|
8117
|
+
pjpeg: {
|
|
8118
|
+
mime: "image/jpeg",
|
|
8119
|
+
role: "image"
|
|
8120
|
+
},
|
|
8121
|
+
pjp: {
|
|
8122
|
+
mime: "image/jpeg",
|
|
8123
|
+
role: "image"
|
|
8124
|
+
},
|
|
8101
8125
|
webp: {
|
|
8102
8126
|
mime: "image/webp",
|
|
8103
8127
|
role: "image"
|
|
@@ -8114,6 +8138,38 @@ const ASSET_TYPES = {
|
|
|
8114
8138
|
mime: "image/svg+xml",
|
|
8115
8139
|
role: "svg"
|
|
8116
8140
|
},
|
|
8141
|
+
bmp: {
|
|
8142
|
+
mime: "image/bmp",
|
|
8143
|
+
role: "image"
|
|
8144
|
+
},
|
|
8145
|
+
ico: {
|
|
8146
|
+
mime: "image/x-icon",
|
|
8147
|
+
role: "image"
|
|
8148
|
+
},
|
|
8149
|
+
cur: {
|
|
8150
|
+
mime: "image/x-icon",
|
|
8151
|
+
role: "image"
|
|
8152
|
+
},
|
|
8153
|
+
jxl: {
|
|
8154
|
+
mime: "image/jxl",
|
|
8155
|
+
role: "image"
|
|
8156
|
+
},
|
|
8157
|
+
tif: {
|
|
8158
|
+
mime: "image/tiff",
|
|
8159
|
+
role: "image"
|
|
8160
|
+
},
|
|
8161
|
+
tiff: {
|
|
8162
|
+
mime: "image/tiff",
|
|
8163
|
+
role: "image"
|
|
8164
|
+
},
|
|
8165
|
+
heic: {
|
|
8166
|
+
mime: "image/heic",
|
|
8167
|
+
role: "image"
|
|
8168
|
+
},
|
|
8169
|
+
heif: {
|
|
8170
|
+
mime: "image/heif",
|
|
8171
|
+
role: "image"
|
|
8172
|
+
},
|
|
8117
8173
|
css: {
|
|
8118
8174
|
mime: "text/css; charset=utf-8",
|
|
8119
8175
|
role: "style"
|
|
@@ -8682,6 +8738,17 @@ function analyzeHtml(source) {
|
|
|
8682
8738
|
};
|
|
8683
8739
|
}
|
|
8684
8740
|
function analyzeDocument(source, format) {
|
|
8741
|
+
if (format === "image") return {
|
|
8742
|
+
title: null,
|
|
8743
|
+
outline: [],
|
|
8744
|
+
sections: [{
|
|
8745
|
+
sectionId: "sec_0000",
|
|
8746
|
+
level: 0,
|
|
8747
|
+
title: "",
|
|
8748
|
+
headingPath: [],
|
|
8749
|
+
text: ""
|
|
8750
|
+
}]
|
|
8751
|
+
};
|
|
8685
8752
|
return format === "markdown" ? analyzeMarkdown(source) : analyzeHtml(source);
|
|
8686
8753
|
}
|
|
8687
8754
|
//#endregion
|