piclaw 0.0.13 → 0.0.14
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/.output/nitro.json +1 -1
- package/.output/public/assets/{defult-giDcMJuT.js → defult-hGXPebpx.js} +1 -1
- package/.output/public/assets/{dist-6l2bMalG.js → dist-BEy0WmVu.js} +1 -1
- package/.output/public/assets/{index-1zeVzeIQ.css → index-DIAPMG-u.css} +1 -1
- package/.output/public/assets/{index-DbZX-IVJ.js → index-pwr3Q8Ee.js} +4 -4
- package/.output/public/index.html +2 -2
- package/.output/server/_chunks/dummy.mjs +149 -0
- package/.output/server/_chunks/resource-manager.mjs +59 -16
- package/.output/server/_chunks/server.mjs +8 -0
- package/.output/server/_chunks/terminal.mjs +7 -2
- package/.output/server/index.mjs +55 -55
- package/bin/piclaw.mjs +6 -2
- package/package.json +1 -1
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
14
14
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
|
15
15
|
<link rel="manifest" href="/manifest.json" />
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-pwr3Q8Ee.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DIAPMG-u.css">
|
|
18
18
|
</head>
|
|
19
19
|
<body style="background-color: #0a0e14">
|
|
20
20
|
<div id="app"></div>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { a as __require } from "../_runtime.mjs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
/**
|
|
5
|
+
* Dummy PTY — fallback when no real PTY backend (Bun / node-pty) is available.
|
|
6
|
+
*
|
|
7
|
+
* Provides basic line-editing (backspace, Ctrl+C/D/L) and executes commands
|
|
8
|
+
* via `child_process.execFile` with a shell. No true PTY allocation — ANSI
|
|
9
|
+
* escape sequences from child processes won't work, but simple commands run fine.
|
|
10
|
+
*/
|
|
11
|
+
function spawnDummyPty(opts) {
|
|
12
|
+
const dataListeners = /* @__PURE__ */ new Set();
|
|
13
|
+
const exitListeners = /* @__PURE__ */ new Set();
|
|
14
|
+
let cwd = opts?.cwd ?? process.cwd();
|
|
15
|
+
const env = { ...opts?.env };
|
|
16
|
+
const shell = opts?.shell ?? process.env.SHELL ?? "/bin/sh";
|
|
17
|
+
let line = "";
|
|
18
|
+
let alive = true;
|
|
19
|
+
let busy = false;
|
|
20
|
+
let pending = "";
|
|
21
|
+
function emit(data) {
|
|
22
|
+
for (const cb of dataListeners) cb(data);
|
|
23
|
+
}
|
|
24
|
+
function prompt() {
|
|
25
|
+
const home = env.HOME || "";
|
|
26
|
+
emit(`\x1b[1;32m${home && cwd.startsWith(home) ? "~" + cwd.slice(home.length) : cwd}\x1b[0m $ `);
|
|
27
|
+
}
|
|
28
|
+
function exec(command) {
|
|
29
|
+
const trimmed = command.trim();
|
|
30
|
+
if (!trimmed) {
|
|
31
|
+
prompt();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const cdMatch = trimmed.match(/^cd\s*(.*)/);
|
|
35
|
+
if (cdMatch) {
|
|
36
|
+
const target = cdMatch[1]?.trim() || env.HOME || "/";
|
|
37
|
+
const resolved = target.startsWith("~") ? (env.HOME || "/") + target.slice(1) : path.resolve(cwd, target);
|
|
38
|
+
try {
|
|
39
|
+
if (!__require("node:fs").statSync(resolved).isDirectory()) emit(`\x1b[31mcd: not a directory: ${target}\x1b[0m\r\n`);
|
|
40
|
+
else cwd = resolved;
|
|
41
|
+
} catch {
|
|
42
|
+
emit(`\x1b[31mcd: no such directory: ${target}\x1b[0m\r\n`);
|
|
43
|
+
}
|
|
44
|
+
prompt();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const exportMatch = trimmed.match(/^export\s+(\w+)=(.*)/);
|
|
48
|
+
if (exportMatch) {
|
|
49
|
+
env[exportMatch[1]] = exportMatch[2].replace(/^["']|["']$/g, "");
|
|
50
|
+
prompt();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
busy = true;
|
|
54
|
+
execFile(shell, ["-c", trimmed], {
|
|
55
|
+
cwd,
|
|
56
|
+
env,
|
|
57
|
+
timeout: 3e4
|
|
58
|
+
}, (err, stdout, stderr) => {
|
|
59
|
+
if (!alive) return;
|
|
60
|
+
if (stderr) {
|
|
61
|
+
emit(`\x1b[31m${stderr.replaceAll("\n", "\r\n")}\x1b[0m`);
|
|
62
|
+
if (!stderr.endsWith("\n")) emit("\r\n");
|
|
63
|
+
}
|
|
64
|
+
if (stdout) {
|
|
65
|
+
emit(stdout.replaceAll("\n", "\r\n"));
|
|
66
|
+
if (!stdout.endsWith("\n")) emit("\r\n");
|
|
67
|
+
}
|
|
68
|
+
if (err && !stdout && !stderr) emit(`\x1b[31m${err.message}\x1b[0m\r\n`);
|
|
69
|
+
busy = false;
|
|
70
|
+
prompt();
|
|
71
|
+
if (pending) {
|
|
72
|
+
const queued = pending;
|
|
73
|
+
pending = "";
|
|
74
|
+
handle.write(queued);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
queueMicrotask(() => {
|
|
79
|
+
emit("\x1B[2m(dummy shell — no PTY; basic commands work, interactive programs may not)\x1B[0m\r\n");
|
|
80
|
+
prompt();
|
|
81
|
+
});
|
|
82
|
+
const handle = {
|
|
83
|
+
write(data) {
|
|
84
|
+
if (!alive) return;
|
|
85
|
+
if (busy) {
|
|
86
|
+
pending += data;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
for (const ch of data) switch (ch) {
|
|
90
|
+
case "\r":
|
|
91
|
+
case "\n": {
|
|
92
|
+
emit("\r\n");
|
|
93
|
+
const cmd = line;
|
|
94
|
+
line = "";
|
|
95
|
+
exec(cmd);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "":
|
|
99
|
+
case "\b":
|
|
100
|
+
if (line.length > 0) {
|
|
101
|
+
line = line.slice(0, -1);
|
|
102
|
+
emit("\b \b");
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case "":
|
|
106
|
+
line = "";
|
|
107
|
+
emit("^C\r\n");
|
|
108
|
+
prompt();
|
|
109
|
+
break;
|
|
110
|
+
case "":
|
|
111
|
+
if (line.length === 0) {
|
|
112
|
+
alive = false;
|
|
113
|
+
emit("\r\nexit\r\n");
|
|
114
|
+
for (const cb of exitListeners) cb();
|
|
115
|
+
dataListeners.clear();
|
|
116
|
+
exitListeners.clear();
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
case "\f":
|
|
120
|
+
emit("\x1B[2J\x1B[H");
|
|
121
|
+
prompt();
|
|
122
|
+
emit(line);
|
|
123
|
+
break;
|
|
124
|
+
default: if (ch >= " " || ch === " ") {
|
|
125
|
+
line += ch;
|
|
126
|
+
emit(ch);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
resize() {},
|
|
131
|
+
kill() {
|
|
132
|
+
if (!alive) return;
|
|
133
|
+
alive = false;
|
|
134
|
+
for (const cb of exitListeners) cb();
|
|
135
|
+
dataListeners.clear();
|
|
136
|
+
exitListeners.clear();
|
|
137
|
+
},
|
|
138
|
+
onData(cb) {
|
|
139
|
+
dataListeners.add(cb);
|
|
140
|
+
return () => dataListeners.delete(cb);
|
|
141
|
+
},
|
|
142
|
+
onExit(cb) {
|
|
143
|
+
exitListeners.add(cb);
|
|
144
|
+
return () => exitListeners.delete(cb);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
return handle;
|
|
148
|
+
}
|
|
149
|
+
export { spawnDummyPty };
|
|
@@ -37,15 +37,8 @@ var ResourceManager = class {
|
|
|
37
37
|
async getProcesses(opts) {
|
|
38
38
|
const sortBy = opts?.sortBy ?? "cpu";
|
|
39
39
|
const limit = Math.min(opts?.limit ?? 50, 200);
|
|
40
|
-
const sortFlag = sortBy === "ram" ? "-rss" : "-%cpu";
|
|
41
40
|
try {
|
|
42
|
-
const { stdout } = await execFileAsync("ps", [
|
|
43
|
-
"axo",
|
|
44
|
-
"pid,user,%cpu,rss,comm,args",
|
|
45
|
-
"--no-headers",
|
|
46
|
-
"--sort",
|
|
47
|
-
sortFlag
|
|
48
|
-
]);
|
|
41
|
+
const { stdout } = await execFileAsync("ps", ["axo", "pid,user,%cpu,rss,comm,args"]);
|
|
49
42
|
const results = [];
|
|
50
43
|
for (const line of stdout.split("\n")) {
|
|
51
44
|
const trimmed = line.trim();
|
|
@@ -53,12 +46,12 @@ var ResourceManager = class {
|
|
|
53
46
|
const parts = trimmed.split(/\s+/);
|
|
54
47
|
if (parts.length < 6) continue;
|
|
55
48
|
const pid = Number.parseInt(parts[0], 10);
|
|
49
|
+
if (Number.isNaN(pid)) continue;
|
|
56
50
|
const user = parts[1];
|
|
57
51
|
const cpu = Number.parseFloat(parts[2]);
|
|
58
52
|
const ram = Number.parseInt(parts[3], 10);
|
|
59
53
|
const name = parts[4];
|
|
60
54
|
const command = parts.slice(5).join(" ");
|
|
61
|
-
if (Number.isNaN(pid)) continue;
|
|
62
55
|
results.push({
|
|
63
56
|
pid,
|
|
64
57
|
user,
|
|
@@ -67,9 +60,9 @@ var ResourceManager = class {
|
|
|
67
60
|
name,
|
|
68
61
|
command
|
|
69
62
|
});
|
|
70
|
-
if (results.length >= limit) break;
|
|
71
63
|
}
|
|
72
|
-
|
|
64
|
+
results.sort((a, b) => sortBy === "ram" ? b.ram - a.ram : b.cpu - a.cpu);
|
|
65
|
+
return results.slice(0, limit);
|
|
73
66
|
} catch (err) {
|
|
74
67
|
logger.warn({ err }, "failed to get process list");
|
|
75
68
|
return [];
|
|
@@ -77,16 +70,40 @@ var ResourceManager = class {
|
|
|
77
70
|
}
|
|
78
71
|
async getPorts() {
|
|
79
72
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const { stdout: udpOut } = await execFileAsync("ss", ["-ulnpH"]);
|
|
83
|
-
const udpPorts = _parseSS(udpOut, "udp");
|
|
84
|
-
return [...tcpPorts, ...udpPorts].sort((a, b) => a.port - b.port);
|
|
73
|
+
if (process.platform === "darwin") return await this._getPortsLsof();
|
|
74
|
+
return await this._getPortsSS();
|
|
85
75
|
} catch (err) {
|
|
86
76
|
logger.warn({ err }, "failed to get listening ports");
|
|
87
77
|
return [];
|
|
88
78
|
}
|
|
89
79
|
}
|
|
80
|
+
async _getPortsSS() {
|
|
81
|
+
const { stdout } = await execFileAsync("ss", ["-tlnpH"]);
|
|
82
|
+
const tcpPorts = _parseSS(stdout, "tcp");
|
|
83
|
+
const { stdout: udpOut } = await execFileAsync("ss", ["-ulnpH"]);
|
|
84
|
+
const udpPorts = _parseSS(udpOut, "udp");
|
|
85
|
+
return [...tcpPorts, ...udpPorts].sort((a, b) => a.port - b.port);
|
|
86
|
+
}
|
|
87
|
+
async _getPortsLsof() {
|
|
88
|
+
const results = [];
|
|
89
|
+
const { stdout } = await execFileAsync("lsof", [
|
|
90
|
+
"-iTCP",
|
|
91
|
+
"-sTCP:LISTEN",
|
|
92
|
+
"-nP"
|
|
93
|
+
]);
|
|
94
|
+
for (const entry of _parseLsof(stdout)) results.push({
|
|
95
|
+
...entry,
|
|
96
|
+
protocol: "tcp"
|
|
97
|
+
});
|
|
98
|
+
try {
|
|
99
|
+
const { stdout: udpOut } = await execFileAsync("lsof", ["-iUDP", "-nP"]);
|
|
100
|
+
for (const entry of _parseLsof(udpOut)) results.push({
|
|
101
|
+
...entry,
|
|
102
|
+
protocol: "udp"
|
|
103
|
+
});
|
|
104
|
+
} catch {}
|
|
105
|
+
return results.sort((a, b) => a.port - b.port);
|
|
106
|
+
}
|
|
90
107
|
killProcess(pid, signal = "SIGTERM") {
|
|
91
108
|
if (pid === process.pid) throw new Error("cannot kill own process");
|
|
92
109
|
try {
|
|
@@ -244,4 +261,30 @@ function _parseSS(stdout, protocol) {
|
|
|
244
261
|
}
|
|
245
262
|
return results;
|
|
246
263
|
}
|
|
264
|
+
function _parseLsof(stdout) {
|
|
265
|
+
const results = [];
|
|
266
|
+
for (const line of stdout.split("\n")) {
|
|
267
|
+
const trimmed = line.trim();
|
|
268
|
+
if (!trimmed || trimmed.startsWith("COMMAND")) continue;
|
|
269
|
+
const parts = trimmed.split(/\s+/);
|
|
270
|
+
if (parts.length < 9) continue;
|
|
271
|
+
const processName = parts[0];
|
|
272
|
+
const pid = Number.parseInt(parts[1], 10);
|
|
273
|
+
const user = parts[2];
|
|
274
|
+
const name = parts[8];
|
|
275
|
+
const lastColon = name.lastIndexOf(":");
|
|
276
|
+
if (lastColon === -1) continue;
|
|
277
|
+
const address = name.slice(0, lastColon);
|
|
278
|
+
const port = Number.parseInt(name.slice(lastColon + 1), 10);
|
|
279
|
+
if (Number.isNaN(port)) continue;
|
|
280
|
+
results.push({
|
|
281
|
+
port,
|
|
282
|
+
address,
|
|
283
|
+
pid,
|
|
284
|
+
process: processName,
|
|
285
|
+
user
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
return results;
|
|
289
|
+
}
|
|
247
290
|
export { resourceManager as t };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { n as MAIN_GROUP_FOLDER, o as config, r as SESSIONS_DIR, t as GROUPS_DIR } from "./config.mjs";
|
|
2
2
|
import { t as createLogger } from "./logger.mjs";
|
|
3
3
|
import { t as streamBus } from "./stream.mjs";
|
|
4
|
+
import { a as resolveGroupModel } from "./session.mjs";
|
|
4
5
|
import { C as setSession, D as updateTaskAfterRun, S as setRouterState, T as storeMessage, _ as removeRegisteredGroup, b as setConfig, d as getMessagesSince, f as getNewMessages, g as logTaskRun, h as initDatabase, i as deleteConfig, l as getConfig, m as getTaskById, o as getAllRegisteredGroups, p as getRouterState, r as deleteChat, s as getAllSessions, u as getDueTasks, v as removeSession, w as storeChatMetadata, x as setRegisteredGroup, y as removeTasksByChat } from "./db.mjs";
|
|
5
6
|
import { t as terminalManager } from "./terminal.mjs";
|
|
6
7
|
import { n as pi_exports } from "./pi.mjs";
|
|
@@ -873,6 +874,13 @@ var PiClawServer = class {
|
|
|
873
874
|
if (!needsProcessing(group, agentMessages)) return true;
|
|
874
875
|
const prompt = formatMessages(agentMessages);
|
|
875
876
|
const lastMessageTimestamp = missedMessages[missedMessages.length - 1].timestamp;
|
|
877
|
+
if (!resolveGroupModel(group)) {
|
|
878
|
+
logger.warn({ group: group.name }, "No model available, notifying user");
|
|
879
|
+
await this.sendBotMessage(chatJid, "No AI model is currently available. Please configure a provider API key or log in via the admin panel.");
|
|
880
|
+
this.lastAgentTimestamp[chatJid] = lastMessageTimestamp;
|
|
881
|
+
await this.saveState();
|
|
882
|
+
return true;
|
|
883
|
+
}
|
|
876
884
|
logger.info({
|
|
877
885
|
group: group.name,
|
|
878
886
|
messageCount: missedMessages.length
|
|
@@ -7,8 +7,13 @@ async function spawnPty(opts) {
|
|
|
7
7
|
const { spawnBunPty } = await import("./bun.mjs");
|
|
8
8
|
return spawnBunPty(opts);
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
try {
|
|
11
|
+
const { spawnNodePty } = await import("./node.mjs");
|
|
12
|
+
return spawnNodePty(opts);
|
|
13
|
+
} catch {
|
|
14
|
+
const { spawnDummyPty } = await import("./dummy.mjs");
|
|
15
|
+
return spawnDummyPty(opts);
|
|
16
|
+
}
|
|
12
17
|
}
|
|
13
18
|
async function spawnVirtualPty(...args) {
|
|
14
19
|
const { spawnVirtualPty: fn } = await import("./virtual.mjs");
|
package/.output/server/index.mjs
CHANGED
|
@@ -80,121 +80,121 @@ var public_assets_data_default = {
|
|
|
80
80
|
"/icon.svg": {
|
|
81
81
|
"type": "image/svg+xml",
|
|
82
82
|
"etag": "\"41a-ki4Lp5uMw3sCqMRSciVIHajM4ps\"",
|
|
83
|
-
"mtime": "2026-03-03T20:
|
|
83
|
+
"mtime": "2026-03-03T20:53:42.168Z",
|
|
84
84
|
"size": 1050,
|
|
85
85
|
"path": "../public/icon.svg"
|
|
86
86
|
},
|
|
87
|
-
"/index.html": {
|
|
88
|
-
"type": "text/html; charset=utf-8",
|
|
89
|
-
"etag": "\"381-6l9MPgXUJXTjzzmJEmsjNQOwMR0\"",
|
|
90
|
-
"mtime": "2026-03-03T20:28:18.245Z",
|
|
91
|
-
"size": 897,
|
|
92
|
-
"path": "../public/index.html"
|
|
93
|
-
},
|
|
94
|
-
"/manifest.json": {
|
|
95
|
-
"type": "application/json",
|
|
96
|
-
"etag": "\"14e-DvUgXsoYV0AGNrrrXwbASbqGR5g\"",
|
|
97
|
-
"mtime": "2026-03-03T20:28:18.281Z",
|
|
98
|
-
"size": 334,
|
|
99
|
-
"path": "../public/manifest.json"
|
|
100
|
-
},
|
|
101
|
-
"/sw.js": {
|
|
102
|
-
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": "\"765-FHQ7M5HcgHxyZi8sVv0/baOJWD8\"",
|
|
104
|
-
"mtime": "2026-03-03T20:28:18.281Z",
|
|
105
|
-
"size": 1893,
|
|
106
|
-
"path": "../public/sw.js"
|
|
107
|
-
},
|
|
108
87
|
"/assets/GeistPixel-Square-CwnHaJd_.woff2": {
|
|
109
88
|
"type": "font/woff2",
|
|
110
89
|
"etag": "\"6fc8-Nl3X3tuURsyt3ex8iF9PBK3Fymk\"",
|
|
111
|
-
"mtime": "2026-03-03T20:
|
|
90
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
112
91
|
"size": 28616,
|
|
113
92
|
"path": "../public/assets/GeistPixel-Square-CwnHaJd_.woff2"
|
|
114
93
|
},
|
|
115
|
-
"/assets/defult-
|
|
94
|
+
"/assets/defult-hGXPebpx.js": {
|
|
116
95
|
"type": "text/javascript; charset=utf-8",
|
|
117
|
-
"etag": "\"5be-
|
|
118
|
-
"mtime": "2026-03-03T20:
|
|
96
|
+
"etag": "\"5be-RUGI/yhdf3kyd8BTrPT8CnPO/MM\"",
|
|
97
|
+
"mtime": "2026-03-03T20:53:42.113Z",
|
|
119
98
|
"size": 1470,
|
|
120
|
-
"path": "../public/assets/defult-
|
|
121
|
-
},
|
|
122
|
-
"/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2": {
|
|
123
|
-
"type": "font/woff2",
|
|
124
|
-
"etag": "\"3bcc-oSFlPnDlb7fAcQTPv6sqm6NgXXU\"",
|
|
125
|
-
"mtime": "2026-03-03T20:28:18.245Z",
|
|
126
|
-
"size": 15308,
|
|
127
|
-
"path": "../public/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2"
|
|
99
|
+
"path": "../public/assets/defult-hGXPebpx.js"
|
|
128
100
|
},
|
|
129
101
|
"/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2": {
|
|
130
102
|
"type": "font/woff2",
|
|
131
103
|
"etag": "\"3964-jfUkxTfHRj1cpO33jEsDk2lkrvM\"",
|
|
132
|
-
"mtime": "2026-03-03T20:
|
|
104
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
133
105
|
"size": 14692,
|
|
134
106
|
"path": "../public/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2"
|
|
135
107
|
},
|
|
108
|
+
"/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2": {
|
|
109
|
+
"type": "font/woff2",
|
|
110
|
+
"etag": "\"3bcc-oSFlPnDlb7fAcQTPv6sqm6NgXXU\"",
|
|
111
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
112
|
+
"size": 15308,
|
|
113
|
+
"path": "../public/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2"
|
|
114
|
+
},
|
|
136
115
|
"/assets/geist-latin-wght-normal-Dm3htQBi.woff2": {
|
|
137
116
|
"type": "font/woff2",
|
|
138
117
|
"etag": "\"6ef0-pZqr0k2V92t+lxQ/ogxqTIOgDGM\"",
|
|
139
|
-
"mtime": "2026-03-03T20:
|
|
118
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
140
119
|
"size": 28400,
|
|
141
120
|
"path": "../public/assets/geist-latin-wght-normal-Dm3htQBi.woff2"
|
|
142
121
|
},
|
|
143
122
|
"/assets/geist-mono-cyrillic-wght-normal-BZdD_g9V.woff2": {
|
|
144
123
|
"type": "font/woff2",
|
|
145
124
|
"etag": "\"3148-fDEowP3hdBu549ke2NSllgnKwFo\"",
|
|
146
|
-
"mtime": "2026-03-03T20:
|
|
125
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
147
126
|
"size": 12616,
|
|
148
127
|
"path": "../public/assets/geist-mono-cyrillic-wght-normal-BZdD_g9V.woff2"
|
|
149
128
|
},
|
|
150
129
|
"/assets/geist-mono-latin-ext-wght-normal-b6lpi8_2.woff2": {
|
|
151
130
|
"type": "font/woff2",
|
|
152
131
|
"etag": "\"32f4-mFhyUXRKosFvmVg6XWwBAV3kvk4\"",
|
|
153
|
-
"mtime": "2026-03-03T20:
|
|
132
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
154
133
|
"size": 13044,
|
|
155
134
|
"path": "../public/assets/geist-mono-latin-ext-wght-normal-b6lpi8_2.woff2"
|
|
156
135
|
},
|
|
157
136
|
"/assets/geist-mono-latin-wght-normal-Cjtb1TV-.woff2": {
|
|
158
137
|
"type": "font/woff2",
|
|
159
138
|
"etag": "\"7a88-DQWpi033XojA2ZmNMyp8i2zZURE\"",
|
|
160
|
-
"mtime": "2026-03-03T20:
|
|
139
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
161
140
|
"size": 31368,
|
|
162
141
|
"path": "../public/assets/geist-mono-latin-wght-normal-Cjtb1TV-.woff2"
|
|
163
142
|
},
|
|
164
|
-
"/assets/index-
|
|
143
|
+
"/assets/index-DIAPMG-u.css": {
|
|
165
144
|
"type": "text/css; charset=utf-8",
|
|
166
|
-
"etag": "\"
|
|
167
|
-
"mtime": "2026-03-03T20:
|
|
168
|
-
"size":
|
|
169
|
-
"path": "../public/assets/index-
|
|
145
|
+
"etag": "\"f763-sz5YAC0HyCnTjJ2c6usb03qpBAw\"",
|
|
146
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
147
|
+
"size": 63331,
|
|
148
|
+
"path": "../public/assets/index-DIAPMG-u.css"
|
|
170
149
|
},
|
|
171
150
|
"/assets/md4x-CNLJ57xO.wasm": {
|
|
172
151
|
"type": "application/wasm",
|
|
173
152
|
"etag": "\"41116-fXWw13Hb4mtmx1zqWY937G5o04w\"",
|
|
174
|
-
"mtime": "2026-03-03T20:
|
|
153
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
175
154
|
"size": 266518,
|
|
176
155
|
"path": "../public/assets/md4x-CNLJ57xO.wasm"
|
|
177
156
|
},
|
|
178
157
|
"/assets/md4x-CyfQToGJ.js": {
|
|
179
158
|
"type": "text/javascript; charset=utf-8",
|
|
180
159
|
"etag": "\"38-QLTgoA+K9j0djblpu5tawfdfO5c\"",
|
|
181
|
-
"mtime": "2026-03-03T20:
|
|
160
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
182
161
|
"size": 56,
|
|
183
162
|
"path": "../public/assets/md4x-CyfQToGJ.js"
|
|
184
163
|
},
|
|
185
|
-
"/
|
|
164
|
+
"/index.html": {
|
|
165
|
+
"type": "text/html; charset=utf-8",
|
|
166
|
+
"etag": "\"381-yBM/ZxljxEUxXkxP0J20jLqkGlg\"",
|
|
167
|
+
"mtime": "2026-03-03T20:53:42.114Z",
|
|
168
|
+
"size": 897,
|
|
169
|
+
"path": "../public/index.html"
|
|
170
|
+
},
|
|
171
|
+
"/assets/index-pwr3Q8Ee.js": {
|
|
186
172
|
"type": "text/javascript; charset=utf-8",
|
|
187
|
-
"etag": "\"
|
|
188
|
-
"mtime": "2026-03-03T20:
|
|
189
|
-
"size":
|
|
190
|
-
"path": "../public/assets/index-
|
|
173
|
+
"etag": "\"a6c43-rJ80bItOKiQbrver0cHvfNUQslc\"",
|
|
174
|
+
"mtime": "2026-03-03T20:53:42.112Z",
|
|
175
|
+
"size": 683075,
|
|
176
|
+
"path": "../public/assets/index-pwr3Q8Ee.js"
|
|
177
|
+
},
|
|
178
|
+
"/manifest.json": {
|
|
179
|
+
"type": "application/json",
|
|
180
|
+
"etag": "\"14e-DvUgXsoYV0AGNrrrXwbASbqGR5g\"",
|
|
181
|
+
"mtime": "2026-03-03T20:53:42.168Z",
|
|
182
|
+
"size": 334,
|
|
183
|
+
"path": "../public/manifest.json"
|
|
184
|
+
},
|
|
185
|
+
"/sw.js": {
|
|
186
|
+
"type": "text/javascript; charset=utf-8",
|
|
187
|
+
"etag": "\"765-FHQ7M5HcgHxyZi8sVv0/baOJWD8\"",
|
|
188
|
+
"mtime": "2026-03-03T20:53:42.168Z",
|
|
189
|
+
"size": 1893,
|
|
190
|
+
"path": "../public/sw.js"
|
|
191
191
|
},
|
|
192
|
-
"/assets/dist-
|
|
192
|
+
"/assets/dist-BEy0WmVu.js": {
|
|
193
193
|
"type": "text/javascript; charset=utf-8",
|
|
194
|
-
"etag": "\"16e8b9-
|
|
195
|
-
"mtime": "2026-03-03T20:
|
|
194
|
+
"etag": "\"16e8b9-Y1r1XYEfvzMzSrI+11dHfqZpFfY\"",
|
|
195
|
+
"mtime": "2026-03-03T20:53:42.113Z",
|
|
196
196
|
"size": 1501369,
|
|
197
|
-
"path": "../public/assets/dist-
|
|
197
|
+
"path": "../public/assets/dist-BEy0WmVu.js"
|
|
198
198
|
}
|
|
199
199
|
};
|
|
200
200
|
function readAsset(id) {
|
package/bin/piclaw.mjs
CHANGED
|
@@ -36,6 +36,8 @@ ${bold("Options:")}
|
|
|
36
36
|
|
|
37
37
|
const port = Number(values.port || process.env.PORT || 3737);
|
|
38
38
|
|
|
39
|
+
const isWebContainer = process.env.SHELL === "/bin/jsh" || !!process.versions?.webcontainer;
|
|
40
|
+
|
|
39
41
|
/** Check if a port is already listening on localhost */
|
|
40
42
|
function isPortOpen(port) {
|
|
41
43
|
return new Promise((resolve) => {
|
|
@@ -60,7 +62,8 @@ if (await isPortOpen(port)) {
|
|
|
60
62
|
);
|
|
61
63
|
|
|
62
64
|
// Preflight: need node:sqlite (Node ≥ 22.5) or sqlite3
|
|
63
|
-
|
|
65
|
+
// Skip in StackBlitz/WebContainer — it provides its own SQLite
|
|
66
|
+
if (!("Bun" in globalThis) && !isWebContainer) {
|
|
64
67
|
let hasSqlite = false;
|
|
65
68
|
try {
|
|
66
69
|
await import("node:sqlite");
|
|
@@ -92,7 +95,8 @@ if (await isPortOpen(port)) {
|
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
// Open browser in app mode (chromeless window, no toolbar/tabs)
|
|
95
|
-
|
|
98
|
+
// Skip in StackBlitz/WebContainer — browser is already embedded
|
|
99
|
+
if (serverUrl && !values["no-open"] && !isWebContainer) {
|
|
96
100
|
const { exec } = await import("node:child_process");
|
|
97
101
|
const url = new URL(serverUrl);
|
|
98
102
|
if (["::", "127.0.0.1", "localhost"].includes(url.hostname)) {
|