webveil 0.1.1 → 0.2.1

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 CHANGED
@@ -49,7 +49,7 @@ Then `webveil search "…"` / `web_fetch` work with no config.
49
49
  > export WEBVEIL_BASE_URL=http://127.0.0.1:8888 # or wherever your instance listens
50
50
  > ```
51
51
  >
52
- > or set `baseUrl` in `.pi/webveil.json` (see config seam below).
52
+ > or set `baseUrl` in `webveil.json` (see config seam below).
53
53
 
54
54
  ### Other SearXNG install options
55
55
 
@@ -170,8 +170,11 @@ backends and for `web_fetch`. See
170
170
  webveil on `socks5` does NOT route your `git push` through the proxy. See
171
171
  [Anonymous egress](#anonymous-egress-mullvad--tor) and
172
172
  [`work/notes/findings/mullvad-socks5-egress-mechanics.md`](work/notes/findings/mullvad-socks5-egress-mechanics.md).
173
- - **config seam**, per-folder resolution: env > nearest `.pi/webveil.json` walking up from
174
- cwd > global `~/.pi/agent/webveil.json` > defaults. Per folder = per account/egress.
173
+ - **config seam**, per-folder resolution: env > nearest `webveil.json` walking up from
174
+ cwd > global `$XDG_CONFIG_HOME/webveil/config.json` (default
175
+ `~/.config/webveil/config.json`) > defaults. Per folder = per account/egress. The
176
+ project file is a frontend-neutral `webveil.json` read identically by the CLI and the
177
+ pi extension. See [`docs/adr/0002`](docs/adr/0002-config-file-location-neutral-webveil-json.md).
175
178
  - **extractor seam**, `urlToMarkdown` via `distilly/fetch` by default, injected with
176
179
  webveil's egress-bound `fetch`; a backend's own `/extract` (Tavily-compat) may override
177
180
  it. Owns the context-friendly markdown + size presets (`s`/`m`/`l`/`f`). See
@@ -193,7 +196,7 @@ export WEBVEIL_EGRESS_URL=socks5://10.64.0.1:1080 # Mullvad
193
196
  # or socks5://127.0.0.1:9050 # Tor
194
197
  ```
195
198
 
196
- or per folder in `.pi/webveil.json`:
199
+ or per folder in `webveil.json`:
197
200
 
