piclaw 0.0.4 → 0.0.6
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/dist-D51xeTP2.js +12 -0
- package/.output/public/assets/index-B3x2_en6.css +1 -0
- package/.output/public/assets/index-SfjxJZSD.js +38 -0
- package/.output/public/assets/md4x-CNLJ57xO.wasm +0 -0
- package/.output/public/assets/md4x-CyfQToGJ.js +1 -0
- package/.output/public/assets/wasm-Cm7RZrwg.js +1 -0
- package/.output/public/icon.svg +25 -0
- package/.output/public/index.html +3 -2
- package/.output/public/manifest.json +1 -1
- package/.output/server/_chunks/bun.mjs +49 -0
- package/.output/server/_chunks/commands.mjs +280 -0
- package/.output/server/_chunks/config.mjs +2 -4
- package/.output/server/_chunks/db.mjs +11 -5
- package/.output/server/_chunks/logger.mjs +1 -1
- package/.output/server/_chunks/node.mjs +31 -0
- package/.output/server/_chunks/ntfy.mjs +45 -0
- package/.output/server/_chunks/pi.mjs +33 -1
- package/.output/server/_chunks/renderer-template.mjs +1 -1
- package/.output/server/_chunks/{bootstrap.mjs → server.mjs} +203 -205
- package/.output/server/_chunks/session.mjs +249 -40
- package/.output/server/_chunks/settings.mjs +1 -1
- package/.output/server/_chunks/terminal.mjs +35 -20
- package/.output/server/_chunks/virtual.mjs +129 -0
- package/.output/server/_jid_.delete.mjs +2 -2
- package/.output/server/_jid_.patch.mjs +30 -3
- package/.output/server/_jid_2.delete.mjs +2 -2
- package/.output/server/_libs/@aws-sdk/client-bedrock-runtime+[...].mjs +13148 -13149
- package/.output/server/_libs/@aws-sdk/credential-provider-http+[...].mjs +1 -1
- package/.output/server/_libs/@aws-sdk/credential-provider-ini+[...].mjs +2 -2
- package/.output/server/_libs/@aws-sdk/credential-provider-process+[...].mjs +1 -1
- package/.output/server/_libs/@aws-sdk/credential-provider-sso+[...].mjs +1 -1
- package/.output/server/_libs/@aws-sdk/credential-provider-web-identity+[...].mjs +1 -1
- package/.output/server/_libs/@google/genai.mjs +2 -2
- package/.output/server/_libs/@mariozechner/pi-agent-core+[...].mjs +40 -74
- package/.output/server/_libs/@mariozechner/pi-coding-agent+[...].mjs +1315 -1210
- package/.output/server/_libs/@smithy/credential-provider-imds+[...].mjs +3 -3
- package/.output/server/_libs/_.mjs +3 -2
- package/.output/server/_libs/_100.mjs +3 -0
- package/.output/server/_libs/_101.mjs +2 -0
- package/.output/server/_libs/_102.mjs +3 -0
- package/.output/server/_libs/_103.mjs +2 -0
- package/.output/server/_libs/_16.mjs +2 -5
- package/.output/server/_libs/_17.mjs +2 -3
- package/.output/server/_libs/_18.mjs +2 -3
- package/.output/server/_libs/_19.mjs +2 -4
- package/.output/server/_libs/_2.mjs +2 -3
- package/.output/server/_libs/_20.mjs +2 -2
- package/.output/server/_libs/_21.mjs +2 -0
- package/.output/server/_libs/_22.mjs +2 -0
- package/.output/server/_libs/_23.mjs +2 -0
- package/.output/server/_libs/_24.mjs +2 -0
- package/.output/server/_libs/_25.mjs +2 -0
- package/.output/server/_libs/_26.mjs +2 -0
- package/.output/server/_libs/_27.mjs +2 -0
- package/.output/server/_libs/_28.mjs +2 -0
- package/.output/server/_libs/_29.mjs +2 -0
- package/.output/server/_libs/_30.mjs +2 -0
- package/.output/server/_libs/_31.mjs +2 -0
- package/.output/server/_libs/_32.mjs +2 -0
- package/.output/server/_libs/_33.mjs +2 -0
- package/.output/server/_libs/_34.mjs +2 -0
- package/.output/server/_libs/_35.mjs +2 -0
- package/.output/server/_libs/_36.mjs +2 -0
- package/.output/server/_libs/_37.mjs +2 -0
- package/.output/server/_libs/_38.mjs +2 -0
- package/.output/server/_libs/_39.mjs +2 -0
- package/.output/server/_libs/_40.mjs +2 -0
- package/.output/server/_libs/_41.mjs +2 -0
- package/.output/server/_libs/_42.mjs +2 -0
- package/.output/server/_libs/_43.mjs +2 -0
- package/.output/server/_libs/_44.mjs +2 -0
- package/.output/server/_libs/_45.mjs +2 -0
- package/.output/server/_libs/_46.mjs +2 -0
- package/.output/server/_libs/_47.mjs +2 -0
- package/.output/server/_libs/_48.mjs +2 -0
- package/.output/server/_libs/_49.mjs +2 -0
- package/.output/server/_libs/_50.mjs +2 -0
- package/.output/server/_libs/_51.mjs +2 -0
- package/.output/server/_libs/_52.mjs +2 -0
- package/.output/server/_libs/_53.mjs +2 -0
- package/.output/server/_libs/_54.mjs +2 -0
- package/.output/server/_libs/_55.mjs +2 -0
- package/.output/server/_libs/_56.mjs +2 -0
- package/.output/server/_libs/_57.mjs +2 -0
- package/.output/server/_libs/_58.mjs +2 -0
- package/.output/server/_libs/_59.mjs +2 -0
- package/.output/server/_libs/_60.mjs +2 -0
- package/.output/server/_libs/_61.mjs +2 -0
- package/.output/server/_libs/_62.mjs +2 -0
- package/.output/server/_libs/_63.mjs +2 -0
- package/.output/server/_libs/_64.mjs +2 -0
- package/.output/server/_libs/_65.mjs +2 -0
- package/.output/server/_libs/_66.mjs +2 -0
- package/.output/server/_libs/_67.mjs +2 -0
- package/.output/server/_libs/_68.mjs +2 -0
- package/.output/server/_libs/_69.mjs +2 -0
- package/.output/server/_libs/_70.mjs +2 -0
- package/.output/server/_libs/_71.mjs +2 -0
- package/.output/server/_libs/_72.mjs +2 -0
- package/.output/server/_libs/_73.mjs +2 -0
- package/.output/server/_libs/_74.mjs +2 -0
- package/.output/server/_libs/_75.mjs +2 -0
- package/.output/server/_libs/_76.mjs +2 -0
- package/.output/server/_libs/_77.mjs +2 -0
- package/.output/server/_libs/_78.mjs +2 -0
- package/.output/server/_libs/_79.mjs +2 -0
- package/.output/server/_libs/_80.mjs +2 -0
- package/.output/server/_libs/_81.mjs +2 -0
- package/.output/server/_libs/_82.mjs +2 -0
- package/.output/server/_libs/_83.mjs +2 -0
- package/.output/server/_libs/_84.mjs +2 -0
- package/.output/server/_libs/_85.mjs +2 -0
- package/.output/server/_libs/_86.mjs +2 -0
- package/.output/server/_libs/_87.mjs +2 -0
- package/.output/server/_libs/_88.mjs +2 -0
- package/.output/server/_libs/_89.mjs +2 -0
- package/.output/server/_libs/_90.mjs +2 -0
- package/.output/server/_libs/_91.mjs +2 -0
- package/.output/server/_libs/_92.mjs +2 -0
- package/.output/server/_libs/_93.mjs +2 -0
- package/.output/server/_libs/_94.mjs +2 -0
- package/.output/server/_libs/_95.mjs +2 -0
- package/.output/server/_libs/_96.mjs +2 -0
- package/.output/server/_libs/_97.mjs +2 -0
- package/.output/server/_libs/_98.mjs +2 -0
- package/.output/server/_libs/_99.mjs +5 -0
- package/.output/server/_libs/amdefine.mjs +188 -0
- package/.output/server/_libs/aws-sdk__nested-clients.mjs +1 -1
- package/.output/server/_libs/compressjs.mjs +50 -0
- package/.output/server/_libs/diff.mjs +137 -0
- package/.output/server/_libs/get-uri.mjs +1 -1
- package/.output/server/_libs/http-proxy-agent.mjs +1 -1
- package/.output/server/_libs/https-proxy-agent.mjs +1 -1
- package/.output/server/_libs/just-bash+[...].mjs +80359 -0
- package/.output/server/_libs/md4x.mjs +73 -0
- package/.output/server/_libs/mixmark-io__domino.mjs +14801 -0
- package/.output/server/_libs/node-fetch.mjs +1 -1
- package/.output/server/_libs/node-liblzma.mjs +1107 -0
- package/.output/server/_libs/pac-proxy-agent+[...].mjs +1 -1
- package/.output/server/_libs/proxy-agent+proxy-from-env.mjs +1 -1
- package/.output/server/_libs/smithy__core.mjs +1 -1
- package/.output/server/_routes/api/files/delete.mjs +2 -2
- package/.output/server/_routes/api/files/groups.mjs +14 -0
- package/.output/server/_routes/api/files/raw.mjs +1 -1
- package/.output/server/_routes/api/files/read.mjs +1 -1
- package/.output/server/_routes/api/files/watch.mjs +1 -1
- package/.output/server/_routes/api/files/write.mjs +3 -2
- package/.output/server/_routes/api/files.mjs +1 -1
- package/.output/server/_routes/api/groups.mjs +2 -2
- package/.output/server/_routes/api/groups2.mjs +3 -2
- package/.output/server/_routes/api/health.mjs +2 -2
- package/.output/server/_routes/api/logs.mjs +4 -2
- package/.output/server/_routes/api/ntfy/setup.mjs +54 -0
- package/.output/server/_routes/api/ntfy/status.mjs +12 -0
- package/.output/server/_routes/api/pi/apikey.mjs +1 -1
- package/.output/server/_routes/api/pi/apikey_providers.mjs +1 -1
- package/.output/server/_routes/api/pi/commands.mjs +6 -0
- package/.output/server/_routes/api/pi/login/events.mjs +1 -1
- package/.output/server/_routes/api/pi/login/respond.mjs +1 -1
- package/.output/server/_routes/api/pi/login.mjs +1 -1
- package/.output/server/_routes/api/pi/logout.mjs +1 -1
- package/.output/server/_routes/api/pi/models.mjs +1 -1
- package/.output/server/_routes/api/pi/status.mjs +1 -1
- package/.output/server/_routes/api/send.mjs +22 -3
- package/.output/server/_routes/api/status.mjs +9 -7
- package/.output/server/_routes/api/tasks2.mjs +2 -2
- package/.output/server/_routes/api/telegram/setup.mjs +2 -2
- package/.output/server/_routes/api/telegram/status.mjs +2 -2
- package/.output/server/_routes/api/terminal2.mjs +3 -2
- package/.output/server/_utils.mjs +12 -4
- package/.output/server/build/md4x.wasm +0 -0
- package/.output/server/index.mjs +223 -149
- package/.output/server/node_modules/@mongodb-js/zstd/lib/index.js +55 -0
- package/.output/server/node_modules/@mongodb-js/zstd/package.json +51 -0
- package/.output/server/package.json +1 -0
- package/README.md +118 -24
- package/bin/piclaw.mjs +39 -1
- package/package.json +16 -13
- package/.output/public/assets/client-TIs-Ghqj.js +0 -9
- package/.output/public/assets/dist-BVjfG3ok.js +0 -12
- package/.output/public/assets/dist-DJh8l6yS.js +0 -1
- package/.output/public/assets/index-BNNEMkNV.js +0 -39
- package/.output/public/assets/index-CdWBxO5V.css +0 -1
- package/.output/public/assets/react-DFP7nCmh.js +0 -1
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=`/assets/md4x-CNLJ57xO.wasm`;export{e as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./index-SfjxJZSD.js";var t;function n(){if(!t)throw Error("md4x: WASM not initialized. Call `await init()` first.");return t.exports}var r={fd_close:()=>0,fd_seek:()=>0,fd_write:()=>0,proc_exit:()=>{}};function i(e,t,n,...r){let{memory:i,md4x_alloc:a,md4x_free:o,md4x_result_ptr:s,md4x_result_size:c}=e,l=new TextEncoder().encode(n),u=a(l.length);new Uint8Array(i.buffer).set(l,u);let d=t(u,l.length,...r);if(o(u),d!==0)throw Error(`md4x: render failed`);let f=s(),p=c(),m=new TextDecoder().decode(new Uint8Array(i.buffer,f,p));return o(f),m}async function a(n){if(t)return;let i=n?.wasm,a;if(i instanceof ArrayBuffer||i instanceof Uint8Array)a=i;else if(i instanceof WebAssembly.Module){let{instance:e}=await WebAssembly.instantiate(i,{wasi_snapshot_preview1:r});t=e;return}else if(i instanceof Response||typeof i==`object`&&typeof i.then==`function`){let e=await i;a=e instanceof Response?await e.arrayBuffer():e}else{let t=globalThis.process?.getBuiltinModule?.(`fs/promises`);if(t){let e=new URL(`/assets/md4x-CNLJ57xO.wasm`,``+import.meta.url);a=await t.readFile(e)}else a=await fetch(await e(()=>import(`./md4x-CyfQToGJ.js`).then(e=>e.default),[])).then(e=>e.arrayBuffer())}let{instance:o}=await WebAssembly.instantiate(a,{wasi_snapshot_preview1:r});t=o}function o(e,t){let r=t?.full?8:0;return i(n(),n().md4x_to_html,e,r)}export{a as init,o as renderToHtml};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="PiClaw icon">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
4
|
+
<stop offset="0%" stop-color="#111820" />
|
|
5
|
+
<stop offset="100%" stop-color="#0a0e14" />
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="1">
|
|
8
|
+
<stop offset="0%" stop-color="#39bae6" />
|
|
9
|
+
<stop offset="100%" stop-color="#0077cc" />
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
|
|
13
|
+
<rect x="8" y="8" width="112" height="112" rx="24" fill="url(#bg)" />
|
|
14
|
+
<rect x="8" y="8" width="112" height="112" rx="24" fill="none" stroke="#1e2630" stroke-width="2" />
|
|
15
|
+
|
|
16
|
+
<path
|
|
17
|
+
d="M84 34c12 0 22 10 22 22 0 8-5 16-12 20l-12 6-10-8 8-11 10-4c3-1 4-3 4-5 0-4-3-7-7-7-3 0-6 2-7 5l-4 8-12-8 5-9c4-9 13-15 23-15z"
|
|
18
|
+
fill="url(#accent)"
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
<circle cx="44" cy="74" r="20" fill="#112a3a" stroke="#39bae6" stroke-width="2" />
|
|
22
|
+
<circle cx="44" cy="74" r="8" fill="#39bae6" />
|
|
23
|
+
|
|
24
|
+
<path d="M20 96h88" stroke="#1e2630" stroke-width="4" stroke-linecap="round" />
|
|
25
|
+
</svg>
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
12
12
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
13
13
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
14
|
+
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
|
14
15
|
<link rel="manifest" href="/manifest.json" />
|
|
15
|
-
<script type="module" crossorigin src="/assets/index-
|
|
16
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-SfjxJZSD.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B3x2_en6.css">
|
|
17
18
|
</head>
|
|
18
19
|
<body style="background-color: #0a0e14">
|
|
19
20
|
<div id="app"></div>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function spawnBunPty(opts) {
|
|
2
|
+
const dataListeners = /* @__PURE__ */ new Set();
|
|
3
|
+
const exitListeners = /* @__PURE__ */ new Set();
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
let exited = false;
|
|
6
|
+
const proc = globalThis.Bun.spawn([opts.shell], {
|
|
7
|
+
cwd: opts.cwd,
|
|
8
|
+
env: opts.env,
|
|
9
|
+
terminal: {
|
|
10
|
+
cols: opts.cols,
|
|
11
|
+
rows: opts.rows,
|
|
12
|
+
data(_term, raw) {
|
|
13
|
+
const str = decoder.decode(raw, { stream: true });
|
|
14
|
+
for (const cb of dataListeners) cb(str);
|
|
15
|
+
},
|
|
16
|
+
exit() {
|
|
17
|
+
if (exited) return;
|
|
18
|
+
exited = true;
|
|
19
|
+
for (const cb of exitListeners) cb();
|
|
20
|
+
dataListeners.clear();
|
|
21
|
+
exitListeners.clear();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
write(data) {
|
|
27
|
+
proc.terminal.write(data);
|
|
28
|
+
},
|
|
29
|
+
resize(cols, rows) {
|
|
30
|
+
proc.terminal.resize(cols, rows);
|
|
31
|
+
},
|
|
32
|
+
kill() {
|
|
33
|
+
if (exited) return;
|
|
34
|
+
try {
|
|
35
|
+
proc.kill();
|
|
36
|
+
proc.terminal.close();
|
|
37
|
+
} catch {}
|
|
38
|
+
},
|
|
39
|
+
onData(cb) {
|
|
40
|
+
dataListeners.add(cb);
|
|
41
|
+
return () => dataListeners.delete(cb);
|
|
42
|
+
},
|
|
43
|
+
onExit(cb) {
|
|
44
|
+
exitListeners.add(cb);
|
|
45
|
+
return () => exitListeners.delete(cb);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export { spawnBunPty };
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { r as GROUPS_DIR } from "./config.mjs";
|
|
2
|
+
import { t as streamBus } from "./stream.mjs";
|
|
3
|
+
import { i as resolveGroupModel, o as sessions, r as modelRegistry } from "./session.mjs";
|
|
4
|
+
import { t as clearMessages, v as removeSession } from "./db.mjs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { exec } from "node:child_process";
|
|
7
|
+
var commands = {
|
|
8
|
+
help: handleHelp,
|
|
9
|
+
info: handleInfo,
|
|
10
|
+
new: handleNew,
|
|
11
|
+
stop: handleStop,
|
|
12
|
+
model: handleModel,
|
|
13
|
+
thinking: handleThinking,
|
|
14
|
+
compact: handleCompact
|
|
15
|
+
};
|
|
16
|
+
/** Descriptions for registering commands with external channels (e.g. Telegram). */
|
|
17
|
+
const commandDescriptions = [
|
|
18
|
+
{
|
|
19
|
+
command: "help",
|
|
20
|
+
description: "Show available commands"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
command: "info",
|
|
24
|
+
description: "Show session info"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
command: "new",
|
|
28
|
+
description: "Reset session and start fresh"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
command: "stop",
|
|
32
|
+
description: "Stop the current agent session"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
command: "model",
|
|
36
|
+
description: "List or set model"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
command: "thinking",
|
|
40
|
+
description: "Show or set thinking level"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
command: "compact",
|
|
44
|
+
description: "Compact current session context"
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
/** Commands that bypass the queue and execute immediately (even during streaming). */
|
|
48
|
+
var priorityCommands = {
|
|
49
|
+
stop: handleStop,
|
|
50
|
+
new: handleNew,
|
|
51
|
+
info: handleInfo
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Try to handle a priority command that must bypass the queue.
|
|
55
|
+
* Called from the message loop and send API before enqueueing.
|
|
56
|
+
* Returns true if the message was a priority command (consumed).
|
|
57
|
+
*/
|
|
58
|
+
function tryPriorityCommand(ctx, text) {
|
|
59
|
+
if (!text.startsWith("/")) return false;
|
|
60
|
+
const spaceIdx = text.indexOf(" ");
|
|
61
|
+
const name = (spaceIdx > 0 ? text.slice(1, spaceIdx) : text.slice(1)).toLowerCase();
|
|
62
|
+
const handler = priorityCommands[name];
|
|
63
|
+
if (!handler) return false;
|
|
64
|
+
Promise.resolve(handler(ctx, "")).catch((err) => {
|
|
65
|
+
ctx.server.sendBotMessage(ctx.chatJid, `Command /${name} failed: ${String(err)}`);
|
|
66
|
+
});
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Try to handle a message as a `/command`. Returns true if handled.
|
|
71
|
+
*/
|
|
72
|
+
function tryCommand(ctx, text) {
|
|
73
|
+
if (!text.startsWith("/")) return false;
|
|
74
|
+
const spaceIdx = text.indexOf(" ");
|
|
75
|
+
const name = (spaceIdx > 0 ? text.slice(1, spaceIdx) : text.slice(1)).toLowerCase();
|
|
76
|
+
const arg = spaceIdx > 0 ? text.slice(spaceIdx + 1).trim() : "";
|
|
77
|
+
const handler = commands[name];
|
|
78
|
+
if (handler) {
|
|
79
|
+
Promise.resolve(handler(ctx, arg)).catch((err) => {
|
|
80
|
+
ctx.server.sendBotMessage(ctx.chatJid, `Command /${name} failed: ${String(err)}`);
|
|
81
|
+
});
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
ctx.server.sendBotMessage(ctx.chatJid, `Unknown command \`/${name}\`. Use /help for available commands.`);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Try to handle a message as a `! <bash>` command. Returns true if handled.
|
|
89
|
+
* Runs the command directly in the group's working directory, bypassing the agent.
|
|
90
|
+
*/
|
|
91
|
+
function tryBashCommand(ctx, text) {
|
|
92
|
+
if (!text.startsWith("!")) return false;
|
|
93
|
+
const cmd = text.slice(1).trim();
|
|
94
|
+
if (!cmd) return false;
|
|
95
|
+
const cwd = path.join(GROUPS_DIR, ctx.group.folder);
|
|
96
|
+
ctx.server.sendBotMessage(ctx.chatJid, `\`$ ${cmd}\``);
|
|
97
|
+
exec(cmd, {
|
|
98
|
+
cwd,
|
|
99
|
+
timeout: 5e3
|
|
100
|
+
}, (err, stdout, stderr) => {
|
|
101
|
+
const parts = [];
|
|
102
|
+
if (stdout) parts.push(stdout.trimEnd());
|
|
103
|
+
if (stderr) parts.push(stderr.trimEnd());
|
|
104
|
+
if (err && !stderr) parts.push(String(err.message || err));
|
|
105
|
+
const timedOut = err && "killed" in err && err.killed;
|
|
106
|
+
const output = parts.join("\n").replace(stripAnsiRe, "") || "(no output)";
|
|
107
|
+
const suffix = timedOut ? "\n(timed out)" : "";
|
|
108
|
+
ctx.server.sendBotMessage(ctx.chatJid, `\`\`\`\n${output}${suffix}\n\`\`\``);
|
|
109
|
+
});
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
function handleHelp(ctx) {
|
|
113
|
+
const lines = ["Available commands:", ...commandDescriptions.map((c) => ` /${c.command} — ${c.description}`)];
|
|
114
|
+
ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
|
|
115
|
+
}
|
|
116
|
+
function handleInfo(ctx) {
|
|
117
|
+
const resolved = resolveGroupModel(ctx.group);
|
|
118
|
+
const modelLabel = resolved ? `${resolved.provider}/${resolved.id}` : "none";
|
|
119
|
+
const modelSource = ctx.group.model ? `group (${ctx.group.model})` : "default";
|
|
120
|
+
const managed = sessions.get(ctx.chatJid);
|
|
121
|
+
const lines = [
|
|
122
|
+
`Group: ${ctx.group.name} (${ctx.group.folder})`,
|
|
123
|
+
`Model: ${modelLabel} [${modelSource}]`,
|
|
124
|
+
`Trigger: ${ctx.group.requiresTrigger ? "required" : "not required"}`
|
|
125
|
+
];
|
|
126
|
+
if (managed) {
|
|
127
|
+
const s = managed.session;
|
|
128
|
+
const actualModel = s.model;
|
|
129
|
+
const actualLabel = actualModel ? `${actualModel.provider}/${actualModel.id}` : "none";
|
|
130
|
+
const ctx$ = s.getContextUsage();
|
|
131
|
+
lines.push("", `Session: ${s.sessionId}`, actualLabel !== modelLabel ? `Session model: ${actualLabel} (MISMATCH with resolved)` : `Session model: ${actualLabel}`, `Messages: ${s.messages.length}`, `Streaming: ${s.isStreaming ? "yes" : "no"}`, `Idle: ${formatDuration(Date.now() - managed.lastActivity)}`);
|
|
132
|
+
if (ctx$?.tokens != null && ctx$.percent != null) {
|
|
133
|
+
const pct = Math.round(ctx$.percent);
|
|
134
|
+
lines.push(`Context: ${ctx$.tokens.toLocaleString()} / ${ctx$.contextWindow.toLocaleString()} tokens (${pct}%)`);
|
|
135
|
+
}
|
|
136
|
+
} else lines.push("", "No active session");
|
|
137
|
+
ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
|
|
138
|
+
}
|
|
139
|
+
function formatDuration(ms) {
|
|
140
|
+
const s = Math.floor(ms / 1e3);
|
|
141
|
+
if (s < 60) return `${s}s`;
|
|
142
|
+
const m = Math.floor(s / 60);
|
|
143
|
+
if (m < 60) return `${m}m ${s % 60}s`;
|
|
144
|
+
return `${Math.floor(m / 60)}h ${m % 60}m`;
|
|
145
|
+
}
|
|
146
|
+
function handleNew(ctx) {
|
|
147
|
+
ctx.server.pi.kill(ctx.chatJid);
|
|
148
|
+
removeSession(ctx.group.folder);
|
|
149
|
+
clearMessages(ctx.chatJid);
|
|
150
|
+
ctx.server.sendBotMessage(ctx.chatJid, "Session reset. Next message starts a fresh conversation.");
|
|
151
|
+
}
|
|
152
|
+
function handleStop(ctx) {
|
|
153
|
+
if (!sessions.get(ctx.chatJid)) {
|
|
154
|
+
ctx.server.sendBotMessage(ctx.chatJid, "No active session to stop.");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
streamBus.emit({
|
|
158
|
+
type: "agent_end",
|
|
159
|
+
chatJid: ctx.chatJid
|
|
160
|
+
});
|
|
161
|
+
ctx.server.pi.kill(ctx.chatJid);
|
|
162
|
+
ctx.server.sendBotMessage(ctx.chatJid, "Session stopped.");
|
|
163
|
+
}
|
|
164
|
+
function handleModel(ctx, arg) {
|
|
165
|
+
if (!arg) return listModels(ctx);
|
|
166
|
+
if (arg === "default" || arg === "reset") return resetModel(ctx);
|
|
167
|
+
return setModel(ctx, arg);
|
|
168
|
+
}
|
|
169
|
+
function listModels(ctx) {
|
|
170
|
+
const available = modelRegistry.getAvailable();
|
|
171
|
+
const resolved = resolveGroupModel(ctx.group);
|
|
172
|
+
const lines = [
|
|
173
|
+
`Current: ${ctx.group.model || "default (global)"} → ${resolved ? `${resolved.provider}/${resolved.id}` : "none"}`,
|
|
174
|
+
"",
|
|
175
|
+
"Available models:"
|
|
176
|
+
];
|
|
177
|
+
const byProvider = /* @__PURE__ */ new Map();
|
|
178
|
+
for (const m of available) {
|
|
179
|
+
let list = byProvider.get(m.provider);
|
|
180
|
+
if (!list) {
|
|
181
|
+
list = [];
|
|
182
|
+
byProvider.set(m.provider, list);
|
|
183
|
+
}
|
|
184
|
+
const marker = resolved && m.provider === resolved.provider && m.id === resolved.id ? " ←" : "";
|
|
185
|
+
list.push(` ${m.provider}/${m.id}${marker}`);
|
|
186
|
+
}
|
|
187
|
+
for (const [provider, models] of byProvider) {
|
|
188
|
+
lines.push(`[${provider}]`);
|
|
189
|
+
lines.push(...models);
|
|
190
|
+
}
|
|
191
|
+
lines.push("", "Usage: /model <query> | /model default");
|
|
192
|
+
ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
|
|
193
|
+
}
|
|
194
|
+
function resetModel(ctx) {
|
|
195
|
+
const had = ctx.group.model;
|
|
196
|
+
updateGroupModel(ctx, void 0);
|
|
197
|
+
ctx.server.sendBotMessage(ctx.chatJid, had ? `Model reset to default (was: ${had}).` : "Already using default model.");
|
|
198
|
+
}
|
|
199
|
+
function setModel(ctx, query) {
|
|
200
|
+
const match = findModel(query);
|
|
201
|
+
if (!match) {
|
|
202
|
+
ctx.server.sendBotMessage(ctx.chatJid, `No model matching "${query}". Use /model to list available models.`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const modelStr = `${match.provider}/${match.id}`;
|
|
206
|
+
updateGroupModel(ctx, modelStr);
|
|
207
|
+
ctx.server.sendBotMessage(ctx.chatJid, `Model set to: ${modelStr}`);
|
|
208
|
+
}
|
|
209
|
+
function updateGroupModel(ctx, model) {
|
|
210
|
+
const old = ctx.group.model;
|
|
211
|
+
ctx.group.model = model;
|
|
212
|
+
ctx.server.setRegisteredGroup(ctx.chatJid, ctx.group);
|
|
213
|
+
if (old !== model) ctx.server.pi.kill(ctx.chatJid);
|
|
214
|
+
}
|
|
215
|
+
var VALID_THINKING_LEVELS = [
|
|
216
|
+
"off",
|
|
217
|
+
"minimal",
|
|
218
|
+
"low",
|
|
219
|
+
"medium",
|
|
220
|
+
"high",
|
|
221
|
+
"xhigh"
|
|
222
|
+
];
|
|
223
|
+
function handleThinking(ctx, arg) {
|
|
224
|
+
if (!arg) {
|
|
225
|
+
const current = ctx.group.thinkingLevel || "off";
|
|
226
|
+
ctx.server.sendBotMessage(ctx.chatJid, `Thinking level: ${current}\n\nUsage: /thinking <level>\nLevels: ${VALID_THINKING_LEVELS.join(", ")}`);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const level = arg.toLowerCase();
|
|
230
|
+
if (!VALID_THINKING_LEVELS.includes(level)) {
|
|
231
|
+
ctx.server.sendBotMessage(ctx.chatJid, `Invalid thinking level "${arg}". Must be one of: ${VALID_THINKING_LEVELS.join(", ")}`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const old = ctx.group.thinkingLevel;
|
|
235
|
+
ctx.group.thinkingLevel = level === "off" ? void 0 : level;
|
|
236
|
+
ctx.server.setRegisteredGroup(ctx.chatJid, ctx.group);
|
|
237
|
+
if (old !== ctx.group.thinkingLevel) ctx.server.pi.kill(ctx.chatJid);
|
|
238
|
+
ctx.server.sendBotMessage(ctx.chatJid, `Thinking level set to: ${level}`);
|
|
239
|
+
}
|
|
240
|
+
async function handleCompact(ctx, arg) {
|
|
241
|
+
const managed = sessions.get(ctx.chatJid);
|
|
242
|
+
if (!managed) {
|
|
243
|
+
ctx.server.sendBotMessage(ctx.chatJid, "No active session to compact. Send a message first, then run /compact.");
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const session = managed.session;
|
|
247
|
+
if (session.isCompacting) {
|
|
248
|
+
ctx.server.sendBotMessage(ctx.chatJid, "Compaction is already in progress.");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const before = session.getContextUsage();
|
|
252
|
+
ctx.server.sendBotMessage(ctx.chatJid, "Compacting session context…");
|
|
253
|
+
const result = await session.compact(arg || void 0);
|
|
254
|
+
const after = session.getContextUsage();
|
|
255
|
+
const lines = ["Compaction complete."];
|
|
256
|
+
if (typeof result?.tokensBefore === "number") lines.push(`Tokens before: ${result.tokensBefore.toLocaleString()}`);
|
|
257
|
+
if (before?.tokens != null) lines.push(`Estimated tokens before: ${before.tokens.toLocaleString()}`);
|
|
258
|
+
if (after?.tokens != null) lines.push(`Estimated tokens after: ${after.tokens.toLocaleString()}`);
|
|
259
|
+
ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
|
|
260
|
+
}
|
|
261
|
+
function findModel(query) {
|
|
262
|
+
const available = modelRegistry.getAvailable();
|
|
263
|
+
if (available.length === 0) return void 0;
|
|
264
|
+
const q = query.toLowerCase();
|
|
265
|
+
const exact = available.filter((m) => `${m.provider}/${m.id}`.toLowerCase() === q);
|
|
266
|
+
if (exact.length === 1) return exact[0];
|
|
267
|
+
const byId = available.filter((m) => m.id.toLowerCase() === q);
|
|
268
|
+
if (byId.length === 1) return byId[0];
|
|
269
|
+
const tokens = q.split(/[\s/]+/).filter(Boolean);
|
|
270
|
+
const fuzzy = available.filter((m) => {
|
|
271
|
+
const label = `${m.provider}/${m.id}`.toLowerCase();
|
|
272
|
+
return tokens.every((t) => label.includes(t));
|
|
273
|
+
});
|
|
274
|
+
const matches = exact.length > 1 ? exact : byId.length > 1 ? byId : fuzzy;
|
|
275
|
+
if (matches.length === 0) return void 0;
|
|
276
|
+
matches.sort((a, b) => a.id.length - b.id.length || b.id.localeCompare(a.id, void 0, { numeric: true }));
|
|
277
|
+
return matches[0];
|
|
278
|
+
}
|
|
279
|
+
var stripAnsiRe = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*[A-Za-z]`, "g");
|
|
280
|
+
export { tryPriorityCommand as i, tryBashCommand as n, tryCommand as r, commandDescriptions as t };
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import os from "os";
|
|
2
2
|
import path from "path";
|
|
3
|
-
process.cwd();
|
|
4
3
|
const ASSISTANT_NAME = process.env.ASSISTANT_NAME || "pi";
|
|
5
|
-
Number.parseInt(process.env.ADMIN_PORT || "3737", 10);
|
|
6
4
|
const POLL_INTERVAL = 2e3;
|
|
7
5
|
const SCHEDULER_POLL_INTERVAL = 6e4;
|
|
8
6
|
function resolveDataRoot() {
|
|
9
|
-
|
|
10
|
-
return path.resolve(
|
|
7
|
+
if (process.env.PICLAW_DIR) return path.resolve(process.env.PICLAW_DIR);
|
|
8
|
+
return path.resolve(os.homedir(), ".pi", "claw");
|
|
11
9
|
}
|
|
12
10
|
const DATA_ROOT = resolveDataRoot();
|
|
13
11
|
const STORE_DIR = path.resolve(DATA_ROOT, "store");
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { d as STORE_DIR } from "./config.mjs";
|
|
2
2
|
import { t as createLogger } from "./logger.mjs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
3
4
|
import path from "path";
|
|
4
5
|
import fs from "fs";
|
|
5
|
-
import { DatabaseSync } from "node:sqlite";
|
|
6
6
|
var logger = createLogger("db");
|
|
7
|
+
var _require = createRequire(import.meta.url);
|
|
8
|
+
function openDatabase(dbPath) {
|
|
9
|
+
if ("Bun" in globalThis) return new (_require("bun:sqlite")).Database(dbPath);
|
|
10
|
+
return new (_require("node:sqlite")).DatabaseSync(dbPath);
|
|
11
|
+
}
|
|
7
12
|
var SCHEMA_VERSION = 2;
|
|
8
13
|
var _db;
|
|
9
14
|
function useDb() {
|
|
@@ -92,13 +97,14 @@ function initDatabase() {
|
|
|
92
97
|
const existing = fs.existsSync(versionFile) ? Number.parseInt(fs.readFileSync(versionFile, "utf-8").trim(), 10) : 0;
|
|
93
98
|
if (existing !== SCHEMA_VERSION) throw new Error(`Database schema version mismatch (have v${existing}, need v${SCHEMA_VERSION}). Delete ${STORE_DIR} to recreate.`);
|
|
94
99
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
const db = openDatabase(dbPath);
|
|
101
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
102
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
98
103
|
if (!dbExists) {
|
|
99
|
-
createSchema(
|
|
104
|
+
createSchema(db);
|
|
100
105
|
fs.writeFileSync(versionFile, String(SCHEMA_VERSION));
|
|
101
106
|
}
|
|
107
|
+
_db = db;
|
|
102
108
|
logger.info({ dbPath }, "Database initialized");
|
|
103
109
|
}
|
|
104
110
|
function storeMessage(msg) {
|
|
@@ -8,7 +8,7 @@ const LOG_LEVELS = {
|
|
|
8
8
|
error: 40,
|
|
9
9
|
fatal: 50
|
|
10
10
|
};
|
|
11
|
-
var currentLevel = LOG_LEVELS[process.env.LOG_LEVEL || "
|
|
11
|
+
var currentLevel = LOG_LEVELS[process.env.LOG_LEVEL || "debug"] ?? LOG_LEVELS.debug;
|
|
12
12
|
var LOGS_FILE = path.join(STORE_DIR, "logs.jsonl");
|
|
13
13
|
var MAX_LINES = 1e3;
|
|
14
14
|
var TRIM_TO = 500;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
async function spawnNodePty(opts) {
|
|
2
|
+
const term = (await import("node-pty")).spawn(opts.shell, [], {
|
|
3
|
+
name: "xterm-256color",
|
|
4
|
+
cols: opts.cols,
|
|
5
|
+
rows: opts.rows,
|
|
6
|
+
cwd: opts.cwd,
|
|
7
|
+
env: opts.env
|
|
8
|
+
});
|
|
9
|
+
return {
|
|
10
|
+
write(data) {
|
|
11
|
+
term.write(data);
|
|
12
|
+
},
|
|
13
|
+
resize(cols, rows) {
|
|
14
|
+
term.resize(cols, rows);
|
|
15
|
+
},
|
|
16
|
+
kill() {
|
|
17
|
+
try {
|
|
18
|
+
term.kill();
|
|
19
|
+
} catch {}
|
|
20
|
+
},
|
|
21
|
+
onData(cb) {
|
|
22
|
+
const d = term.onData(cb);
|
|
23
|
+
return () => d.dispose();
|
|
24
|
+
},
|
|
25
|
+
onExit(cb) {
|
|
26
|
+
const d = term.onExit(() => cb());
|
|
27
|
+
return () => d.dispose();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export { spawnNodePty };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { t as createLogger } from "./logger.mjs";
|
|
2
|
+
import { b as setConfig, i as deleteConfig, l as getConfig } from "./db.mjs";
|
|
3
|
+
var logger = createLogger("ntfy");
|
|
4
|
+
var CONFIG_KEY = "ntfy";
|
|
5
|
+
function getNtfyConfig() {
|
|
6
|
+
return getConfig(CONFIG_KEY);
|
|
7
|
+
}
|
|
8
|
+
function setNtfyConfig(config) {
|
|
9
|
+
setConfig(CONFIG_KEY, config);
|
|
10
|
+
}
|
|
11
|
+
function clearNtfyConfig() {
|
|
12
|
+
deleteConfig(CONFIG_KEY);
|
|
13
|
+
}
|
|
14
|
+
async function sendNtfyNotification(config, opts) {
|
|
15
|
+
const url = `${config.serverUrl.replace(/\/$/, "")}/${encodeURIComponent(config.topic)}`;
|
|
16
|
+
const headers = {};
|
|
17
|
+
if (config.token) headers["Authorization"] = `Bearer ${config.token}`;
|
|
18
|
+
if (opts.title) headers["X-Title"] = opts.title;
|
|
19
|
+
if (opts.priority) headers["X-Priority"] = String(opts.priority);
|
|
20
|
+
if (opts.tags?.length) headers["X-Tags"] = opts.tags.join(",");
|
|
21
|
+
if (opts.click) headers["X-Click"] = opts.click;
|
|
22
|
+
if (opts.icon) headers["X-Icon"] = opts.icon;
|
|
23
|
+
if (opts.markdown) headers["X-Markdown"] = "true";
|
|
24
|
+
if (opts.delay) headers["X-Delay"] = opts.delay;
|
|
25
|
+
if (opts.actions?.length) headers["X-Actions"] = opts.actions.join("; ");
|
|
26
|
+
if (opts.attach) headers["X-Attach"] = opts.attach;
|
|
27
|
+
if (opts.filename) headers["X-Filename"] = opts.filename;
|
|
28
|
+
if (opts.email) headers["X-Email"] = opts.email;
|
|
29
|
+
const res = await fetch(url, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
body: opts.message,
|
|
32
|
+
headers
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
const text = await res.text().catch(() => "");
|
|
36
|
+
logger.error({
|
|
37
|
+
status: res.status,
|
|
38
|
+
response: text,
|
|
39
|
+
url,
|
|
40
|
+
headers
|
|
41
|
+
}, "ntfy send failed");
|
|
42
|
+
}
|
|
43
|
+
logger.info({ ...opts }, "ntfy notification sent");
|
|
44
|
+
}
|
|
45
|
+
export { setNtfyConfig as i, getNtfyConfig as n, sendNtfyNotification as r, clearNtfyConfig as t };
|
|
@@ -116,7 +116,8 @@ var pi_exports = /* @__PURE__ */ __exportAll({
|
|
|
116
116
|
modelRegistry: () => modelRegistry,
|
|
117
117
|
run: () => run,
|
|
118
118
|
sendMessage: () => sendMessage,
|
|
119
|
-
shutdown: () => shutdown
|
|
119
|
+
shutdown: () => shutdown,
|
|
120
|
+
warmUp: () => warmUp
|
|
120
121
|
});
|
|
121
122
|
var logger = createLogger("pi");
|
|
122
123
|
async function run(group, input, onOutput) {
|
|
@@ -147,6 +148,37 @@ function kill(groupJid) {
|
|
|
147
148
|
sessions.delete(groupJid);
|
|
148
149
|
}
|
|
149
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Eagerly restore in-memory sessions for groups that had persisted sessions.
|
|
153
|
+
* Called on server boot so sessions are warm before message recovery.
|
|
154
|
+
*/
|
|
155
|
+
async function warmUp(groups, storedSessions, assistantName) {
|
|
156
|
+
const folderToJid = /* @__PURE__ */ new Map();
|
|
157
|
+
for (const [jid, group] of Object.entries(groups)) folderToJid.set(group.folder, {
|
|
158
|
+
jid,
|
|
159
|
+
group
|
|
160
|
+
});
|
|
161
|
+
const toRestore = Object.entries(storedSessions).filter(([folder]) => folderToJid.has(folder) && !sessions.has(folderToJid.get(folder).jid));
|
|
162
|
+
if (toRestore.length === 0) return;
|
|
163
|
+
logger.info({ count: toRestore.length }, "Warming up persisted sessions");
|
|
164
|
+
const results = await Promise.allSettled(toRestore.map(async ([folder, sessionId]) => {
|
|
165
|
+
const { jid, group } = folderToJid.get(folder);
|
|
166
|
+
await getOrCreateSession(group, {
|
|
167
|
+
prompt: "",
|
|
168
|
+
sessionId,
|
|
169
|
+
groupFolder: folder,
|
|
170
|
+
chatJid: jid,
|
|
171
|
+
isMain: folder === "main",
|
|
172
|
+
assistantName
|
|
173
|
+
});
|
|
174
|
+
return {
|
|
175
|
+
jid,
|
|
176
|
+
group: group.name
|
|
177
|
+
};
|
|
178
|
+
}));
|
|
179
|
+
for (const r of results) if (r.status === "fulfilled") logger.info({ group: r.value.group }, "Session restored");
|
|
180
|
+
else logger.warn({ err: r.reason }, "Failed to restore session");
|
|
181
|
+
}
|
|
150
182
|
async function shutdown(timeoutMs) {
|
|
151
183
|
for (const [jid, managed] of sessions) {
|
|
152
184
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as HTTPResponse } from "../_libs/h3+rou3+srvx.mjs";
|
|
2
|
-
const rendererTemplate = () => new HTTPResponse("<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover, interactive-widget=resizes-content\"\n />\n <title>PiClaw</title>\n <meta name=\"theme-color\" content=\"#0a0e14\" />\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\n <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\" />\n <meta name=\"mobile-web-app-capable\" content=\"yes\" />\n <link rel=\"manifest\" href=\"/manifest.json\" />\n </head>\n <body style=\"background-color: #0a0e14\">\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/app/index.ts\"><\/script>\n </body>\n</html>\n", { headers: { "content-type": "text/html; charset=utf-8" } });
|
|
2
|
+
const rendererTemplate = () => new HTTPResponse("<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover, interactive-widget=resizes-content\"\n />\n <title>PiClaw</title>\n <meta name=\"theme-color\" content=\"#0a0e14\" />\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\n <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\" />\n <meta name=\"mobile-web-app-capable\" content=\"yes\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/icon.svg\" />\n <link rel=\"manifest\" href=\"/manifest.json\" />\n </head>\n <body style=\"background-color: #0a0e14\">\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/app/index.ts\"><\/script>\n </body>\n</html>\n", { headers: { "content-type": "text/html; charset=utf-8" } });
|
|
3
3
|
function renderIndexHTML(event) {
|
|
4
4
|
return rendererTemplate(event.req);
|
|
5
5
|
}
|