jishushell 0.4.24 → 0.5.15
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/INSTALL-NOTICE +11 -0
- package/apps/anythingllm-container.yaml +287 -0
- package/apps/browserless-chromium-container.yaml +90 -0
- package/apps/filebrowser-container.yaml +163 -0
- package/apps/hermes-container.yaml +36 -2
- package/apps/ollama-binary.yaml +91 -90
- package/apps/ollama-cpu-container.yaml +8 -1
- package/apps/ollama-with-hollama-binary.yaml +91 -90
- package/apps/openclaw-binary.yaml +38 -1
- package/apps/openclaw-container.yaml +45 -2
- package/apps/openclaw-with-ollama-container.yaml +11 -2
- package/apps/openclaw-with-searxng-container.yaml +26 -2
- package/apps/openwebui-container.yaml +45 -1
- package/apps/playwright-container.yaml +7 -1
- package/apps/searxng-container.yaml +58 -7
- package/apps/weknora-container.yaml +471 -0
- package/dist/cli/app.js +79 -9
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/doctor.d.ts +12 -12
- package/dist/cli/doctor.js +242 -55
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/llm.d.ts +4 -3
- package/dist/cli/llm.js +4 -3
- package/dist/cli/llm.js.map +1 -1
- package/dist/cli/panel.d.ts +6 -5
- package/dist/cli/panel.js +10 -9
- package/dist/cli/panel.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.js +99 -1
- package/dist/config.js.map +1 -1
- package/dist/control.d.ts +7 -6
- package/dist/control.js +7 -6
- package/dist/control.js.map +1 -1
- package/dist/install.js +3 -3
- package/dist/install.js.map +1 -1
- package/dist/routes/agent-apps.d.ts +1 -1
- package/dist/routes/agent-apps.js +1 -1
- package/dist/routes/apps.js +44 -11
- package/dist/routes/apps.js.map +1 -1
- package/dist/routes/auth.js +5 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/backup.js +64 -11
- package/dist/routes/backup.js.map +1 -1
- package/dist/routes/external-mounts.d.ts +17 -0
- package/dist/routes/external-mounts.js +73 -0
- package/dist/routes/external-mounts.js.map +1 -0
- package/dist/routes/file-mounts.d.ts +13 -0
- package/dist/routes/file-mounts.js +90 -0
- package/dist/routes/file-mounts.js.map +1 -0
- package/dist/routes/files-organize.d.ts +28 -0
- package/dist/routes/files-organize.js +167 -0
- package/dist/routes/files-organize.js.map +1 -0
- package/dist/routes/files.d.ts +31 -0
- package/dist/routes/files.js +321 -0
- package/dist/routes/files.js.map +1 -0
- package/dist/routes/instances.js +826 -17
- package/dist/routes/instances.js.map +1 -1
- package/dist/routes/internal.d.ts +2 -0
- package/dist/routes/internal.js +59 -0
- package/dist/routes/internal.js.map +1 -0
- package/dist/routes/llm.js +24 -35
- package/dist/routes/llm.js.map +1 -1
- package/dist/routes/setup.js +10 -10
- package/dist/routes/setup.js.map +1 -1
- package/dist/routes/system.js +1 -1
- package/dist/routes/system.js.map +1 -1
- package/dist/routes/webdav.d.ts +17 -0
- package/dist/routes/webdav.js +114 -0
- package/dist/routes/webdav.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +751 -20
- package/dist/server.js.map +1 -1
- package/dist/services/agent-apps/catalog.js +4 -3
- package/dist/services/agent-apps/catalog.js.map +1 -1
- package/dist/services/agent-apps/index.d.ts +1 -1
- package/dist/services/agent-apps/index.js +1 -1
- package/dist/services/agent-apps/installers/adapter.d.ts +1 -1
- package/dist/services/agent-apps/installers/adapter.js +1 -1
- package/dist/services/agent-apps/installers/shell-script.d.ts +1 -1
- package/dist/services/agent-apps/installers/shell-script.js +3 -3
- package/dist/services/agent-apps/installers/shell-script.js.map +1 -1
- package/dist/services/agent-apps/types.d.ts +2 -2
- package/dist/services/agent-apps/types.js +1 -1
- package/dist/services/app/app-compiler.d.ts +1 -1
- package/dist/services/app/app-compiler.js +5 -5
- package/dist/services/app/app-compiler.js.map +1 -1
- package/dist/services/app/app-manager.d.ts +25 -1
- package/dist/services/app/app-manager.js +829 -150
- package/dist/services/app/app-manager.js.map +1 -1
- package/dist/services/app/custom-manager.js.map +1 -1
- package/dist/services/app/hermes-agent-manager.js +7 -4
- package/dist/services/app/hermes-agent-manager.js.map +1 -1
- package/dist/services/app/ollama-manager.js +1 -1
- package/dist/services/app/ollama-manager.js.map +1 -1
- package/dist/services/app/openclaw-manager.js +20 -3
- package/dist/services/app/openclaw-manager.js.map +1 -1
- package/dist/services/app/platform-transform.d.ts +32 -0
- package/dist/services/app/platform-transform.js +65 -0
- package/dist/services/app/platform-transform.js.map +1 -0
- package/dist/services/app/provide-resolver.d.ts +29 -0
- package/dist/services/app/provide-resolver.js +112 -0
- package/dist/services/app/provide-resolver.js.map +1 -0
- package/dist/services/app-passwords.d.ts +61 -0
- package/dist/services/app-passwords.js +173 -0
- package/dist/services/app-passwords.js.map +1 -0
- package/dist/services/backup-manager.d.ts +11 -0
- package/dist/services/backup-manager.js +177 -4
- package/dist/services/backup-manager.js.map +1 -1
- package/dist/services/capability-endpoint-validator.d.ts +41 -0
- package/dist/services/capability-endpoint-validator.js +104 -0
- package/dist/services/capability-endpoint-validator.js.map +1 -0
- package/dist/services/capability-health.d.ts +16 -0
- package/dist/services/capability-health.js +121 -0
- package/dist/services/capability-health.js.map +1 -0
- package/dist/services/capability-registry.d.ts +106 -0
- package/dist/services/capability-registry.js +313 -0
- package/dist/services/capability-registry.js.map +1 -0
- package/dist/services/connection-apply.d.ts +91 -0
- package/dist/services/connection-apply.js +475 -0
- package/dist/services/connection-apply.js.map +1 -0
- package/dist/services/connection-resolver.d.ts +65 -0
- package/dist/services/connection-resolver.js +281 -0
- package/dist/services/connection-resolver.js.map +1 -0
- package/dist/services/connection-transactor.d.ts +39 -0
- package/dist/services/connection-transactor.js +351 -0
- package/dist/services/connection-transactor.js.map +1 -0
- package/dist/services/external-mounts.d.ts +40 -0
- package/dist/services/external-mounts.js +187 -0
- package/dist/services/external-mounts.js.map +1 -0
- package/dist/services/files-manager.d.ts +252 -0
- package/dist/services/files-manager.js +1075 -0
- package/dist/services/files-manager.js.map +1 -0
- package/dist/services/files-mounts.d.ts +42 -0
- package/dist/services/files-mounts.js +207 -0
- package/dist/services/files-mounts.js.map +1 -0
- package/dist/services/instance-manager.d.ts +13 -0
- package/dist/services/instance-manager.js +138 -46
- package/dist/services/instance-manager.js.map +1 -1
- package/dist/services/llm-proxy/index.d.ts +16 -2
- package/dist/services/llm-proxy/index.js +48 -44
- package/dist/services/llm-proxy/index.js.map +1 -1
- package/dist/services/llm-proxy/probe.d.ts +6 -0
- package/dist/services/llm-proxy/probe.js +85 -0
- package/dist/services/llm-proxy/probe.js.map +1 -0
- package/dist/services/llm-proxy/ssrf.d.ts +1 -0
- package/dist/services/llm-proxy/ssrf.js +24 -9
- package/dist/services/llm-proxy/ssrf.js.map +1 -1
- package/dist/services/nomad-manager.d.ts +4 -0
- package/dist/services/nomad-manager.js +428 -35
- package/dist/services/nomad-manager.js.map +1 -1
- package/dist/services/organize/applier.d.ts +46 -0
- package/dist/services/organize/applier.js +218 -0
- package/dist/services/organize/applier.js.map +1 -0
- package/dist/services/organize/rules.d.ts +57 -0
- package/dist/services/organize/rules.js +286 -0
- package/dist/services/organize/rules.js.map +1 -0
- package/dist/services/organize/scanner.d.ts +50 -0
- package/dist/services/organize/scanner.js +366 -0
- package/dist/services/organize/scanner.js.map +1 -0
- package/dist/services/organize/store.d.ts +14 -0
- package/dist/services/organize/store.js +82 -0
- package/dist/services/organize/store.js.map +1 -0
- package/dist/services/panel-manager.js +20 -1
- package/dist/services/panel-manager.js.map +1 -1
- package/dist/services/process-manager.js +4 -3
- package/dist/services/process-manager.js.map +1 -1
- package/dist/services/runtime/adapters/hermes.d.ts +30 -1
- package/dist/services/runtime/adapters/hermes.js +219 -6
- package/dist/services/runtime/adapters/hermes.js.map +1 -1
- package/dist/services/runtime/adapters/openclaw-mcporter.d.ts +45 -0
- package/dist/services/runtime/adapters/openclaw-mcporter.js +108 -0
- package/dist/services/runtime/adapters/openclaw-mcporter.js.map +1 -0
- package/dist/services/runtime/adapters/openclaw-routes.d.ts +8 -2
- package/dist/services/runtime/adapters/openclaw-routes.js +68 -0
- package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -1
- package/dist/services/runtime/adapters/openclaw.d.ts +177 -0
- package/dist/services/runtime/adapters/openclaw.js +1171 -11
- package/dist/services/runtime/adapters/openclaw.js.map +1 -1
- package/dist/services/runtime/instance.d.ts +1 -1
- package/dist/services/runtime/instance.js +1 -1
- package/dist/services/runtime/instance.js.map +1 -1
- package/dist/services/runtime/mcp-shims/anythingllm-shim.d.ts +46 -0
- package/dist/services/runtime/mcp-shims/anythingllm-shim.js +281 -0
- package/dist/services/runtime/mcp-shims/anythingllm-shim.js.map +1 -0
- package/dist/services/runtime/mcp-shims/drive-shim.d.ts +54 -0
- package/dist/services/runtime/mcp-shims/drive-shim.js +489 -0
- package/dist/services/runtime/mcp-shims/drive-shim.js.map +1 -0
- package/dist/services/runtime/mcp-shims/firewall.d.ts +26 -0
- package/dist/services/runtime/mcp-shims/firewall.js +129 -0
- package/dist/services/runtime/mcp-shims/firewall.js.map +1 -0
- package/dist/services/runtime/mcp-shims/searxng-shim.d.ts +27 -0
- package/dist/services/runtime/mcp-shims/searxng-shim.js +125 -0
- package/dist/services/runtime/mcp-shims/searxng-shim.js.map +1 -0
- package/dist/services/runtime/mcp-shims/write-mcp-entry.d.ts +83 -0
- package/dist/services/runtime/mcp-shims/write-mcp-entry.js +127 -0
- package/dist/services/runtime/mcp-shims/write-mcp-entry.js.map +1 -0
- package/dist/services/runtime/migrations.d.ts +8 -0
- package/dist/services/runtime/migrations.js +100 -0
- package/dist/services/runtime/migrations.js.map +1 -1
- package/dist/services/runtime/types.d.ts +46 -0
- package/dist/services/setup-manager.js +99 -24
- package/dist/services/setup-manager.js.map +1 -1
- package/dist/services/suggestions.d.ts +27 -0
- package/dist/services/suggestions.js +133 -0
- package/dist/services/suggestions.js.map +1 -0
- package/dist/services/task-registry.js +4 -2
- package/dist/services/task-registry.js.map +1 -1
- package/dist/services/telemetry/device-fingerprint.d.ts +1 -1
- package/dist/services/telemetry/device-fingerprint.js +1 -1
- package/dist/services/types-shim.d.ts +16 -0
- package/dist/services/types-shim.js +2 -0
- package/dist/services/types-shim.js.map +1 -0
- package/dist/services/webdav/server.d.ts +24 -0
- package/dist/services/webdav/server.js +420 -0
- package/dist/services/webdav/server.js.map +1 -0
- package/dist/services/webdav/xml-builder.d.ts +73 -0
- package/dist/services/webdav/xml-builder.js +156 -0
- package/dist/services/webdav/xml-builder.js.map +1 -0
- package/dist/services/workspace-builder.d.ts +29 -0
- package/dist/services/workspace-builder.js +188 -0
- package/dist/services/workspace-builder.js.map +1 -0
- package/dist/types.d.ts +231 -1
- package/dist/utils/instance-lock.d.ts +22 -0
- package/dist/utils/instance-lock.js +48 -0
- package/dist/utils/instance-lock.js.map +1 -0
- package/dist/utils/path-locks.d.ts +30 -0
- package/dist/utils/path-locks.js +63 -0
- package/dist/utils/path-locks.js.map +1 -0
- package/dist/utils/path-safety.d.ts +41 -0
- package/dist/utils/path-safety.js +119 -0
- package/dist/utils/path-safety.js.map +1 -0
- package/dist/utils/safe-json.js +55 -22
- package/dist/utils/safe-json.js.map +1 -1
- package/dist/utils/safe-write.d.ts +24 -0
- package/dist/utils/safe-write.js +82 -0
- package/dist/utils/safe-write.js.map +1 -0
- package/install/jishu-install.sh +323 -27
- package/install/jishu-uninstall.sh +353 -20
- package/package.json +18 -1
- package/public/assets/Dashboard-BdWPtroF.js +1 -0
- package/public/assets/{HermesChatPanel-mFSureyc.js → HermesChatPanel-B_2HlVBQ.js} +1 -1
- package/public/assets/HermesConfigForm-DVlhg3WV.js +4 -0
- package/public/assets/{InitPassword-CVA8wQA6.js → InitPassword-D7glTExX.js} +1 -1
- package/public/assets/InstanceDetail-CxSy2cpe.js +92 -0
- package/public/assets/{Login-BWsZH2mu.js → Login-Cfr5c2sv.js} +1 -1
- package/public/assets/NewInstance-BIYDmJis.js +1 -0
- package/public/assets/ProviderRecommendations-BuRnvRcI.js +1 -0
- package/public/assets/Settings-Cc-tYBil.js +1 -0
- package/public/assets/Setup-lGZEk5jq.js +1 -0
- package/public/assets/{WeixinLoginPanel-CnjR8xMu.js → WeixinLoginPanel-CoGqzxeV.js} +2 -2
- package/public/assets/index-87IJXG-w.css +1 -0
- package/public/assets/index-BZc5zH7u.js +19 -0
- package/public/assets/providers-DtNXh9JD.js +1 -0
- package/public/assets/registry-BWnkJgZ1.js +2 -0
- package/public/assets/{usePolling-Do5Erqm_.js → usePolling-CwwT9KrC.js} +1 -1
- package/public/assets/{vendor-i18n-ucpM0OR0.js → vendor-i18n-y9V7Sfuu.js} +1 -1
- package/public/assets/{vendor-react-Bk1hRGiY.js → vendor-react-BWrEVJVb.js} +6 -6
- package/public/index.html +4 -4
- package/scripts/check-app-spec.mjs +457 -0
- package/scripts/check-i18n.mjs +154 -0
- package/scripts/check-new-file-tests.mjs +230 -0
- package/scripts/check-quarantine-expiry.mjs +105 -0
- package/scripts/perf/README.md +49 -0
- package/scripts/perf/auth.js +99 -0
- package/scripts/perf/config.js +63 -0
- package/scripts/perf/instances.js +143 -0
- package/scripts/perf/proxy.js +96 -0
- package/scripts/run.sh +4 -4
- package/scripts/smoke/files-w1.sh +142 -0
- package/scripts/smoke-backend.mjs +122 -0
- package/scripts/smoke-post-publish.mjs +346 -0
- package/public/assets/Dashboard-B-JoOjBQ.js +0 -1
- package/public/assets/HermesConfigForm-DvR05LK1.js +0 -4
- package/public/assets/InstanceDetail-DcZW2QGO.js +0 -91
- package/public/assets/NewInstance-BCIrAd86.js +0 -1
- package/public/assets/Settings-xkDcduFz.js +0 -1
- package/public/assets/Setup-Cfuwj4gV.js +0 -1
- package/public/assets/index-CPhVFEsx.css +0 -1
- package/public/assets/index-DQsM6Joa.js +0 -19
- package/public/assets/providers-V-vwrExZ.js +0 -1
- package/public/assets/registry-B4UFJdpA.js +0 -2
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import http from "k6/http";
|
|
2
|
+
import { check, group, sleep } from "k6";
|
|
3
|
+
import {
|
|
4
|
+
BASE_URL,
|
|
5
|
+
PASSWORD,
|
|
6
|
+
DEFAULT_THRESHOLDS,
|
|
7
|
+
DEFAULT_STAGES,
|
|
8
|
+
SMOKE_STAGES,
|
|
9
|
+
bearerHeaders,
|
|
10
|
+
} from "./config.js";
|
|
11
|
+
|
|
12
|
+
const isSmoke = __ENV.SMOKE === "true";
|
|
13
|
+
|
|
14
|
+
export const options = {
|
|
15
|
+
stages: isSmoke ? SMOKE_STAGES : DEFAULT_STAGES,
|
|
16
|
+
thresholds: {
|
|
17
|
+
...DEFAULT_THRESHOLDS,
|
|
18
|
+
"http_req_duration{name:list_models}": ["p(95)<300"],
|
|
19
|
+
},
|
|
20
|
+
tags: { suite: "proxy" },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Setup: obtain auth token for proxy requests.
|
|
25
|
+
*/
|
|
26
|
+
export function setup() {
|
|
27
|
+
const statusRes = http.get(`${BASE_URL}/api/auth/status`);
|
|
28
|
+
const initialized = statusRes.json("initialized");
|
|
29
|
+
|
|
30
|
+
let token;
|
|
31
|
+
if (!initialized) {
|
|
32
|
+
const initRes = http.post(
|
|
33
|
+
`${BASE_URL}/api/auth/init`,
|
|
34
|
+
JSON.stringify({ password: PASSWORD }),
|
|
35
|
+
{ headers: { "Content-Type": "application/json" } },
|
|
36
|
+
);
|
|
37
|
+
token = initRes.json("token");
|
|
38
|
+
} else {
|
|
39
|
+
const loginRes = http.post(
|
|
40
|
+
`${BASE_URL}/api/auth/login`,
|
|
41
|
+
JSON.stringify({ password: PASSWORD }),
|
|
42
|
+
{ headers: { "Content-Type": "application/json" } },
|
|
43
|
+
);
|
|
44
|
+
token = loginRes.json("token");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!token) {
|
|
48
|
+
throw new Error("Failed to obtain auth token during setup");
|
|
49
|
+
}
|
|
50
|
+
return { token };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default function (data) {
|
|
54
|
+
const headers = bearerHeaders(data.token);
|
|
55
|
+
|
|
56
|
+
group("list-models", () => {
|
|
57
|
+
const res = http.get(`${BASE_URL}/proxy/v1/models`, {
|
|
58
|
+
headers,
|
|
59
|
+
tags: { name: "list_models" },
|
|
60
|
+
});
|
|
61
|
+
check(res, {
|
|
62
|
+
"models 200": (r) => r.status === 200,
|
|
63
|
+
"has data array": (r) => {
|
|
64
|
+
try {
|
|
65
|
+
return Array.isArray(r.json("data"));
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
sleep(0.5);
|
|
74
|
+
|
|
75
|
+
group("list-providers", () => {
|
|
76
|
+
const res = http.get(`${BASE_URL}/api/llm/providers`, {
|
|
77
|
+
headers: {
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
Cookie: `jishushell_session=${data.token}`,
|
|
80
|
+
},
|
|
81
|
+
tags: { name: "list_providers" },
|
|
82
|
+
});
|
|
83
|
+
check(res, {
|
|
84
|
+
"providers 200": (r) => r.status === 200,
|
|
85
|
+
"returns array": (r) => {
|
|
86
|
+
try {
|
|
87
|
+
return Array.isArray(r.json());
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
sleep(1);
|
|
96
|
+
}
|
package/scripts/run.sh
CHANGED
|
@@ -81,7 +81,7 @@ kill_port() {
|
|
|
81
81
|
|
|
82
82
|
# ─── Nomad ────────────────────────────────────────────────────────────────────
|
|
83
83
|
ensure_nomad() {
|
|
84
|
-
#
|
|
84
|
+
# If anything is holding Nomad-related ports, kill it all to guarantee a clean restart.
|
|
85
85
|
local nomad_ports_pids
|
|
86
86
|
nomad_ports_pids="$(sudo lsof -ti tcp:4646,4647,4648 2>/dev/null || lsof -ti tcp:4646,4647,4648 2>/dev/null || true)"
|
|
87
87
|
if [[ -n "$nomad_ports_pids" ]]; then
|
|
@@ -105,7 +105,7 @@ ensure_nomad() {
|
|
|
105
105
|
success "Nomad ports 4646/4647/4648 freed"
|
|
106
106
|
fi
|
|
107
107
|
|
|
108
|
-
#
|
|
108
|
+
# Locate the nomad binary; prefer the one bundled with jishushell.
|
|
109
109
|
local nomad_bin="${HOME}/.jishushell/bin/nomad"
|
|
110
110
|
if [[ ! -x "$nomad_bin" ]]; then
|
|
111
111
|
nomad_bin="$(command -v nomad 2>/dev/null || true)"
|
|
@@ -133,7 +133,7 @@ ensure_nomad() {
|
|
|
133
133
|
nohup "$nomad_bin" agent -dev -bind=127.0.0.1 > "$log_path" 2>&1 &
|
|
134
134
|
fi
|
|
135
135
|
|
|
136
|
-
#
|
|
136
|
+
# Wait for Nomad to become ready (up to 15 seconds).
|
|
137
137
|
local tries=0
|
|
138
138
|
while ! lsof -ti tcp:4646 &>/dev/null && [[ $tries -lt 15 ]]; do
|
|
139
139
|
sleep 1
|
|
@@ -294,7 +294,7 @@ mode_server() {
|
|
|
294
294
|
# ─── Entry point ──────────────────────────────────────────────────────────────
|
|
295
295
|
check_node
|
|
296
296
|
|
|
297
|
-
# Nomad
|
|
297
|
+
# Start Nomad first (not required in build/frontend/help modes).
|
|
298
298
|
case "$MODE" in
|
|
299
299
|
""|dev|server) ensure_nomad ;;
|
|
300
300
|
esac
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# End-to-end smoke for Files M1 W1 (PR-4).
|
|
4
|
+
#
|
|
5
|
+
# Drives the eight /api/files endpoints against a running jishushell panel:
|
|
6
|
+
# 1. GET /api/files (list root)
|
|
7
|
+
# 2. PUT /api/files?path=... (upload, octet-stream)
|
|
8
|
+
# 3. GET /api/files?path=... (list subdirectory)
|
|
9
|
+
# 4. POST /api/files/mkdir (create directory)
|
|
10
|
+
# 5. POST /api/files/move (move/rename)
|
|
11
|
+
# 6. GET /api/files/raw?path=... (stream download, sha verified)
|
|
12
|
+
# 7. GET /api/files/preview?path=... (text preview, truncation)
|
|
13
|
+
# 8. GET /api/files/quota (quota info)
|
|
14
|
+
# 9. DELETE /api/files?path=... (soft-delete)
|
|
15
|
+
# 10. PUT with Content-Type: text/plain → expect 415
|
|
16
|
+
# 11. PUT with path traversal → expect 400
|
|
17
|
+
#
|
|
18
|
+
# Usage:
|
|
19
|
+
# # Either provide a token directly:
|
|
20
|
+
# JISHUSHELL_URL=http://pi2:8090 JISHUSHELL_TOKEN=... ./scripts/smoke/files-w1.sh
|
|
21
|
+
# # Or let the script log in for you:
|
|
22
|
+
# JISHUSHELL_URL=http://pi2:8090 JISHUSHELL_PASSWORD=... ./scripts/smoke/files-w1.sh
|
|
23
|
+
#
|
|
24
|
+
# Per docs/feedback_validate_before_commit.md, this script MUST run on a real
|
|
25
|
+
# Pi2 box before the Files W1 work is considered complete.
|
|
26
|
+
|
|
27
|
+
set -eo pipefail
|
|
28
|
+
|
|
29
|
+
PANEL_URL="${JISHUSHELL_URL:-http://127.0.0.1:8090}"
|
|
30
|
+
AUTH_TOKEN="${JISHUSHELL_TOKEN:-}"
|
|
31
|
+
PANEL_PASSWORD="${JISHUSHELL_PASSWORD:-}"
|
|
32
|
+
PREFIX="${PREFIX:-smoke-w1}"
|
|
33
|
+
|
|
34
|
+
if [[ -z "$AUTH_TOKEN" && -z "$PANEL_PASSWORD" ]]; then
|
|
35
|
+
echo "ERROR: set JISHUSHELL_TOKEN or JISHUSHELL_PASSWORD env var" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
if [[ -z "$AUTH_TOKEN" ]]; then
|
|
40
|
+
echo "[auth] logging in as admin"
|
|
41
|
+
AUTH_TOKEN=$(curl -sS -X POST -H "Content-Type: application/json" \
|
|
42
|
+
-d "{\"password\":\"$PANEL_PASSWORD\"}" \
|
|
43
|
+
"$PANEL_URL/api/auth/login" | sed -n 's/.*"token":"\([^"]*\)".*/\1/p')
|
|
44
|
+
if [[ -z "$AUTH_TOKEN" ]]; then
|
|
45
|
+
echo "ERROR: login failed" >&2
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
echo " ok: got JWT (${#AUTH_TOKEN} chars)"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
H_AUTH=(-H "Authorization: Bearer $AUTH_TOKEN")
|
|
52
|
+
fail() { echo "FAIL: $*" >&2; exit 1; }
|
|
53
|
+
pass() { echo " ok: $*"; }
|
|
54
|
+
|
|
55
|
+
# Cleanup any leftovers from a previous run (best-effort)
|
|
56
|
+
curl -s -X DELETE "$PANEL_URL/api/files?path=$PREFIX/x.txt" "${H_AUTH[@]}" >/dev/null || true
|
|
57
|
+
curl -s -X DELETE "$PANEL_URL/api/files?path=$PREFIX/y.txt" "${H_AUTH[@]}" >/dev/null || true
|
|
58
|
+
curl -s -X DELETE "$PANEL_URL/api/files?path=$PREFIX/sub" "${H_AUTH[@]}" >/dev/null || true
|
|
59
|
+
curl -s -X DELETE "$PANEL_URL/api/files?path=$PREFIX" "${H_AUTH[@]}" >/dev/null || true
|
|
60
|
+
|
|
61
|
+
echo "[1/11] List root"
|
|
62
|
+
RESP=$(curl -sS "${H_AUTH[@]}" "$PANEL_URL/api/files")
|
|
63
|
+
echo "$RESP" | grep -q '"entries"' || fail "list root missing entries: $RESP"
|
|
64
|
+
pass "list root ok"
|
|
65
|
+
|
|
66
|
+
echo "[2/11] mkdir $PREFIX"
|
|
67
|
+
RESP=$(curl -sS -X POST "${H_AUTH[@]}" -H "Content-Type: application/json" \
|
|
68
|
+
-d "{\"path\":\"$PREFIX\"}" "$PANEL_URL/api/files/mkdir")
|
|
69
|
+
echo "$RESP" | grep -q "\"$PREFIX\"" || fail "mkdir failed: $RESP"
|
|
70
|
+
pass "mkdir $PREFIX"
|
|
71
|
+
|
|
72
|
+
echo "[3/11] PUT octet-stream upload"
|
|
73
|
+
echo -n "hello smoke" > /tmp/files-smoke-w1.bin
|
|
74
|
+
RESP=$(curl -sS -X PUT "${H_AUTH[@]}" \
|
|
75
|
+
-H "Content-Type: application/octet-stream" \
|
|
76
|
+
--data-binary @/tmp/files-smoke-w1.bin \
|
|
77
|
+
"$PANEL_URL/api/files?path=$PREFIX/x.txt")
|
|
78
|
+
echo "$RESP" | grep -q '"size":11' || fail "upload size wrong: $RESP"
|
|
79
|
+
ETAG=$(echo "$RESP" | sed -n 's/.*"etag":"\([^"]*\)".*/\1/p')
|
|
80
|
+
[[ -n "$ETAG" ]] || fail "upload returned no etag: $RESP"
|
|
81
|
+
pass "uploaded $PREFIX/x.txt (etag=$ETAG)"
|
|
82
|
+
|
|
83
|
+
echo "[4/11] PUT with wrong Content-Type expects 415"
|
|
84
|
+
CODE=$(curl -sS -o /dev/null -w "%{http_code}" -X PUT "${H_AUTH[@]}" \
|
|
85
|
+
-H "Content-Type: text/plain" --data "x" \
|
|
86
|
+
"$PANEL_URL/api/files?path=$PREFIX/y.txt")
|
|
87
|
+
[[ "$CODE" == "415" ]] || fail "expected 415, got $CODE"
|
|
88
|
+
pass "wrong content-type → 415"
|
|
89
|
+
|
|
90
|
+
echo "[5/11] PUT path traversal expects 400"
|
|
91
|
+
CODE=$(curl -sS -o /dev/null -w "%{http_code}" -X PUT "${H_AUTH[@]}" \
|
|
92
|
+
-H "Content-Type: application/octet-stream" --data "x" \
|
|
93
|
+
"$PANEL_URL/api/files?path=../../../etc/passwd")
|
|
94
|
+
[[ "$CODE" == "400" ]] || fail "expected 400, got $CODE"
|
|
95
|
+
pass "path traversal → 400"
|
|
96
|
+
|
|
97
|
+
echo "[6/11] List $PREFIX"
|
|
98
|
+
RESP=$(curl -sS "${H_AUTH[@]}" "$PANEL_URL/api/files?path=$PREFIX")
|
|
99
|
+
echo "$RESP" | grep -q '"x.txt"' || fail "missing x.txt in list: $RESP"
|
|
100
|
+
pass "subdirectory listing ok"
|
|
101
|
+
|
|
102
|
+
echo "[7/11] Move x.txt → sub/x.txt"
|
|
103
|
+
curl -sS -X POST "${H_AUTH[@]}" -H "Content-Type: application/json" \
|
|
104
|
+
-d "{\"path\":\"$PREFIX/sub\"}" "$PANEL_URL/api/files/mkdir" >/dev/null
|
|
105
|
+
RESP=$(curl -sS -X POST "${H_AUTH[@]}" -H "Content-Type: application/json" \
|
|
106
|
+
-d "{\"from\":\"$PREFIX/x.txt\",\"to\":\"$PREFIX/sub/x.txt\"}" \
|
|
107
|
+
"$PANEL_URL/api/files/move")
|
|
108
|
+
echo "$RESP" | grep -q '"to":' || fail "move response missing 'to': $RESP"
|
|
109
|
+
pass "move ok"
|
|
110
|
+
|
|
111
|
+
echo "[8/11] GET /raw streams content"
|
|
112
|
+
GOT=$(curl -sS "${H_AUTH[@]}" "$PANEL_URL/api/files/raw?path=$PREFIX/sub/x.txt")
|
|
113
|
+
[[ "$GOT" == "hello smoke" ]] || fail "raw content mismatch: '$GOT'"
|
|
114
|
+
pass "raw download verified"
|
|
115
|
+
|
|
116
|
+
echo "[9/11] GET /preview truncates"
|
|
117
|
+
RESP=$(curl -sS "${H_AUTH[@]}" "$PANEL_URL/api/files/preview?path=$PREFIX/sub/x.txt&max_kb=1")
|
|
118
|
+
echo "$RESP" | grep -q '"truncated":false' || fail "preview missing truncated:false: $RESP"
|
|
119
|
+
echo "$RESP" | grep -q '"content":"hello smoke"' || fail "preview content mismatch: $RESP"
|
|
120
|
+
pass "preview ok"
|
|
121
|
+
|
|
122
|
+
echo "[10/11] GET /quota"
|
|
123
|
+
RESP=$(curl -sS "${H_AUTH[@]}" "$PANEL_URL/api/files/quota")
|
|
124
|
+
echo "$RESP" | grep -q '"quota_mb"' || fail "quota response missing quota_mb: $RESP"
|
|
125
|
+
pass "quota ok"
|
|
126
|
+
|
|
127
|
+
echo "[11/11] DELETE soft-deletes to .trash/"
|
|
128
|
+
CODE=$(curl -sS -o /dev/null -w "%{http_code}" -X DELETE "${H_AUTH[@]}" \
|
|
129
|
+
"$PANEL_URL/api/files?path=$PREFIX/sub/x.txt")
|
|
130
|
+
[[ "$CODE" == "204" ]] || fail "expected 204, got $CODE"
|
|
131
|
+
# Confirm by listing — file should be gone from sub/
|
|
132
|
+
RESP=$(curl -sS "${H_AUTH[@]}" "$PANEL_URL/api/files?path=$PREFIX/sub")
|
|
133
|
+
echo "$RESP" | grep -q '"x.txt"' && fail "x.txt still in sub/ after delete"
|
|
134
|
+
pass "soft-delete ok"
|
|
135
|
+
|
|
136
|
+
# Final cleanup
|
|
137
|
+
curl -s -X DELETE "$PANEL_URL/api/files?path=$PREFIX/sub" "${H_AUTH[@]}" >/dev/null || true
|
|
138
|
+
curl -s -X DELETE "$PANEL_URL/api/files?path=$PREFIX" "${H_AUTH[@]}" >/dev/null || true
|
|
139
|
+
rm -f /tmp/files-smoke-w1.bin
|
|
140
|
+
|
|
141
|
+
echo ""
|
|
142
|
+
echo "✓ All 11 smoke checks passed against $PANEL_URL"
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CI smoke test: compile backend → spawn server → verify /api/auth/status → exit.
|
|
4
|
+
*
|
|
5
|
+
* Uses the same stdout-parsing approach as tests/e2e-real/helpers/server-manager.ts
|
|
6
|
+
* to discover the OS-assigned port.
|
|
7
|
+
*
|
|
8
|
+
* Exit codes:
|
|
9
|
+
* 0 — smoke test passed
|
|
10
|
+
* 1 — smoke test failed (server did not start or health check failed)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawn } from "child_process";
|
|
14
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
15
|
+
import { tmpdir } from "os";
|
|
16
|
+
import { join } from "path";
|
|
17
|
+
import { setTimeout as delay } from "timers/promises";
|
|
18
|
+
|
|
19
|
+
const STARTUP_TIMEOUT_MS = 15_000;
|
|
20
|
+
const HEALTH_POLL_INTERVAL_MS = 200;
|
|
21
|
+
const HEALTH_POLL_ATTEMPTS = 25;
|
|
22
|
+
|
|
23
|
+
const testHome = mkdtempSync(join(tmpdir(), "jishushell-smoke-"));
|
|
24
|
+
let serverProcess = null;
|
|
25
|
+
|
|
26
|
+
let cleaning = false;
|
|
27
|
+
|
|
28
|
+
async function cleanup(exitCode) {
|
|
29
|
+
if (cleaning) return;
|
|
30
|
+
cleaning = true;
|
|
31
|
+
if (serverProcess && !serverProcess.killed) {
|
|
32
|
+
serverProcess.kill("SIGTERM");
|
|
33
|
+
await delay(500);
|
|
34
|
+
if (!serverProcess.killed) {
|
|
35
|
+
try { serverProcess.kill("SIGKILL"); } catch { /* already dead */ }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
try { rmSync(testHome, { recursive: true, force: true }); } catch { /* noop */ }
|
|
39
|
+
process.exit(exitCode);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
process.on("SIGINT", () => cleanup(1));
|
|
43
|
+
process.on("SIGTERM", () => cleanup(1));
|
|
44
|
+
process.on("unhandledRejection", (err) => {
|
|
45
|
+
console.error("[smoke] unhandled rejection:", err);
|
|
46
|
+
cleanup(1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
async function main() {
|
|
50
|
+
const cliPath = join(process.cwd(), "dist", "cli.js");
|
|
51
|
+
|
|
52
|
+
console.log(`[smoke] JISHUSHELL_HOME = ${testHome}`);
|
|
53
|
+
console.log(`[smoke] Starting server: node ${cliPath} serve --port 0 --host 127.0.0.1`);
|
|
54
|
+
|
|
55
|
+
serverProcess = spawn("node", [cliPath, "serve", "--port", "0", "--host", "127.0.0.1"], {
|
|
56
|
+
env: {
|
|
57
|
+
...process.env,
|
|
58
|
+
JISHUSHELL_HOME: testHome,
|
|
59
|
+
JISHUSHELL_JWT_SECRET: "ci-smoke-test-jwt-secret-that-is-at-least-32-chars",
|
|
60
|
+
NODE_ENV: "test",
|
|
61
|
+
},
|
|
62
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Discover assigned port from stdout/stderr
|
|
66
|
+
const port = await new Promise((resolve, reject) => {
|
|
67
|
+
const timer = setTimeout(() => reject(new Error("Server did not start within 15 seconds")), STARTUP_TIMEOUT_MS);
|
|
68
|
+
let output = "";
|
|
69
|
+
|
|
70
|
+
const onData = (chunk) => {
|
|
71
|
+
output += chunk.toString();
|
|
72
|
+
const match = output.match(/listening at http:\/\/127\.0\.0\.1:(\d+)/);
|
|
73
|
+
if (match) {
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
resolve(parseInt(match[1], 10));
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
serverProcess.stdout.on("data", onData);
|
|
80
|
+
serverProcess.stderr.on("data", onData);
|
|
81
|
+
serverProcess.on("exit", (code) => {
|
|
82
|
+
clearTimeout(timer);
|
|
83
|
+
reject(new Error(`Server exited with code ${code} before becoming ready.\nOutput:\n${output}`));
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log(`[smoke] Server listening on port ${port}`);
|
|
88
|
+
|
|
89
|
+
// Poll /api/auth/status
|
|
90
|
+
let lastStatus = 0;
|
|
91
|
+
for (let i = 0; i < HEALTH_POLL_ATTEMPTS; i++) {
|
|
92
|
+
try {
|
|
93
|
+
const resp = await fetch(`http://127.0.0.1:${port}/api/auth/status`, {
|
|
94
|
+
signal: AbortSignal.timeout(2000),
|
|
95
|
+
});
|
|
96
|
+
lastStatus = resp.status;
|
|
97
|
+
if (resp.ok) {
|
|
98
|
+
console.log(`[smoke] PASSED: /api/auth/status returned ${resp.status}`);
|
|
99
|
+
await cleanup(0);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
// Server may not be fully ready yet
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (serverProcess.exitCode !== null) {
|
|
107
|
+
console.error(`[smoke] FAILED: Server exited unexpectedly with code ${serverProcess.exitCode}`);
|
|
108
|
+
await cleanup(1);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
await delay(HEALTH_POLL_INTERVAL_MS);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.error(`[smoke] FAILED: /api/auth/status returned ${lastStatus} after ${HEALTH_POLL_ATTEMPTS} attempts`);
|
|
116
|
+
await cleanup(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
main().catch(async (err) => {
|
|
120
|
+
console.error(`[smoke] FAILED: ${err.message}`);
|
|
121
|
+
await cleanup(1);
|
|
122
|
+
});
|