weifuwu 0.18.9 → 0.18.10

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/dist/index.js CHANGED
@@ -5130,7 +5130,7 @@ function ensureCertificates(config) {
5130
5130
  import { createOpenAI as createOpenAI3 } from "@ai-sdk/openai";
5131
5131
 
5132
5132
  // opencode/rest.ts
5133
- import { join as join4 } from "node:path";
5133
+ import { join as join5 } from "node:path";
5134
5134
 
5135
5135
  // ssr.ts
5136
5136
  import { createElement } from "react";
@@ -5489,9 +5489,112 @@ function layout(path2) {
5489
5489
  };
5490
5490
  }
5491
5491
 
5492
+ // tailwind.ts
5493
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync } from "node:fs";
5494
+ import { join as join3, relative, resolve as resolve5 } from "node:path";
5495
+
5496
+ // live.ts
5497
+ import chokidar from "chokidar";
5498
+ var clients = /* @__PURE__ */ new Set();
5499
+ function broadcastReload() {
5500
+ for (const ws of clients) {
5501
+ try {
5502
+ ws.send("reload");
5503
+ } catch {
5504
+ clients.delete(ws);
5505
+ }
5506
+ }
5507
+ }
5508
+ function liveReload(opts) {
5509
+ const r = new Router();
5510
+ r.ws("/__weifuwu/livereload", {
5511
+ open(ws) {
5512
+ clients.add(ws);
5513
+ ws.on("close", () => clients.delete(ws));
5514
+ ws.on("error", () => clients.delete(ws));
5515
+ }
5516
+ });
5517
+ const watcher = chokidar.watch(opts.dirs, {
5518
+ ignored: /(^|[/\\])\.|node_modules|[/\\]\.weifuwu[/\\]/,
5519
+ ignoreInitial: true
5520
+ });
5521
+ watcher.on("change", (path2) => {
5522
+ if (!/\.tsx?$/.test(path2)) return;
5523
+ clearCompileCache();
5524
+ setTimeout(broadcastReload, 50);
5525
+ });
5526
+ r.close = () => {
5527
+ watcher.close();
5528
+ clients.clear();
5529
+ };
5530
+ return r;
5531
+ }
5532
+
5533
+ // tailwind.ts
5534
+ var isDev2 = process.env.NODE_ENV !== "production";
5535
+ var extraSources = /* @__PURE__ */ new Set();
5536
+ function addTailwindSource(dir) {
5537
+ extraSources.add(resolve5(dir));
5538
+ }
5539
+ function tailwind(dir) {
5540
+ const cssDir = resolve5(dir);
5541
+ const cssPath = join3(cssDir, "app.css");
5542
+ let compiledCss = "";
5543
+ let twWatcher = null;
5544
+ return async (req, ctx, next) => {
5545
+ const url = new URL(req.url);
5546
+ if (!compiledCss) compiledCss = await compile(cssPath, cssDir);
5547
+ const stylePath = (ctx.mountPath || "") + "/__wfw/style.css";
5548
+ if (url.pathname === stylePath) {
5549
+ return new Response(compiledCss || "", {
5550
+ headers: { "content-type": "text/css; charset=utf-8" }
5551
+ });
5552
+ }
5553
+ ctx.compiledTailwindCss = compiledCss;
5554
+ if (isDev2 && !twWatcher) {
5555
+ twWatcher = watchFile(cssPath, () => {
5556
+ compiledCss = "";
5557
+ broadcastReload();
5558
+ });
5559
+ }
5560
+ return next(req, ctx);
5561
+ };
5562
+ }
5563
+ async function compile(cssPath, cssDir) {
5564
+ try {
5565
+ if (!existsSync3(cssPath)) {
5566
+ mkdirSync2(cssDir, { recursive: true });
5567
+ writeFileSync(cssPath, '@import "tailwindcss"\n', "utf-8");
5568
+ }
5569
+ const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
5570
+ const { default: postcss } = await import("postcss");
5571
+ let src = readFileSync3(cssPath, "utf-8");
5572
+ src = `@source "./";
5573
+ ${src}`;
5574
+ for (const srcDir of extraSources) {
5575
+ const rel = relative(cssDir, srcDir) || ".";
5576
+ src = `@source "${rel.startsWith(".") ? rel : "./" + rel}";
5577
+ ${src}`;
5578
+ }
5579
+ const result = await postcss([tailwindPlugin()]).process(src, { from: cssPath });
5580
+ return result.css;
5581
+ } catch (err) {
5582
+ console.warn("Tailwind CSS processing failed:", err.message);
5583
+ return "";
5584
+ }
5585
+ }
5586
+ function watchFile(path2, onChange) {
5587
+ let watcher = null;
5588
+ import("chokidar").then((chokidar2) => {
5589
+ watcher = chokidar2.default.watch(resolve5(path2), { persistent: false });
5590
+ watcher.on("change", onChange);
5591
+ });
5592
+ return watcher;
5593
+ }
5594
+
5492
5595
  // opencode/session.ts
