@xbghc/warden 0.2.0 → 0.3.0
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
|
@@ -134,7 +134,8 @@ branch name, plus mtime and size of the paths status reports — enough to notic
|
|
|
134
134
|
already-modified file) and pushes a change event over `GET /api/events` (SSE). The page then re-runs
|
|
135
135
|
the normal refresh: re-anchor, reload both file lists, reload the open diff. Your draft comment,
|
|
136
136
|
selection, current view and current file are left alone, and the diff is scrolled back to where you
|
|
137
|
-
were reading. Turn it off with the
|
|
137
|
+
were reading. Turn it off with the *自动* toggle next to the refresh button; `r` still
|
|
138
|
+
refreshes by hand.
|
|
138
139
|
|
|
139
140
|
## Todos
|
|
140
141
|
|
|
@@ -226,11 +227,12 @@ Only `dist/`, `README.md`, `LICENSE` and `package.json` are published.
|
|
|
226
227
|
|
|
227
228
|
Releasing: bump `version` in `package.json`, commit, then push a matching tag —
|
|
228
229
|
`git tag v0.2.0 && git push origin v0.2.0`. The `Publish to npm` workflow checks the tag against the
|
|
229
|
-
version, runs build + tests through `prepublishOnly`, and publishes over OIDC trusted publishing —
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
`
|
|
233
|
-
|
|
230
|
+
version, runs build + tests through `prepublishOnly`, and publishes over OIDC trusted publishing — no
|
|
231
|
+
`NPM_TOKEN` secret to store or rotate. It relies on a trusted publisher configured on the package's
|
|
232
|
+
npmjs.com settings page (user `xbghc`, repo `warden`, workflow `publish.yml`), and passes
|
|
233
|
+
`--provenance` explicitly, because npm's automatic attestation does not fire through `pnpm publish`
|
|
234
|
+
(0.2.0 shipped without one). CI runs typecheck, tests, build and a `publish --dry-run` on every push
|
|
235
|
+
to `main` and every pull request.
|
|
234
236
|
|
|
235
237
|
## License
|
|
236
238
|
|
package/dist/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ import { fileURLToPath } from "url";
|
|
|
8
8
|
|
|
9
9
|
// packages/server/src/index.ts
|
|
10
10
|
import net from "net";
|
|
11
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
11
12
|
|
|
12
13
|
// node_modules/.pnpm/@hono+node-server@1.19.17_hono@4.13.7/node_modules/@hono/node-server/dist/index.mjs
|
|
13
14
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -4246,6 +4247,7 @@ function createApp(opts) {
|
|
|
4246
4247
|
return c.json({ error: err instanceof Error ? err.message : String(err), code: "internal" }, 500);
|
|
4247
4248
|
});
|
|
4248
4249
|
const api = new Hono2();
|
|
4250
|
+
api.get("/ping", (c) => c.text(opts.instanceToken ?? ""));
|
|
4249
4251
|
api.get("/repo", async (c) => {
|
|
4250
4252
|
const state = await store.load();
|
|
4251
4253
|
const info = await getRepoInfo(repo, state.prefs.lastTarget ?? "working");
|
|
@@ -4800,6 +4802,37 @@ function createApp(opts) {
|
|
|
4800
4802
|
return app;
|
|
4801
4803
|
}
|
|
4802
4804
|
|
|
4805
|
+
// packages/server/src/wsl.ts
|
|
4806
|
+
import { execFile as execFile3 } from "child_process";
|
|
4807
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
4808
|
+
var PROBE_TIMEOUT_MS = 3e3;
|
|
4809
|
+
async function isWsl(env = process.env, platform = process.platform) {
|
|
4810
|
+
if (platform !== "linux") return false;
|
|
4811
|
+
if (env.WSL_DISTRO_NAME || env.WSL_INTEROP) return true;
|
|
4812
|
+
try {
|
|
4813
|
+
return /microsoft/i.test(await readFile4("/proc/sys/kernel/osrelease", "utf8"));
|
|
4814
|
+
} catch {
|
|
4815
|
+
return false;
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
function reachableFromWindows(port, token, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
4819
|
+
return new Promise((resolve) => {
|
|
4820
|
+
execFile3(
|
|
4821
|
+
"curl.exe",
|
|
4822
|
+
["--silent", "--max-time", String(Math.ceil(timeoutMs / 1e3)), `http://127.0.0.1:${port}/api/ping`],
|
|
4823
|
+
{ timeout: timeoutMs + 1e3, encoding: "utf8", windowsHide: true },
|
|
4824
|
+
(error, stdout) => {
|
|
4825
|
+
const code = error?.code;
|
|
4826
|
+
if (typeof code === "string") {
|
|
4827
|
+
resolve(void 0);
|
|
4828
|
+
return;
|
|
4829
|
+
}
|
|
4830
|
+
resolve(stdout.trim() === token);
|
|
4831
|
+
}
|
|
4832
|
+
);
|
|
4833
|
+
});
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4803
4836
|
// packages/server/src/index.ts
|
|
4804
4837
|
var HOST = "127.0.0.1";
|
|
4805
4838
|
var DEFAULT_PORT_START = 4100;
|
|
@@ -4818,35 +4851,56 @@ async function findFreePort(start = DEFAULT_PORT_START, host = HOST) {
|
|
|
4818
4851
|
}
|
|
4819
4852
|
throw new Error(`no free port found starting at ${start}`);
|
|
4820
4853
|
}
|
|
4854
|
+
var PROBE_ATTEMPTS = 5;
|
|
4821
4855
|
async function startServer(opts) {
|
|
4822
4856
|
const repo = await resolveRepo(opts.repoPath);
|
|
4823
4857
|
const stateFile = opts.stateFile ?? stateFilePath(repo.commonRoot);
|
|
4824
4858
|
const store = new StateStore(stateFile, repo.commonRoot);
|
|
4825
|
-
const
|
|
4859
|
+
const instanceToken = randomUUID2();
|
|
4860
|
+
const app = createApp({ repo, store, nvim: new NvimService(), webDir: opts.webDir, instanceToken });
|
|
4861
|
+
const listen = (p) => new Promise((resolve, reject) => {
|
|
4862
|
+
const s = serve({ fetch: app.fetch, hostname: HOST, port: p }, () => resolve(s));
|
|
4863
|
+
s.once("error", reject);
|
|
4864
|
+
});
|
|
4865
|
+
const stop = (s) => new Promise((resolve, reject) => {
|
|
4866
|
+
s.close((err) => err ? reject(err) : resolve());
|
|
4867
|
+
if ("closeAllConnections" in s) s.closeAllConnections();
|
|
4868
|
+
});
|
|
4826
4869
|
let port;
|
|
4870
|
+
let server;
|
|
4871
|
+
const skippedPorts = [];
|
|
4872
|
+
let windowsReachable;
|
|
4827
4873
|
if (opts.port !== void 0) {
|
|
4828
4874
|
if (!await isPortFree(opts.port)) throw new Error(`port ${opts.port} is already in use`);
|
|
4829
4875
|
port = opts.port;
|
|
4876
|
+
server = await listen(port);
|
|
4830
4877
|
} else {
|
|
4831
|
-
|
|
4878
|
+
const probe = opts.probeWindows ?? (await isWsl() ? reachableFromWindows : void 0);
|
|
4879
|
+
let start = DEFAULT_PORT_START;
|
|
4880
|
+
for (let attempt = 1; ; attempt++) {
|
|
4881
|
+
port = await findFreePort(start);
|
|
4882
|
+
server = await listen(port);
|
|
4883
|
+
if (!probe) break;
|
|
4884
|
+
windowsReachable = await probe(port, instanceToken);
|
|
4885
|
+
if (windowsReachable !== false || attempt >= PROBE_ATTEMPTS) break;
|
|
4886
|
+
await stop(server);
|
|
4887
|
+
skippedPorts.push(port);
|
|
4888
|
+
start = port + 1;
|
|
4889
|
+
}
|
|
4832
4890
|
}
|
|
4833
|
-
const server = await new Promise((resolve, reject) => {
|
|
4834
|
-
const s = serve({ fetch: app.fetch, hostname: HOST, port }, () => resolve(s));
|
|
4835
|
-
s.once("error", reject);
|
|
4836
|
-
});
|
|
4837
4891
|
return {
|
|
4838
4892
|
url: `http://${HOST}:${port}/`,
|
|
4839
4893
|
port,
|
|
4840
4894
|
repo,
|
|
4841
4895
|
stateFile,
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4896
|
+
skippedPorts,
|
|
4897
|
+
windowsReachable,
|
|
4898
|
+
close: () => stop(server)
|
|
4845
4899
|
};
|
|
4846
4900
|
}
|
|
4847
4901
|
|
|
4848
4902
|
// bin/cli.ts
|
|
4849
|
-
var VERSION = true ? "0.
|
|
4903
|
+
var VERSION = true ? "0.3.0" : "dev";
|
|
4850
4904
|
function parseArgs(argv) {
|
|
4851
4905
|
const args = { repoPath: process.cwd(), open: true, help: false, version: false };
|
|
4852
4906
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -4874,7 +4928,8 @@ function usage() {
|
|
|
4874
4928
|
Usage: warden [repoPath] [options]
|
|
4875
4929
|
|
|
4876
4930
|
Options:
|
|
4877
|
-
--port <n>, -p <n> Listen on a fixed port (default: first free port from 4100
|
|
4931
|
+
--port <n>, -p <n> Listen on a fixed port (default: first free port from 4100, and under WSL
|
|
4932
|
+
the first one the Windows side can reach)
|
|
4878
4933
|
--no-open Do not try to open the browser
|
|
4879
4934
|
-h, --help Show this help
|
|
4880
4935
|
-v, --version Print version
|
|
@@ -4951,6 +5006,14 @@ async function main() {
|
|
|
4951
5006
|
console.log(` repo: ${server.repo.root}`);
|
|
4952
5007
|
console.log(` state: ${server.stateFile}`);
|
|
4953
5008
|
console.log(` url: ${server.url}`);
|
|
5009
|
+
if (server.skippedPorts.length > 0) {
|
|
5010
|
+
const ports = server.skippedPorts.join(", ");
|
|
5011
|
+
const plural = server.skippedPorts.length > 1 ? "s" : "";
|
|
5012
|
+
console.log(` note: skipped port${plural} ${ports} \u2014 the WSL2 localhost relay does not publish ${plural ? "them" : "it"} to Windows`);
|
|
5013
|
+
}
|
|
5014
|
+
if (server.windowsReachable === false) {
|
|
5015
|
+
console.error(`warning: Windows cannot reach ${server.url} either. Run with --port <n> to pick a port it can publish.`);
|
|
5016
|
+
}
|
|
4954
5017
|
if (args.open) {
|
|
4955
5018
|
const opened = await openBrowser(server.url);
|
|
4956
5019
|
if (!opened) console.log(" (could not open a browser automatically; open the URL manually)");
|