open-walnut 0.4.1 → 0.4.2
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 +2 -5
- package/dist/cli-fast.js +69 -46
- package/dist/cli.js +704 -274
- package/dist/daemon-binaries/acp-worker.js.version +1 -1
- package/dist/web/server.js +704 -274
- package/dist/web/static/assets/{OfficePreview-C8OMbtiq.js → OfficePreview-CEHO0xkd.js} +2 -2
- package/dist/web/static/assets/{docx-preview-hDgtrOpv.js → docx-preview-CuZwjAMS.js} +1 -1
- package/dist/web/static/assets/{index-CWIydpPr.js → index-0MyC-yGG.js} +1 -1
- package/dist/web/static/assets/{index-BAb6UVet.js → index-BBjg7m-_.js} +1 -1
- package/dist/web/static/assets/{index-D1uUk0AQ.js → index-BFF_G72i.js} +289 -289
- package/dist/web/static/assets/{index-CPHXL-wy.js → index-BRLxNhyy.js} +1 -1
- package/dist/web/static/assets/{index-VcSnwuHG.js → index-Bqg4_WEG.js} +1 -1
- package/dist/web/static/assets/{index-bfZj1PAc.js → index-C2YGUYGS.js} +1 -1
- package/dist/web/static/assets/{index-ph8Hxff-.js → index-D1dpOEzW.js} +1 -1
- package/dist/web/static/assets/{index-nRBC-NJN.js → index-D9qPPm7h.js} +1 -1
- package/dist/web/static/assets/{index-D81YKipC.js → index-DAOPV34I.js} +1 -1
- package/dist/web/static/assets/{index-CBHRNnCk.js → index-DLjK8dGE.js} +1 -1
- package/dist/web/static/assets/{index-KY36bfpA.js → index-DOXm2Aye.js} +1 -1
- package/dist/web/static/assets/{index-EowLf_Xf.js → index-DR-LSqAg.js} +1 -1
- package/dist/web/static/assets/{index-gv-TJwHT.js → index-DXtp_ZWh.js} +1 -1
- package/dist/web/static/assets/index-DeYCGmOR.css +32 -0
- package/dist/web/static/assets/{index-B2-N8jTH.js → index-DrWzb338.js} +1 -1
- package/dist/web/static/assets/{index-Caj09uf7.js → index-DtRwkh8J.js} +1 -1
- package/dist/web/static/assets/{index-C5-vT4kT.js → index-ccs5s80D.js} +1 -1
- package/dist/web/static/assets/{index-DtRt21Zi.js → index-mWEwJcqw.js} +1 -1
- package/dist/web/static/assets/{index-B35fidy6.js → index-unnPilnK.js} +1 -1
- package/dist/web/static/assets/{jszip.min-DyrlNEg4.js → jszip.min-DYFwy4PE.js} +1 -1
- package/dist/web/static/assets/{pptx-preview.es-DjND6y6O.js → pptx-preview.es-eu2nX9JC.js} +1 -1
- package/dist/web/static/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/static/assets/index-Btn4AoIy.css +0 -32
package/README.md
CHANGED
|
@@ -44,12 +44,9 @@ local-first, self-hosted, and has no telemetry.
|
|
|
44
44
|
- Node.js 22 or newer. If you don't have it: `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash` then `nvm install 22`.
|
|
45
45
|
- git, only for the checkout route below (macOS: `xcode-select --install`, Ubuntu: `sudo apt install git`)
|
|
46
46
|
- Linux: a C library from 2019 or later (glibc 2.29+: Ubuntu 20.04+, Debian 11+, AL2023, Fedora). Older distros compile one native module and need a newer Python and GCC first; `npm start` prints the exact commands, and [Getting Started](GETTING_STARTED.md#older-linux-glibc-before-229) has them too.
|
|
47
|
-
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
|
|
48
|
-
- An Anthropic API key, AWS Bedrock credentials, or another supported model provider
|
|
49
|
-
for Walnut
|
|
47
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code), signed in once (`npm install -g @anthropic-ai/claude-code`, then run `claude`)
|
|
50
48
|
|
|
51
|
-
Claude Code and
|
|
52
|
-
Claude Code CLI login, while Walnut uses the model provider selected during setup.
|
|
49
|
+
That is the whole AI setup. Walnut runs on your Claude Code: the chat, coding sessions, and background work (summaries, titles, subagents) all use the `claude` you already have, however it signs in (Anthropic account, Bedrock, or Vertex). An Anthropic API key or AWS Bedrock credentials are optional, for people who would rather point Walnut's background work at a provider directly (Settings → AI Provider).
|
|
53
50
|
|
|
54
51
|
### Install
|
|
55
52
|
|
package/dist/cli-fast.js
CHANGED
|
@@ -291,9 +291,9 @@ function causeCode(err) {
|
|
|
291
291
|
}
|
|
292
292
|
return void 0;
|
|
293
293
|
}
|
|
294
|
-
async function rawRequest(base, method,
|
|
294
|
+
async function rawRequest(base, method, path7, body, timeoutMs, prov) {
|
|
295
295
|
const serverRoot = base.replace(/\/api\/v1$/, "");
|
|
296
|
-
const url =
|
|
296
|
+
const url = path7.startsWith("/api/") ? `${serverRoot}${path7}` : `${base}${path7}`;
|
|
297
297
|
let res;
|
|
298
298
|
try {
|
|
299
299
|
res = await fetch(url, {
|
|
@@ -312,7 +312,7 @@ async function rawRequest(base, method, path6, body, timeoutMs, prov) {
|
|
|
312
312
|
return { ok: false, message: `Walnut server not running at ${base} \u2014 start with \`open-walnut web\`` };
|
|
313
313
|
}
|
|
314
314
|
if (err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError")) {
|
|
315
|
-
return { ok: false, message: `Walnut request timed out after ${timeoutMs}ms: ${method} ${
|
|
315
|
+
return { ok: false, message: `Walnut request timed out after ${timeoutMs}ms: ${method} ${path7}` };
|
|
316
316
|
}
|
|
317
317
|
return { ok: false, message: `Walnut request failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
318
318
|
}
|
|
@@ -335,7 +335,7 @@ async function rawRequest(base, method, path6, body, timeoutMs, prov) {
|
|
|
335
335
|
}
|
|
336
336
|
function materializeBinding(bind, args2) {
|
|
337
337
|
const used = /* @__PURE__ */ new Set();
|
|
338
|
-
const
|
|
338
|
+
const path7 = bind.path.replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, (_, name) => {
|
|
339
339
|
used.add(name);
|
|
340
340
|
const v = args2[name];
|
|
341
341
|
if (v === void 0 || v === null || v === "") {
|
|
@@ -363,7 +363,7 @@ function materializeBinding(bind, args2) {
|
|
|
363
363
|
const qs = sp.toString();
|
|
364
364
|
const needsBody = bind.method !== "GET" && bind.method !== "DELETE";
|
|
365
365
|
const body = bodyEntries.length > 0 ? Object.fromEntries(bodyEntries) : needsBody ? {} : void 0;
|
|
366
|
-
return { path: qs ? `${
|
|
366
|
+
return { path: qs ? `${path7}?${qs}` : path7, body };
|
|
367
367
|
}
|
|
368
368
|
async function executeOp(name, rawArgs, options = {}) {
|
|
369
369
|
const op = getOp(name);
|
|
@@ -384,8 +384,8 @@ async function runOp(op, args2, base, prov) {
|
|
|
384
384
|
const timeoutMs = op.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
385
385
|
if (op.handler) {
|
|
386
386
|
try {
|
|
387
|
-
const call = async (method,
|
|
388
|
-
const r2 = await rawRequest(base, method,
|
|
387
|
+
const call = async (method, path7, body) => {
|
|
388
|
+
const r2 = await rawRequest(base, method, path7, body, timeoutMs, prov);
|
|
389
389
|
if (!r2.ok) throw new Error(r2.message);
|
|
390
390
|
return r2.result;
|
|
391
391
|
};
|
|
@@ -1104,11 +1104,34 @@ var init_model_catalog = __esm({
|
|
|
1104
1104
|
}
|
|
1105
1105
|
});
|
|
1106
1106
|
|
|
1107
|
+
// src/core/claude-cli-detect.ts
|
|
1108
|
+
import { execFileSync } from "child_process";
|
|
1109
|
+
import fs3 from "fs";
|
|
1110
|
+
import os2 from "os";
|
|
1111
|
+
import path3 from "path";
|
|
1112
|
+
var _CLAUDE_CREDENTIALS_HOME;
|
|
1113
|
+
var init_claude_cli_detect = __esm({
|
|
1114
|
+
"src/core/claude-cli-detect.ts"() {
|
|
1115
|
+
"use strict";
|
|
1116
|
+
init_constants();
|
|
1117
|
+
_CLAUDE_CREDENTIALS_HOME = os2.homedir();
|
|
1118
|
+
}
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
// src/agent/providers/default-provider.ts
|
|
1122
|
+
var init_default_provider = __esm({
|
|
1123
|
+
"src/agent/providers/default-provider.ts"() {
|
|
1124
|
+
"use strict";
|
|
1125
|
+
init_claude_cli_detect();
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1107
1129
|
// src/core/cheap-model.ts
|
|
1108
1130
|
var init_cheap_model = __esm({
|
|
1109
1131
|
"src/core/cheap-model.ts"() {
|
|
1110
1132
|
"use strict";
|
|
1111
1133
|
init_model_catalog();
|
|
1134
|
+
init_default_provider();
|
|
1112
1135
|
}
|
|
1113
1136
|
});
|
|
1114
1137
|
|
|
@@ -1257,8 +1280,8 @@ var init_output_mode = __esm({
|
|
|
1257
1280
|
});
|
|
1258
1281
|
|
|
1259
1282
|
// src/core/session-hooks/builtins.ts
|
|
1260
|
-
import
|
|
1261
|
-
import
|
|
1283
|
+
import fs4 from "fs";
|
|
1284
|
+
import path4 from "path";
|
|
1262
1285
|
function caseInsensitiveFragment(pattern) {
|
|
1263
1286
|
return pattern.replace(/[a-zA-Z]/g, (ch) => `[${ch.toUpperCase()}${ch.toLowerCase()}]`);
|
|
1264
1287
|
}
|
|
@@ -1456,8 +1479,8 @@ var init_tasks = __esm({
|
|
|
1456
1479
|
if (effective.limit === void 0 && args2.working_set !== true) {
|
|
1457
1480
|
effective.limit = DEFAULT_TASK_LIST_LIMIT;
|
|
1458
1481
|
}
|
|
1459
|
-
const { path:
|
|
1460
|
-
const body = await call("GET",
|
|
1482
|
+
const { path: path7 } = materializeBinding(TASK_LIST_BINDING, effective);
|
|
1483
|
+
const body = await call("GET", path7);
|
|
1461
1484
|
const tasks = body?.tasks;
|
|
1462
1485
|
if (!Array.isArray(tasks)) return body;
|
|
1463
1486
|
const total = typeof body?.total === "number" ? body.total : tasks.length;
|
|
@@ -1687,10 +1710,10 @@ function looksLikeNoteId(value) {
|
|
|
1687
1710
|
}
|
|
1688
1711
|
async function resolveNoteTarget(args2, call) {
|
|
1689
1712
|
const id = typeof args2.id === "string" ? args2.id.trim() : "";
|
|
1690
|
-
const
|
|
1691
|
-
if (!id && !
|
|
1692
|
-
const ref = id ||
|
|
1693
|
-
if (!id && !looksLikeNoteId(
|
|
1713
|
+
const path7 = typeof args2.path === "string" ? args2.path.trim() : "";
|
|
1714
|
+
if (!id && !path7) throw new Error("pass path (vault-relative note path) or id (from note_search)");
|
|
1715
|
+
const ref = id || path7;
|
|
1716
|
+
if (!id && !looksLikeNoteId(path7)) return path7;
|
|
1694
1717
|
const resolved = await call("GET", `/notes/resolve?ref=${encodeURIComponent(ref)}`);
|
|
1695
1718
|
const resolvedPath = resolved.path;
|
|
1696
1719
|
if (typeof resolvedPath !== "string" || !resolvedPath) throw new Error(`cannot resolve note reference: ${ref}`);
|
|
@@ -1829,16 +1852,16 @@ var init_core = __esm({
|
|
|
1829
1852
|
expectedHash: z4.string().optional().describe("contentHash from note_read (update only)")
|
|
1830
1853
|
},
|
|
1831
1854
|
handler: async (args2, call) => {
|
|
1832
|
-
const { path:
|
|
1833
|
-
const encoded = encodeVaultPath(String(
|
|
1855
|
+
const { path: path7, content, expectedHash } = args2;
|
|
1856
|
+
const encoded = encodeVaultPath(String(path7));
|
|
1834
1857
|
if (expectedHash === void 0) {
|
|
1835
1858
|
try {
|
|
1836
|
-
return await call("POST", "/notes", { path:
|
|
1859
|
+
return await call("POST", "/notes", { path: path7, content });
|
|
1837
1860
|
} catch (err) {
|
|
1838
1861
|
const message = err instanceof Error ? err.message : String(err);
|
|
1839
1862
|
if (/already exists/i.test(message)) {
|
|
1840
1863
|
throw new Error(
|
|
1841
|
-
`note exists; pass expectedHash from note_read to update ${String(
|
|
1864
|
+
`note exists; pass expectedHash from note_read to update ${String(path7)} (note_read \u2192 contentHash \u2192 note_write), or use note_edit for a partial change`
|
|
1842
1865
|
);
|
|
1843
1866
|
}
|
|
1844
1867
|
throw err;
|
|
@@ -1926,11 +1949,11 @@ var init_core = __esm({
|
|
|
1926
1949
|
},
|
|
1927
1950
|
handler: async (args2, call) => {
|
|
1928
1951
|
const method = String(args2.method);
|
|
1929
|
-
const
|
|
1930
|
-
if (!
|
|
1952
|
+
const path7 = String(args2.path);
|
|
1953
|
+
if (!path7.startsWith("/api/")) {
|
|
1931
1954
|
throw new Error("api passthrough only accepts paths starting with /api/");
|
|
1932
1955
|
}
|
|
1933
|
-
return call(method,
|
|
1956
|
+
return call(method, path7, args2.body);
|
|
1934
1957
|
},
|
|
1935
1958
|
tags: { readonly: false, remote: "allow" }
|
|
1936
1959
|
});
|
|
@@ -2215,9 +2238,9 @@ function classifyArgsSource(raw, stdinIsTty) {
|
|
|
2215
2238
|
const value = raw.trim();
|
|
2216
2239
|
if (value === "-") return { kind: "stdin" };
|
|
2217
2240
|
if (value.startsWith("@")) {
|
|
2218
|
-
const
|
|
2219
|
-
if (!
|
|
2220
|
-
return { kind: "file", path:
|
|
2241
|
+
const path7 = value.slice(1);
|
|
2242
|
+
if (!path7) return { kind: "usage-error", message: "@ needs a file path, e.g. @/tmp/letter.json" };
|
|
2243
|
+
return { kind: "file", path: path7 };
|
|
2221
2244
|
}
|
|
2222
2245
|
if (!value) return { kind: "none" };
|
|
2223
2246
|
return { kind: "inline", json: raw };
|
|
@@ -2260,10 +2283,10 @@ __export(wn_cli_exports, {
|
|
|
2260
2283
|
resolveWalnutCliEndpoint: () => resolveWalnutCliEndpoint,
|
|
2261
2284
|
runWalnutCli: () => runWalnutCli
|
|
2262
2285
|
});
|
|
2263
|
-
import
|
|
2286
|
+
import fs5 from "fs";
|
|
2264
2287
|
import net from "net";
|
|
2265
|
-
import
|
|
2266
|
-
import
|
|
2288
|
+
import os3 from "os";
|
|
2289
|
+
import path5 from "path";
|
|
2267
2290
|
function parseWalnutCliArgs(argv2) {
|
|
2268
2291
|
const [head, ...rest2] = argv2;
|
|
2269
2292
|
if (head === void 0) return { kind: "usage-error", message: "missing command" };
|
|
@@ -2399,7 +2422,7 @@ The 0600 socket mode is the gateway credential, so walnut will not talk to it.`
|
|
|
2399
2422
|
}
|
|
2400
2423
|
function probeSocket(socketPath) {
|
|
2401
2424
|
try {
|
|
2402
|
-
const st =
|
|
2425
|
+
const st = fs5.statSync(socketPath);
|
|
2403
2426
|
return { isSocket: st.isSocket(), uid: st.uid, mode: st.mode & 511 };
|
|
2404
2427
|
} catch {
|
|
2405
2428
|
return null;
|
|
@@ -2505,12 +2528,12 @@ run \`walnut --help\` for usage
|
|
|
2505
2528
|
else if (source.kind === "stdin") {
|
|
2506
2529
|
rawJson = await readStdin();
|
|
2507
2530
|
if (Buffer.byteLength(rawJson, "utf-8") > GATEWAY_INLINE_ARGS_MAX_BYTES) {
|
|
2508
|
-
spilledArgsFile =
|
|
2509
|
-
|
|
2531
|
+
spilledArgsFile = path5.join(
|
|
2532
|
+
os3.tmpdir(),
|
|
2510
2533
|
`walnut-args-${process.pid}-${Date.now().toString(36)}.json`
|
|
2511
2534
|
);
|
|
2512
2535
|
try {
|
|
2513
|
-
|
|
2536
|
+
fs5.writeFileSync(spilledArgsFile, rawJson, { encoding: "utf-8", mode: 384 });
|
|
2514
2537
|
} catch (err) {
|
|
2515
2538
|
process.stderr.write(
|
|
2516
2539
|
`walnut: cannot stage a large payload at ${spilledArgsFile}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2521,10 +2544,10 @@ run \`walnut --help\` for usage
|
|
|
2521
2544
|
argsFile = spilledArgsFile;
|
|
2522
2545
|
}
|
|
2523
2546
|
} else if (source.kind === "file") {
|
|
2524
|
-
const abs =
|
|
2547
|
+
const abs = path5.resolve(source.path);
|
|
2525
2548
|
let size = -1;
|
|
2526
2549
|
try {
|
|
2527
|
-
size =
|
|
2550
|
+
size = fs5.statSync(abs).size;
|
|
2528
2551
|
} catch (err) {
|
|
2529
2552
|
process.stderr.write(
|
|
2530
2553
|
`walnut: cannot read arguments from ${source.path}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2536,7 +2559,7 @@ run \`walnut --help\` for usage
|
|
|
2536
2559
|
argsFile = abs;
|
|
2537
2560
|
} else {
|
|
2538
2561
|
try {
|
|
2539
|
-
rawJson =
|
|
2562
|
+
rawJson = fs5.readFileSync(abs, "utf-8");
|
|
2540
2563
|
} catch (err) {
|
|
2541
2564
|
process.stderr.write(
|
|
2542
2565
|
`walnut: cannot read arguments from ${source.path}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2577,7 +2600,7 @@ run \`walnut --help\` for usage
|
|
|
2577
2600
|
} finally {
|
|
2578
2601
|
if (spilledArgsFile) {
|
|
2579
2602
|
try {
|
|
2580
|
-
|
|
2603
|
+
fs5.unlinkSync(spilledArgsFile);
|
|
2581
2604
|
} catch {
|
|
2582
2605
|
}
|
|
2583
2606
|
}
|
|
@@ -2997,12 +3020,12 @@ function apiBaseUrl() {
|
|
|
2997
3020
|
const raw = process.env.OPEN_WALNUT_API_URL?.trim();
|
|
2998
3021
|
return (raw || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
2999
3022
|
}
|
|
3000
|
-
async function request(method,
|
|
3023
|
+
async function request(method, path7, body, opts) {
|
|
3001
3024
|
const base = apiBaseUrl();
|
|
3002
3025
|
const timeoutMs = opts?.timeoutMs ?? REQUEST_TIMEOUT_MS2;
|
|
3003
3026
|
let res;
|
|
3004
3027
|
try {
|
|
3005
|
-
res = await fetch(base +
|
|
3028
|
+
res = await fetch(base + path7, {
|
|
3006
3029
|
method,
|
|
3007
3030
|
...body !== void 0 ? { headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) } : {},
|
|
3008
3031
|
signal: AbortSignal.timeout(timeoutMs)
|
|
@@ -3036,11 +3059,11 @@ async function request(method, path6, body, opts) {
|
|
|
3036
3059
|
}
|
|
3037
3060
|
return parsed;
|
|
3038
3061
|
}
|
|
3039
|
-
function apiGet(
|
|
3040
|
-
return request("GET",
|
|
3062
|
+
function apiGet(path7, opts) {
|
|
3063
|
+
return request("GET", path7, void 0, opts);
|
|
3041
3064
|
}
|
|
3042
|
-
function apiPost(
|
|
3043
|
-
return request("POST",
|
|
3065
|
+
function apiPost(path7, body) {
|
|
3066
|
+
return request("POST", path7, body ?? {});
|
|
3044
3067
|
}
|
|
3045
3068
|
function reportApiError(err, globals2) {
|
|
3046
3069
|
const message = err instanceof ApiUnreachableError ? `Open Walnut server is not running at ${err.baseUrl} \u2014 start it with: open-walnut web` : err instanceof Error ? err.message : String(err);
|
|
@@ -3519,8 +3542,8 @@ var init_start = __esm({
|
|
|
3519
3542
|
});
|
|
3520
3543
|
|
|
3521
3544
|
// src/cli-fast.ts
|
|
3522
|
-
import
|
|
3523
|
-
import
|
|
3545
|
+
import fs6 from "fs";
|
|
3546
|
+
import path6 from "path";
|
|
3524
3547
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3525
3548
|
var LITE_COMMANDS = /* @__PURE__ */ new Set([
|
|
3526
3549
|
"tools",
|
|
@@ -3537,8 +3560,8 @@ var LITE_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
3537
3560
|
var argv = process.argv.slice(2);
|
|
3538
3561
|
if (argv.includes("--version") || argv.includes("-V")) {
|
|
3539
3562
|
try {
|
|
3540
|
-
const pkgPath =
|
|
3541
|
-
console.log(JSON.parse(
|
|
3563
|
+
const pkgPath = path6.join(path6.dirname(fileURLToPath2(import.meta.url)), "..", "package.json");
|
|
3564
|
+
console.log(JSON.parse(fs6.readFileSync(pkgPath, "utf-8")).version ?? "0.0.0");
|
|
3542
3565
|
} catch {
|
|
3543
3566
|
console.log("0.0.0");
|
|
3544
3567
|
}
|