5493
5596
  import { randomUUID as randomUUID2 } from "node:crypto";
5494
- import { join as join3 } from "node:path";
5597
+ import { join as join4 } from "node:path";
5495
5598
  import { mkdir as mkdir2 } from "node:fs/promises";
5496
5599
  var sessions = pgTable("_opencode_sessions", {
5497
5600
  id: uuid("id"),
@@ -5528,7 +5631,7 @@ async function createSession(sql2, opts, cwd, mountPath) {
5528
5631
  }
5529
5632
  function computeSessionWorkspace(cwd, mountPath, sessionId) {
5530
5633
  const name = !mountPath || mountPath === "/" ? "default" : mountPath.replace(/^\//, "");
5531
- return join3(cwd, ".sessions", name, sessionId);
5634
+ return join4(cwd, ".sessions", name, sessionId);
5532
5635
  }
5533
5636
  async function getSession(sql2, id3) {
5534
5637
  const { data: rows } = await sessions.readMany(sql2, { id: id3, active: true });
@@ -5744,8 +5847,8 @@ function createBashTool(ctx) {
5744
5847
  // opencode/tools/read.ts
5745
5848
  import { tool as tool4 } from "ai";
5746
5849
  import { z as z6 } from "zod";
5747
- import { readFileSync as readFileSync3 } from "node:fs";
5748
- import { resolve as resolve5 } from "node:path";
5850
+ import { readFileSync as readFileSync4 } from "node:fs";
5851
+ import { resolve as resolve6 } from "node:path";
5749
5852
  function createReadTool(ctx) {
5750
5853
  return tool4({
5751
5854
  description: "Read file contents. Supports offset and limit for reading specific line ranges.",
@@ -5755,11 +5858,11 @@ function createReadTool(ctx) {
5755
5858
  limit: z6.number().optional().describe("Number of lines to read")
5756
5859
  }),
5757
5860
  execute: async ({ path: path2, offset, limit }) => {
5758
- const resolved = resolve5(ctx.workspace, path2);
5861
+ const resolved = resolve6(ctx.workspace, path2);
5759
5862
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
5760
5863
  return { error: "Path not allowed", content: null, totalLines: 0 };
5761
5864
  }
5762
- const content = readFileSync3(resolved, "utf-8");
5865
+ const content = readFileSync4(resolved, "utf-8");
5763
5866
  const lines = content.split("\n");
5764
5867
  const totalLines = lines.length;
5765
5868
  if (offset !== void 0) {
@@ -5786,8 +5889,8 @@ function createReadTool(ctx) {
5786
5889
  // opencode/tools/write.ts
5787
5890
  import { tool as tool5 } from "ai";
5788
5891
  import { z as z7 } from "zod";
5789
- import { writeFileSync, mkdirSync as mkdirSync2 } from "node:fs";
5790
- import { resolve as resolve6, dirname as dirname3 } from "node:path";
5892
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "node:fs";
5893
+ import { resolve as resolve7, dirname as dirname3 } from "node:path";
5791
5894
  function createWriteTool(ctx) {
5792
5895
  return tool5({
5793
5896
  description: "Create or overwrite a file. Parent directories are created automatically.",
@@ -5796,12 +5899,12 @@ function createWriteTool(ctx) {
5796
5899
  content: z7.string().describe("File content")
5797
5900
  }),
5798
5901
  execute: async ({ path: path2, content }) => {
5799
- const resolved = resolve6(ctx.workspace, path2);
5902
+ const resolved = resolve7(ctx.workspace, path2);
5800
5903
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
5801
5904
  return { error: "Path not allowed" };
5802
5905
  }
5803
- mkdirSync2(dirname3(resolved), { recursive: true });
5804
- writeFileSync(resolved, content, "utf-8");
5906
+ mkdirSync3(dirname3(resolved), { recursive: true });
5907
+ writeFileSync2(resolved, content, "utf-8");
5805
5908
  return { path: path2, size: content.length };
5806
5909
  }
5807
5910
  });
@@ -5810,8 +5913,8 @@ function createWriteTool(ctx) {
5810
5913
  // opencode/tools/edit.ts
5811
5914
  import { tool as tool6 } from "ai";
5812
5915
  import { z as z8 } from "zod";
5813
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
5814
- import { resolve as resolve7 } from "node:path";
5916
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
5917
+ import { resolve as resolve8 } from "node:path";
5815
5918
  function createEditTool(ctx) {
5816
5919
  return tool6({
5817
5920
  description: "Perform exact string replacements in a file. If oldString appears multiple times, provide more surrounding context.",
@@ -5822,18 +5925,18 @@ function createEditTool(ctx) {
5822
5925
  replaceAll: z8.boolean().default(false).describe("Replace all occurrences")
5823
5926
  }),
5824
5927
  execute: async ({ path: path2, oldString, newString, replaceAll }) => {
5825
- const resolved = resolve7(ctx.workspace, path2);
5928
+ const resolved = resolve8(ctx.workspace, path2);
5826
5929
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
5827
5930
  return { error: "Path not allowed" };
5828
5931
  }
5829
- const content = readFileSync4(resolved, "utf-8");
5932
+ const content = readFileSync5(resolved, "utf-8");
5830
5933
  if (replaceAll) {
5831
5934
  if (!content.includes(oldString)) {
5832
5935
  return { error: "oldString not found in file", replaced: 0 };
5833
5936
  }
5834
5937
  const count = content.split(oldString).length - 1;
5835
5938
  const result2 = content.replaceAll(oldString, newString);
5836
- writeFileSync2(resolved, result2, "utf-8");
5939
+ writeFileSync3(resolved, result2, "utf-8");
5837
5940
  return { path: path2, replaced: count };
5838
5941
  }
5839
5942
  const firstIdx = content.indexOf(oldString);
@@ -5845,7 +5948,7 @@ function createEditTool(ctx) {
5845
5948
  return { error: "Found multiple matches. Provide more surrounding context in oldString.", replaced: 0 };
5846
5949
  }
5847
5950
  const result = content.replace(oldString, newString);
5848
- writeFileSync2(resolved, result, "utf-8");
5951
+ writeFileSync3(resolved, result, "utf-8");
5849
5952
  return { path: path2, replaced: 1 };
5850
5953
  }
5851
5954
  });
@@ -5855,8 +5958,8 @@ function createEditTool(ctx) {
5855
5958
  import { tool as tool7 } from "ai";
5856
5959
  import { z as z9 } from "zod";
5857
5960
  import { execFileSync } from "node:child_process";
5858
- import { resolve as resolve8 } from "node:path";
5859
- import { existsSync as existsSync3 } from "node:fs";
5961
+ import { resolve as resolve9 } from "node:path";
5962
+ import { existsSync as existsSync4 } from "node:fs";
5860
5963
  function createGrepTool(ctx) {
5861
5964
  return tool7({
5862
5965
  description: "Search file contents using regex. Supports file type filtering and context lines.",
@@ -5867,10 +5970,10 @@ function createGrepTool(ctx) {
5867
5970
  context: z9.number().default(0).describe("Number of context lines before and after each match")
5868
5971
  }),
5869
5972
  execute: async ({ pattern, include, path: path2, context }) => {
5870
- const searchDir = path2 ? resolve8(ctx.workspace, path2) : ctx.workspace;
5973
+ const searchDir = path2 ? resolve9(ctx.workspace, path2) : ctx.workspace;
5871
5974
  try {
5872
5975
  let stdout;
5873
- if (existsSync3("/usr/bin/rg") || existsSync3("/usr/local/bin/rg")) {
5976
+ if (existsSync4("/usr/bin/rg") || existsSync4("/usr/local/bin/rg")) {
5874
5977
  const args = ["-n"];
5875
5978
  if (context > 0) args.push("-C", String(context));
5876
5979
  if (include) args.push("-g", include);
@@ -5899,7 +6002,7 @@ function createGrepTool(ctx) {
5899
6002
  import { tool as tool8 } from "ai";
5900
6003
  import { z as z10 } from "zod";
5901
6004
  import { execFileSync as execFileSync2 } from "node:child_process";
5902
- import { resolve as resolve9 } from "node:path";
6005
+ import { resolve as resolve10 } from "node:path";
5903
6006
  function createGlobTool(ctx) {
5904
6007
  return tool8({
5905
6008
  description: "Find files matching a glob pattern.",
@@ -5908,7 +6011,7 @@ function createGlobTool(ctx) {
5908
6011
  path: z10.string().optional().describe("Subdirectory relative to workspace")
5909
6012
  }),
5910
6013
  execute: async ({ pattern, path: path2 }) => {
5911
- const searchDir = path2 ? resolve9(ctx.workspace, path2) : ctx.workspace;
6014
+ const searchDir = path2 ? resolve10(ctx.workspace, path2) : ctx.workspace;
5912
6015
  try {
5913
6016
  const stdout = execFileSync2("find", [
5914
6017
  searchDir,
@@ -6124,8 +6227,9 @@ async function buildRouter4(deps) {
6124
6227
  });
6125
6228
  try {
6126
6229
  const uiDir = new URL("../opencode/ui/", import.meta.url).pathname;
6127
- router.use(layout(join4(uiDir, "layout.tsx")));
6128
- router.get("/", ssr(join4(uiDir, "page.tsx")));
6230
+ addTailwindSource(uiDir);
6231
+ router.use(layout(join5(uiDir, "layout.tsx")));
6232
+ router.get("/", ssr(join5(uiDir, "page.tsx")));
6129
6233
  } catch (e) {
6130
6234
  console.warn("[opencode] UI not available:", e);
6131
6235
  }
@@ -6133,17 +6237,17 @@ async function buildRouter4(deps) {
6133
6237
  }
6134
6238
 
6135
6239
  // opencode/ws.ts
6136
- var clients = /* @__PURE__ */ new WeakMap();
6240
+ var clients2 = /* @__PURE__ */ new WeakMap();
6137
6241
  function createWSHandler2(deps) {
6138
6242
  const { sql: sql2, model, workspace, systemPrompt, skills, skillsRegistry, permissions, pendingQuestions } = deps;
6139
6243
  return {
6140
6244
  open(ws, ctx) {
6141
6245
  const userId = ctx.user?.id ?? 0;
6142
6246
  const mountPath = ctx.mountPath ?? "";
6143
- clients.set(ws, { userId, mountPath });
6247
+ clients2.set(ws, { userId, mountPath });
6144
6248
  },
6145
6249
  async message(ws, ctx, data) {
6146
- const client = clients.get(ws);
6250
+ const client = clients2.get(ws);
6147
6251
  if (!client) return;
6148
6252
  let msg;
6149
6253
  try {
@@ -6240,17 +6344,17 @@ function createWSHandler2(deps) {
6240
6344
  }
6241
6345
  },
6242
6346
  close(ws) {
6243
- const client = clients.get(ws);
6347
+ const client = clients2.get(ws);
6244
6348
  if (client) {
6245
6349
  client.abortController?.abort();
6246
- clients.delete(ws);
6350
+ clients2.delete(ws);
6247
6351
  }
6248
6352
  },
6249
6353
  error(ws, _ctx, _err) {
6250
- const client = clients.get(ws);
6354
+ const client = clients2.get(ws);
6251
6355
  if (client) {
6252
6356
  client.abortController?.abort();
6253
- clients.delete(ws);
6357
+ clients2.delete(ws);
6254
6358
  }
6255
6359
  }
6256
6360
  };
@@ -6260,7 +6364,7 @@ function createWSHandler2(deps) {
6260
6364
  import { readFile } from "node:fs/promises";
6261
6365
  import { glob } from "node:fs/promises";
6262
6366
  import { homedir } from "node:os";
6263
- import { resolve as resolve10 } from "node:path";
6367
+ import { resolve as resolve11 } from "node:path";
6264
6368
  import { parse as parseYaml } from "yaml";
6265
6369
  var SEARCH_DIRS = [
6266
6370
  (ws) => `${ws}/.opencode/skills`,
@@ -6298,7 +6402,7 @@ async function scanDir(dir) {
6298
6402
  try {
6299
6403
  const files = [];
6300
6404
  for await (const entry of glob("*/SKILL.md", { cwd: dir })) {
6301
- const skill = await parseSkillFile(resolve10(dir, entry));
6405
+ const skill = await parseSkillFile(resolve11(dir, entry));
6302
6406
  if (skill) files.push(skill);
6303
6407
  }
6304
6408
  return files;
@@ -6633,8 +6737,8 @@ function analytics(options) {
6633
6737
 
6634
6738
  // preferences.ts
6635
6739
  import { readFile as readFile2 } from "node:fs/promises";
6636
- import { existsSync as existsSync4 } from "node:fs";
6637
- import { join as join5, resolve as resolve11 } from "node:path";
6740
+ import { existsSync as existsSync5 } from "node:fs";
6741
+ import { join as join6, resolve as resolve12 } from "node:path";
6638
6742
  var defaults = {
6639
6743
  locale: { default: "en", cookie: "locale", fromAcceptLanguage: true },
6640
6744
  theme: { default: "system", cookie: "theme" }
@@ -6683,7 +6787,7 @@ async function handlePrefSwitch(req, value, cookieName, load) {
6683
6787
  });
6684
6788
  }
6685
6789
  function preferences(options) {
6686
- const dir = options.dir ? resolve11(options.dir) : void 0;
6790
+ const dir = options.dir ? resolve12(options.dir) : void 0;
6687
6791
  const localeOpts = { ...defaults.locale, ...options.locale };
6688
6792
  const themeOpts = { ...defaults.theme, ...options.theme };
6689
6793
  const cache2 = /* @__PURE__ */ new Map();
@@ -6695,8 +6799,8 @@ function preferences(options) {
6695
6799
  if (!validLocale(locale)) return {};
6696
6800
  const cached = cache2.get(locale);
6697
6801
  if (cached) return cached;
6698
- const filePath = join5(dir, `${locale}.json`);
6699
- if (!existsSync4(filePath)) return {};
6802
+ const filePath = join6(dir, `${locale}.json`);
6803
+ if (!existsSync5(filePath)) return {};
6700
6804
  try {
6701
6805
  const content = await readFile2(filePath, "utf-8");
6702
6806
  const data = JSON.parse(content);
@@ -8116,102 +8220,6 @@ function registerWorker(url) {
8116
8220
  };
8117
8221
  }
8118
8222
 
8119
- // live.ts
8120
- import chokidar from "chokidar";
8121
- var clients2 = /* @__PURE__ */ new Set();
8122
- function broadcastReload() {
8123
- for (const ws of clients2) {
8124
- try {
8125
- ws.send("reload");
8126
- } catch {
8127
- clients2.delete(ws);
8128
- }
8129
- }
8130
- }
8131
- function liveReload(opts) {
8132
- const r = new Router();
8133
- r.ws("/__weifuwu/livereload", {
8134
- open(ws) {
8135
- clients2.add(ws);
8136
- ws.on("close", () => clients2.delete(ws));
8137
- ws.on("error", () => clients2.delete(ws));
8138
- }
8139
- });
8140
- const watcher = chokidar.watch(opts.dirs, {
8141
- ignored: /(^|[/\\])\.|node_modules|[/\\]\.weifuwu[/\\]/,
8142
- ignoreInitial: true
8143
- });
8144
- watcher.on("change", (path2) => {
8145
- if (!/\.tsx?$/.test(path2)) return;
8146
- clearCompileCache();
8147
- setTimeout(broadcastReload, 50);
8148
- });
8149
- r.close = () => {
8150
- watcher.close();
8151
- clients2.clear();
8152
- };
8153
- return r;
8154
- }
8155
-
8156
- // tailwind.ts
8157
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
8158
- import { relative, resolve as resolve12 } from "node:path";
8159
- var isDev2 = process.env.NODE_ENV !== "production";
8160
- function tailwind(cssPath, scanDir2) {
8161
- let compiledCss = "";
8162
- let twWatcher = null;
8163
- return async (req, ctx, next) => {
8164
- const url = new URL(req.url);
8165
- if (!compiledCss) {
8166
- compiledCss = await compile(cssPath, scanDir2);
8167
- }
8168
- if (url.pathname === "/__wfw/style.css") {
8169
- return new Response(compiledCss || "", {
8170
- headers: { "content-type": "text/css; charset=utf-8" }
8171
- });
8172
- }
8173
- ctx.compiledTailwindCss = compiledCss;
8174
- if (isDev2 && !twWatcher) {
8175
- twWatcher = watchFile(cssPath, () => {
8176
- compiledCss = "";
8177
- });
8178
- }
8179
- return next(req, ctx);
8180
- };
8181
- }
8182
- async function compile(cssPath, scanDir2) {
8183
- try {
8184
- const inputFile = resolve12(cssPath);
8185
- if (!existsSync5(inputFile)) {
8186
- mkdirSync3(dirname4(inputFile), { recursive: true });
8187
- writeFileSync3(inputFile, '@import "tailwindcss"\n', "utf-8");
8188
- }
8189
- const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
8190
- const { default: postcss } = await import("postcss");
8191
- let src = readFileSync5(inputFile, "utf-8");
8192
- const scanSource = scanDir2 ? relative(dirname4(inputFile), scanDir2) || "." : ".";
8193
- const sourcePath = scanSource === "." ? "./" : `./${scanSource}/`;
8194
- src = `@source "${sourcePath}";
8195
- ${src}`;
8196
- const result = await postcss([tailwindPlugin()]).process(src, { from: inputFile });
8197
- return result.css;
8198
- } catch (err) {
8199
- console.warn("Tailwind CSS processing failed:", err.message);
8200
- return "";
8201
- }
8202
- }
8203
- function dirname4(p) {
8204
- return p.substring(0, p.lastIndexOf("/")) || "/";
8205
- }
8206
- function watchFile(path2, onChange) {
8207
- let watcher = null;
8208
- import("chokidar").then((chokidar2) => {
8209
- watcher = chokidar2.default.watch(resolve12(path2), { persistent: false });
8210
- watcher.on("change", onChange);
8211
- });
8212
- return watcher;
8213
- }
8214
-
8215
8223
  // not-found.ts
8216
8224
  function notFound(path2) {
8217
8225
  return async (req, ctx) => {
package/dist/live.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Router } from './router.ts';
2
+ export declare function broadcastReload(): void;
2
3
  export declare function liveReload(opts: {
3
4
  dirs: string[];
4
5
  }): Router & {
@@ -1,2 +1,3 @@
1
1
  import type { Middleware } from './types.ts';
2
- export declare function tailwind(cssPath: string, scanDir?: string): Middleware;
2
+ export declare function addTailwindSource(dir: string): void;
3
+ export declare function tailwind(dir: string): Middleware;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weifuwu",
3
- "version": "0.18.9",
3
+ "version": "0.18.10",
4
4
  "description": "Web-standard HTTP framework for Node.js — (req, ctx) => Response",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",