mulmoterminal 0.1.3 → 0.2.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 +4 -0
- package/bin/mulmoterminal.js +18 -0
- package/bin/update-check.js +37 -0
- package/bin/update-check.spec.ts +46 -0
- package/dist/assets/index-BQpDgtuh.js +294 -0
- package/dist/assets/index-BTYOl3Xg.css +1 -0
- package/dist/assets/{marp-ByJn8N3A.js → marp-B0qDHvVn.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +10 -4
- package/plugins/plugins.json +2 -1
- package/server/backends/artifacts.ts +67 -0
- package/server/backends/collections.spec.ts +221 -0
- package/server/backends/collections.ts +410 -0
- package/server/backends/files.spec.ts +67 -0
- package/server/backends/files.ts +126 -0
- package/server/backends/html.spec.ts +85 -0
- package/server/backends/html.ts +119 -0
- package/server/backends/shortcuts.spec.ts +124 -0
- package/server/backends/shortcuts.ts +139 -0
- package/server/backends/viewToken.spec.ts +111 -0
- package/server/backends/viewToken.ts +101 -0
- package/server/claude-args.spec.ts +59 -0
- package/server/claude-args.ts +37 -0
- package/server/config-routes.ts +28 -0
- package/server/cwd-presets.spec.ts +54 -0
- package/server/cwd-presets.ts +44 -0
- package/server/host-tools.ts +4 -2
- package/server/index.ts +281 -79
- package/server/open-dir.spec.ts +14 -0
- package/server/open-dir.ts +46 -0
- package/server/plugins-registry.ts +83 -4
- package/server/transcript.spec.ts +73 -0
- package/server/transcript.ts +48 -0
- package/dist/assets/index-Bqu764bM.js +0 -186
- package/dist/assets/index-C8IoNzUa.css +0 -1
package/README.md
CHANGED
|
@@ -24,6 +24,10 @@ npm install -g mulmoterminal
|
|
|
24
24
|
mulmoterminal
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
A global install isn't auto-updated, so on startup MulmoTerminal checks npm and
|
|
28
|
+
prints a one-line notice when a newer version is available (`npm i -g mulmoterminal`
|
|
29
|
+
to update). Disable with `MULMOTERMINAL_NO_UPDATE_CHECK=1` (or `NO_UPDATE_NOTIFIER=1`).
|
|
30
|
+
|
|
27
31
|
Options: `--cwd <dir>` (working directory — relative paths allowed; defaults to the
|
|
28
32
|
directory you run the command from), `--port <n>` (default 3456), `--no-open`,
|
|
29
33
|
`--version`, `--help`.
|
package/bin/mulmoterminal.js
CHANGED
|
@@ -12,6 +12,7 @@ import { createRequire } from "node:module";
|
|
|
12
12
|
import { createServer } from "node:net";
|
|
13
13
|
import { dirname, join, resolve } from "node:path";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { fetchLatestVersion, isNewerVersion } from "./update-check.js";
|
|
15
16
|
|
|
16
17
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const PKG_DIR = join(__dirname, "..");
|
|
@@ -30,6 +31,21 @@ const { version: VERSION } = createRequire(import.meta.url)("../package.json");
|
|
|
30
31
|
const log = (msg) => console.log(`\x1b[36m[mulmoterminal]\x1b[0m ${msg}`);
|
|
31
32
|
const error = (msg) => console.error(`\x1b[31m[mulmoterminal]\x1b[0m ${msg}`);
|
|
32
33
|
|
|
34
|
+
// Non-blocking notice when a newer version is published — `npm i -g` never
|
|
35
|
+
// auto-updates. Opt out via MULMOTERMINAL_NO_UPDATE_CHECK / NO_UPDATE_NOTIFIER.
|
|
36
|
+
function checkForUpdate() {
|
|
37
|
+
if (process.env.MULMOTERMINAL_NO_UPDATE_CHECK || process.env.NO_UPDATE_NOTIFIER) return;
|
|
38
|
+
fetchLatestVersion()
|
|
39
|
+
.then((latest) => {
|
|
40
|
+
if (latest && isNewerVersion(latest, VERSION)) {
|
|
41
|
+
log(`\x1b[33mUpdate available: ${VERSION} → ${latest} · run: npm i -g mulmoterminal\x1b[0m`);
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
.catch(() => {
|
|
45
|
+
// best-effort; never disrupt startup
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
33
49
|
function claudeInstalled() {
|
|
34
50
|
try {
|
|
35
51
|
// Intentionally resolves `claude` from the user's PATH — detecting their
|
|
@@ -230,6 +246,8 @@ Options:
|
|
|
230
246
|
return;
|
|
231
247
|
}
|
|
232
248
|
|
|
249
|
+
checkForUpdate();
|
|
250
|
+
|
|
233
251
|
if (!claudeInstalled()) {
|
|
234
252
|
error("Claude Code CLI not found.");
|
|
235
253
|
error("Install it first: npm install -g @anthropic-ai/claude-code && claude auth login");
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Update-check helpers for the launcher, split out so the version comparison is
|
|
2
|
+
// unit-testable. Network calls are best-effort and never throw.
|
|
3
|
+
|
|
4
|
+
const REGISTRY = (process.env.npm_config_registry || "https://registry.npmjs.org").replace(/\/$/, "");
|
|
5
|
+
|
|
6
|
+
// Best-effort latest-version lookup. Resolves null on any failure (offline,
|
|
7
|
+
// timeout, non-OK, bad payload) so callers never block or break startup.
|
|
8
|
+
export async function fetchLatestVersion(pkg = "mulmoterminal") {
|
|
9
|
+
try {
|
|
10
|
+
const res = await fetch(`${REGISTRY}/${pkg}/latest`, {
|
|
11
|
+
signal: AbortSignal.timeout(1500),
|
|
12
|
+
headers: { accept: "application/json" },
|
|
13
|
+
});
|
|
14
|
+
if (!res.ok) return null;
|
|
15
|
+
const body = await res.json();
|
|
16
|
+
return typeof body.version === "string" ? body.version : null;
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// True if `latest` is a strictly newer major.minor.patch than `current`.
|
|
23
|
+
// Pre-release suffixes are ignored and parts are compared numerically (so
|
|
24
|
+
// 0.1.10 > 0.1.9, which a lexical compare would get wrong).
|
|
25
|
+
export function isNewerVersion(latest, current) {
|
|
26
|
+
const parts = (v) =>
|
|
27
|
+
String(v)
|
|
28
|
+
.split("-")[0]
|
|
29
|
+
.split(".")
|
|
30
|
+
.map((n) => Number.parseInt(n, 10) || 0);
|
|
31
|
+
const a = parts(latest);
|
|
32
|
+
const b = parts(current);
|
|
33
|
+
for (let i = 0; i < 3; i++) {
|
|
34
|
+
if ((a[i] ?? 0) !== (b[i] ?? 0)) return (a[i] ?? 0) > (b[i] ?? 0);
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { isNewerVersion, fetchLatestVersion } from "./update-check.js";
|
|
3
|
+
|
|
4
|
+
describe("isNewerVersion", () => {
|
|
5
|
+
const cases: [string, string, boolean][] = [
|
|
6
|
+
["0.1.3", "0.1.0", true],
|
|
7
|
+
["0.2.0", "0.1.9", true],
|
|
8
|
+
["1.0.0", "0.9.9", true],
|
|
9
|
+
["0.1.10", "0.1.9", true], // numeric, not lexical (the bug a string compare hits)
|
|
10
|
+
["0.1.3", "0.1.3", false],
|
|
11
|
+
["0.1.0", "0.1.3", false],
|
|
12
|
+
["0.9.9", "1.0.0", false],
|
|
13
|
+
["0.1.4-beta.1", "0.1.3", true], // pre-release suffix ignored on the core
|
|
14
|
+
["0.1.3", "0.1.3-beta.1", false], // equal core → not newer
|
|
15
|
+
];
|
|
16
|
+
it.each(cases)("isNewerVersion(%s, %s) === %s", (latest, current, expected) => {
|
|
17
|
+
expect(isNewerVersion(latest, current)).toBe(expected);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("fetchLatestVersion", () => {
|
|
22
|
+
const stubFetch = (impl: () => Promise<unknown>) => vi.stubGlobal("fetch", vi.fn(impl));
|
|
23
|
+
afterEach(() => vi.unstubAllGlobals());
|
|
24
|
+
|
|
25
|
+
it("returns the version from a 200 response", async () => {
|
|
26
|
+
stubFetch(async () => ({ ok: true, json: async () => ({ version: "1.2.3" }) }));
|
|
27
|
+
expect(await fetchLatestVersion()).toBe("1.2.3");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("returns null on a non-OK response", async () => {
|
|
31
|
+
stubFetch(async () => ({ ok: false, json: async () => ({}) }));
|
|
32
|
+
expect(await fetchLatestVersion()).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("returns null when fetch rejects (offline / timeout)", async () => {
|
|
36
|
+
stubFetch(async () => {
|
|
37
|
+
throw new Error("offline");
|
|
38
|
+
});
|
|
39
|
+
expect(await fetchLatestVersion()).toBeNull();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("returns null when the payload has no version string", async () => {
|
|
43
|
+
stubFetch(async () => ({ ok: true, json: async () => ({ name: "mulmoterminal" }) }));
|
|
44
|
+
expect(await fetchLatestVersion()).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
});
|