198
201
  ```json
199
202
  { "egress": { "mode": "socks5", "url": "socks5://10.64.0.1:1080" } }
@@ -287,7 +290,7 @@ a promise); `LOC` is the actual line count of the built file.
287
290
  | src/cli.ts (incur frontend) | 106 | ~80 |
288
291
  | src/core/search.ts | 104 | ~90 |
289
292
  | src/core/fetch.ts | 132 | ~90 |
290
- | src/core/config.ts | 106 | ~80 |
293
+ | src/core/config.ts | 128 | ~80 |
291
294
  | src/core/egress.ts | 106 | ~70 |
292
295
  | src/core/http.ts | 62 | ~60 |
293
296
  | src/core/extract.ts | 82 | ~60 |
@@ -297,7 +300,7 @@ a promise); `LOC` is the actual line count of the built file.
297
300
  | src/core/backends/searxng.ts | 70 | ~90 |
298
301
  | src/core/backends/tavily-compat.ts | 156 | ~90 |
299
302
  | src/core/backends/custom.ts | 159 | ~70 |
300
- | **subtotal** | 1408 | |
303
+ | **subtotal** | 1430 | |
301
304
 
302
305
  ### `packages/pi-webveil` (pi extension frontend)
303
306
 
@@ -305,7 +308,7 @@ a promise); `LOC` is the actual line count of the built file.
305
308
  | ------------ | --: | -----: |
306
309
  | src/index.ts | 168 | ~90 |
307
310
 
308
- **Total own source: 1576 LOC** (excluding deps).
311
+ **Total own source: 1598 LOC** (excluding deps).
309
312
 
310
313
  > Reality vs. target: several modules currently exceed their `CONTEXT.md` ceilings (notably
311
314
  > `tavily-compat.ts`, `custom.ts`, `pi-webveil/src/index.ts`), and two built modules
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAmBA,OAAO,EAAC,GAAG,EAAI,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAC,MAAM,IAAI,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAC,KAAK,IAAI,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACvB,MAAM,CAAC,EAAE,OAAO,UAAU,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,SAAS,CAAC;CACzB;AAKD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,GAAE,OAAY;;;;;;;;;;;;;;;;;;oCA4C3C;AAKD,QAAA,MAAM,GAAG;;;;;;;;;;;;;;;;;;mCAAc,CAAC;AAexB,eAAe,GAAG,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAoBA,OAAO,EAAC,GAAG,EAAI,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAC,MAAM,IAAI,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAC,KAAK,IAAI,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACvB,MAAM,CAAC,EAAE,OAAO,UAAU,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,SAAS,CAAC;CACzB;AAKD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,GAAE,OAAY;;;;;;;;;;;;;;;;;;oCA4C3C;AAKD,QAAA,MAAM,GAAG;;;;;;;;;;;;;;;;;;mCAAc,CAAC;AAuBxB,eAAe,GAAG,CAAC"}
package/dist/cli.js CHANGED
@@ -14,6 +14,7 @@
14
14
  // a test wires fakes and asserts the commands call the core (via `cli.serve`
15
15
  // with custom argv/stdout) WITHOUT touching the network. The bottom of the file
16
16
  // builds the real CLI and serves it when run as the bin.
17
+ import { realpathSync } from 'node:fs';
17
18
  import { argv } from 'node:process';
18
19
  import { fileURLToPath } from 'node:url';
19
20
  import { Cli, z } from 'incur';
@@ -73,13 +74,21 @@ export function createCli(deps = {}) {
73
74
  // CTAs). Serving is GUARDED to the bin entry below, so importing this module in
74
75
  // a test never consumes `process.argv` or exits the process.
75
76
  const cli = createCli();
76
- /** True when this module is the process entry (the `webveil` bin), not imported. */
77
+ /**
78
+ * True when this module is the process entry (the `webveil` bin), not imported.
79
+ * `argv[1]` is the launched path, which for an npm-installed bin is the
80
+ * `node_modules/.bin/webveil` SYMLINK, while `import.meta.url` resolves to the
81
+ * real `dist/cli.js`. Comparing them raw makes the guard false for every
82
+ * installed invocation (the CLI silently never serves). So resolve symlinks on
83
+ * BOTH sides (`realpathSync`) before comparing.
84
+ */
77
85
  function isMain() {
78
86
  const entry = argv[1];
79
87
  if (!entry)
80
88
  return false;
81
89
  try {
82
- return fileURLToPath(import.meta.url) === entry;
90
+ const self = fileURLToPath(import.meta.url);
91
+ return realpathSync(self) === realpathSync(entry);
83
92
  }
84
93
  catch {
85
94
  return false;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -25,9 +25,14 @@ export interface ResolveOptions {
25
25
  cwd?: string;
26
26
  /** Environment to read overrides from. Defaults to process.env. */
27
27
  env?: Record<string, string | undefined>;
28
+ /** Home directory for the XDG fallback. Defaults to os.homedir(). */
29
+ homeDir?: string;
28
30
  /**
29
- * Path to the global config file. Defaults to ~/.pi/agent/webveil.json.
30
- * Tests point this at a temp dir to isolate the real home directory.
31
+ * Path to the global config file. When given it WINS outright and the XDG
32
+ * resolution is skipped. Tests point this at a temp dir to isolate the real
33
+ * home directory. When absent, the global file resolves to
34
+ * $XDG_CONFIG_HOME/webveil/config.json, falling back to
35
+ * <homeDir>/.config/webveil/config.json.
31
36
  */
32
37
  globalPath?: string;
33
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAUA,2DAA2D;AAC3D,MAAM,MAAM,MAAM,GACf;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GAChB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GAC3B;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,CAAC;AAEjC,sEAAsE;AACtE,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE9C,+DAA+D;AAC/D,MAAM,WAAW,MAAM;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;CACrB;AAED,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC9B,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA+CD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,CAalE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAcA,2DAA2D;AAC3D,MAAM,MAAM,MAAM,GACf;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GAChB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GAC3B;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,CAAC;AAEjC,sEAAsE;AACtE,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE9C,+DAA+D;AAC/D,MAAM,WAAW,MAAM;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;CACrB;AAED,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC9B,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA4DD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,CAalE"}
@@ -1,8 +1,12 @@
1
1
  // config seam — per-folder resolution. Precedence (highest wins):
2
- // env > nearest .pi/webveil.json (walking up from cwd) > global
3
- // ~/.pi/agent/webveil.json > defaults.
2
+ // env > nearest webveil.json (walking up from cwd) > global
3
+ // $XDG_CONFIG_HOME/webveil/config.json (~/.config/webveil/config.json) >
4
+ // defaults.
4
5
  // "Per folder = per account/egress." Each layer is a partial; later (lower)
5
- // layers fill gaps the higher layers leave.
6
+ // layers fill gaps the higher layers leave. The project file is a
7
+ // frontend-neutral `webveil.json` (no `.pi/`): both the pi-agnostic CLI and the
8
+ // pi extension resolve the same name, so a project is configured the same way
9
+ // regardless of which frontend reads it. See docs/adr/0002.
6
10
  import { readFileSync } from 'node:fs';
7
11
  import { homedir } from 'node:os';
8
12
  import { dirname, join, parse } from 'node:path';
@@ -12,7 +16,7 @@ const DEFAULTS = {
12
16
  egress: { mode: 'direct' },
13
17
  fetchSize: 'm',
14
18
  };
15
- const PROJECT_FILE = join('.pi', 'webveil.json');
19
+ const PROJECT_FILE = 'webveil.json';
16
20
  function readJson(path) {
17
21
  let text;
18
22
  try {
@@ -23,7 +27,7 @@ function readJson(path) {
23
27
  }
24
28
  return JSON.parse(text);
25
29
  }
26
- /** The nearest `.pi/webveil.json` walking up from `cwd` (first found wins). */
30
+ /** The nearest `webveil.json` walking up from `cwd` (first found wins). */
27
31
  function readProjectChain(cwd) {
28
32
  let dir = cwd;
29
33
  const { root } = parse(dir);
@@ -53,6 +57,15 @@ function readEnv(env) {
53
57
  layer.egress = { mode, url: env.WEBVEIL_EGRESS_URL ?? '' };
54
58
  return layer;
55
59
  }
60
+ /**
61
+ * The global config path, XDG-style: `$XDG_CONFIG_HOME/webveil/config.json`,
62
+ * falling back to `<homeDir>/.config/webveil/config.json` when XDG_CONFIG_HOME
63
+ * is unset. (`options.globalPath`, when given, bypasses this entirely.)
64
+ */
65
+ function resolveGlobalPath(env, homeDir = homedir()) {
66
+ const base = env.XDG_CONFIG_HOME || join(homeDir, '.config');
67
+ return join(base, 'webveil', 'config.json');
68
+ }
56
69
  /**
57
70
  * Resolve the effective config. Higher-precedence layers override lower ones,
58
71
  * key by key: env > project chain > global file > defaults.
@@ -60,7 +73,7 @@ function readEnv(env) {
60
73
  export function resolveConfig(options = {}) {
61
74
  const cwd = options.cwd ?? process.cwd();
62
75
  const env = options.env ?? process.env;
63
- const globalPath = options.globalPath ?? join(homedir(), '.pi', 'agent', 'webveil.json');
76
+ const globalPath = options.globalPath ?? resolveGlobalPath(env, options.homeDir);
64
77
  const layers = [
65
78
  DEFAULTS,
66
79
  readJson(globalPath) ?? {},
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webveil",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Anonymous-capable, self-hosted, account-free web search and fetch for agents. CLI + MCP (built on incur), pi-agnostic. Swappable backend and egress (direct, http proxy, socks5/Tor).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "keywords": [
package/src/cli.ts CHANGED
@@ -15,6 +15,7 @@
15
15
  // with custom argv/stdout) WITHOUT touching the network. The bottom of the file
16
16
  // builds the real CLI and serves it when run as the bin.
17
17
 
18
+ import {realpathSync} from 'node:fs';
18
19
  import {argv} from 'node:process';
19
20
  import {fileURLToPath} from 'node:url';
20
21
  import {Cli, z} from 'incur';
@@ -90,12 +91,20 @@ export function createCli(deps: CliDeps = {}) {
90
91
  // a test never consumes `process.argv` or exits the process.
91
92
  const cli = createCli();
92
93
 
93
- /** True when this module is the process entry (the `webveil` bin), not imported. */
94
+ /**
95
+ * True when this module is the process entry (the `webveil` bin), not imported.
96
+ * `argv[1]` is the launched path, which for an npm-installed bin is the
97
+ * `node_modules/.bin/webveil` SYMLINK, while `import.meta.url` resolves to the
98
+ * real `dist/cli.js`. Comparing them raw makes the guard false for every
99
+ * installed invocation (the CLI silently never serves). So resolve symlinks on
100
+ * BOTH sides (`realpathSync`) before comparing.
101
+ */
94
102
  function isMain(): boolean {
95
103
  const entry = argv[1];
96
104
  if (!entry) return false;
97
105
  try {
98
- return fileURLToPath(import.meta.url) === entry;
106
+ const self = fileURLToPath(import.meta.url);
107
+ return realpathSync(self) === realpathSync(entry);
99
108
  } catch {
100
109
  return false;
101
110
  }
@@ -1,8 +1,12 @@
1
1
  // config seam — per-folder resolution. Precedence (highest wins):
2
- // env > nearest .pi/webveil.json (walking up from cwd) > global
3
- // ~/.pi/agent/webveil.json > defaults.
2
+ // env > nearest webveil.json (walking up from cwd) > global
3
+ // $XDG_CONFIG_HOME/webveil/config.json (~/.config/webveil/config.json) >
4
+ // defaults.
4
5
  // "Per folder = per account/egress." Each layer is a partial; later (lower)
5
- // layers fill gaps the higher layers leave.
6
+ // layers fill gaps the higher layers leave. The project file is a
7
+ // frontend-neutral `webveil.json` (no `.pi/`): both the pi-agnostic CLI and the
8
+ // pi extension resolve the same name, so a project is configured the same way
9
+ // regardless of which frontend reads it. See docs/adr/0002.
6
10
 
7
11
  import {readFileSync} from 'node:fs';
8
12
  import {homedir} from 'node:os';
@@ -34,9 +38,14 @@ export interface ResolveOptions {
34
38
  cwd?: string;
35
39
  /** Environment to read overrides from. Defaults to process.env. */
36
40
  env?: Record<string, string | undefined>;
41
+ /** Home directory for the XDG fallback. Defaults to os.homedir(). */
42
+ homeDir?: string;
37
43
  /**
38
- * Path to the global config file. Defaults to ~/.pi/agent/webveil.json.
39
- * Tests point this at a temp dir to isolate the real home directory.
44
+ * Path to the global config file. When given it WINS outright and the XDG
45
+ * resolution is skipped. Tests point this at a temp dir to isolate the real
46
+ * home directory. When absent, the global file resolves to
47
+ * $XDG_CONFIG_HOME/webveil/config.json, falling back to
48
+ * <homeDir>/.config/webveil/config.json.
40
49
  */
41
50
  globalPath?: string;
42
51
  }
@@ -48,7 +57,7 @@ const DEFAULTS: Config = {
48
57
  fetchSize: 'm',
49
58
  };
50
59
 
51
- const PROJECT_FILE = join('.pi', 'webveil.json');
60
+ const PROJECT_FILE = 'webveil.json';
52
61
 
53
62
  function readJson(path: string): PartialConfig | undefined {
54
63
  let text: string;
@@ -60,7 +69,7 @@ function readJson(path: string): PartialConfig | undefined {
60
69
  return JSON.parse(text) as PartialConfig;
61
70
  }
62
71
 
63
- /** The nearest `.pi/webveil.json` walking up from `cwd` (first found wins). */
72
+ /** The nearest `webveil.json` walking up from `cwd` (first found wins). */
64
73
  function readProjectChain(cwd: string): PartialConfig | undefined {
65
74
  let dir = cwd;
66
75
  const {root} = parse(dir);
@@ -86,6 +95,19 @@ function readEnv(env: Record<string, string | undefined>): PartialConfig {
86
95
  return layer;
87
96
  }
88
97
 
98
+ /**
99
+ * The global config path, XDG-style: `$XDG_CONFIG_HOME/webveil/config.json`,
100
+ * falling back to `<homeDir>/.config/webveil/config.json` when XDG_CONFIG_HOME
101
+ * is unset. (`options.globalPath`, when given, bypasses this entirely.)
102
+ */
103
+ function resolveGlobalPath(
104
+ env: Record<string, string | undefined>,
105
+ homeDir = homedir(),
106
+ ): string {
107
+ const base = env.XDG_CONFIG_HOME || join(homeDir, '.config');
108
+ return join(base, 'webveil', 'config.json');
109
+ }
110
+
89
111
  /**
90
112
  * Resolve the effective config. Higher-precedence layers override lower ones,
91
113
  * key by key: env > project chain > global file > defaults.
@@ -94,7 +116,7 @@ export function resolveConfig(options: ResolveOptions = {}): Config {
94
116
  const cwd = options.cwd ?? process.cwd();
95
117
  const env = options.env ?? process.env;
96
118
  const globalPath =
97
- options.globalPath ?? join(homedir(), '.pi', 'agent', 'webveil.json');
119
+ options.globalPath ?? resolveGlobalPath(env, options.homeDir);
98
120
 
99
121
  const layers: PartialConfig[] = [
100
122
  DEFAULTS,