jishushell 0.4.30 → 0.5.22

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.
Files changed (226) hide show
  1. package/Dockerfile.hermes-slim +2 -5
  2. package/apps/anythingllm-container.yaml +287 -0
  3. package/apps/browserless-chromium-container.yaml +18 -6
  4. package/apps/filebrowser-container.yaml +164 -0
  5. package/apps/ollama-binary.yaml +44 -0
  6. package/apps/ollama-with-hollama-binary.yaml +45 -1
  7. package/apps/openclaw-binary.yaml +8 -0
  8. package/apps/openclaw-container.yaml +9 -1
  9. package/apps/openclaw-with-searxng-container.yaml +4 -0
  10. package/apps/searxng-container.yaml +5 -4
  11. package/apps/weknora-container.yaml +471 -0
  12. package/dist/cli/doctor.js +144 -16
  13. package/dist/cli/doctor.js.map +1 -1
  14. package/dist/cli/panel.js.map +1 -1
  15. package/dist/config.d.ts +19 -0
  16. package/dist/config.js +99 -1
  17. package/dist/config.js.map +1 -1
  18. package/dist/install.js +4 -4
  19. package/dist/install.js.map +1 -1
  20. package/dist/routes/auth.js +2 -2
  21. package/dist/routes/auth.js.map +1 -1
  22. package/dist/routes/backup.js +64 -11
  23. package/dist/routes/backup.js.map +1 -1
  24. package/dist/routes/external-mounts.d.ts +17 -0
  25. package/dist/routes/external-mounts.js +73 -0
  26. package/dist/routes/external-mounts.js.map +1 -0
  27. package/dist/routes/file-mounts.d.ts +13 -0
  28. package/dist/routes/file-mounts.js +90 -0
  29. package/dist/routes/file-mounts.js.map +1 -0
  30. package/dist/routes/files-organize.d.ts +28 -0
  31. package/dist/routes/files-organize.js +167 -0
  32. package/dist/routes/files-organize.js.map +1 -0
  33. package/dist/routes/files.d.ts +31 -0
  34. package/dist/routes/files.js +321 -0
  35. package/dist/routes/files.js.map +1 -0
  36. package/dist/routes/instances.js +87 -12
  37. package/dist/routes/instances.js.map +1 -1
  38. package/dist/routes/internal.d.ts +2 -0
  39. package/dist/routes/internal.js +59 -0
  40. package/dist/routes/internal.js.map +1 -0
  41. package/dist/routes/llm.js +29 -0
  42. package/dist/routes/llm.js.map +1 -1
  43. package/dist/routes/setup.js +9 -9
  44. package/dist/routes/setup.js.map +1 -1
  45. package/dist/routes/system.js +1 -1
  46. package/dist/routes/system.js.map +1 -1
  47. package/dist/routes/webdav.d.ts +17 -0
  48. package/dist/routes/webdav.js +114 -0
  49. package/dist/routes/webdav.js.map +1 -0
  50. package/dist/server.js +358 -6
  51. package/dist/server.js.map +1 -1
  52. package/dist/services/agent-apps/catalog.d.ts +3 -0
  53. package/dist/services/agent-apps/catalog.js +40 -13
  54. package/dist/services/agent-apps/catalog.js.map +1 -1
  55. package/dist/services/agent-apps/installers/shell-script.d.ts +1 -1
  56. package/dist/services/agent-apps/installers/shell-script.js +19 -2
  57. package/dist/services/agent-apps/installers/shell-script.js.map +1 -1
  58. package/dist/services/agent-apps/types.d.ts +3 -0
  59. package/dist/services/app/app-compiler.d.ts +1 -1
  60. package/dist/services/app/app-compiler.js +5 -5
  61. package/dist/services/app/app-compiler.js.map +1 -1
  62. package/dist/services/app/app-manager.d.ts +9 -0
  63. package/dist/services/app/app-manager.js +248 -43
  64. package/dist/services/app/app-manager.js.map +1 -1
  65. package/dist/services/app/custom-manager.js.map +1 -1
  66. package/dist/services/app/hermes-agent-manager.js +1 -0
  67. package/dist/services/app/hermes-agent-manager.js.map +1 -1
  68. package/dist/services/app/ollama-manager.js +1 -1
  69. package/dist/services/app/ollama-manager.js.map +1 -1
  70. package/dist/services/app/openclaw-manager.js +37 -5
  71. package/dist/services/app/openclaw-manager.js.map +1 -1
  72. package/dist/services/app/platform-transform.d.ts +32 -0
  73. package/dist/services/app/platform-transform.js +65 -0
  74. package/dist/services/app/platform-transform.js.map +1 -0
  75. package/dist/services/app-passwords.d.ts +61 -0
  76. package/dist/services/app-passwords.js +173 -0
  77. package/dist/services/app-passwords.js.map +1 -0
  78. package/dist/services/backup-manager.d.ts +11 -0
  79. package/dist/services/backup-manager.js +220 -8
  80. package/dist/services/backup-manager.js.map +1 -1
  81. package/dist/services/capability-endpoint-validator.js +26 -7
  82. package/dist/services/capability-endpoint-validator.js.map +1 -1
  83. package/dist/services/connection-apply.d.ts +2 -0
  84. package/dist/services/connection-apply.js +55 -1
  85. package/dist/services/connection-apply.js.map +1 -1
  86. package/dist/services/connection-resolver.js +1 -1
  87. package/dist/services/connection-resolver.js.map +1 -1
  88. package/dist/services/connection-transactor.d.ts +2 -0
  89. package/dist/services/connection-transactor.js +12 -2
  90. package/dist/services/connection-transactor.js.map +1 -1
  91. package/dist/services/external-mounts.d.ts +40 -0
  92. package/dist/services/external-mounts.js +187 -0
  93. package/dist/services/external-mounts.js.map +1 -0
  94. package/dist/services/files-manager.d.ts +252 -0
  95. package/dist/services/files-manager.js +1075 -0
  96. package/dist/services/files-manager.js.map +1 -0
  97. package/dist/services/files-mounts.d.ts +42 -0
  98. package/dist/services/files-mounts.js +207 -0
  99. package/dist/services/files-mounts.js.map +1 -0
  100. package/dist/services/instance-manager.js +90 -32
  101. package/dist/services/instance-manager.js.map +1 -1
  102. package/dist/services/llm-proxy/index.d.ts +28 -0
  103. package/dist/services/llm-proxy/index.js +76 -3
  104. package/dist/services/llm-proxy/index.js.map +1 -1
  105. package/dist/services/llm-proxy/ssrf.js +6 -2
  106. package/dist/services/llm-proxy/ssrf.js.map +1 -1
  107. package/dist/services/llm-proxy/validate-key.d.ts +41 -0
  108. package/dist/services/llm-proxy/validate-key.js +672 -0
  109. package/dist/services/llm-proxy/validate-key.js.map +1 -0
  110. package/dist/services/macos-launchd.d.ts +89 -0
  111. package/dist/services/macos-launchd.js +273 -0
  112. package/dist/services/macos-launchd.js.map +1 -0
  113. package/dist/services/nomad-manager.d.ts +11 -0
  114. package/dist/services/nomad-manager.js +343 -98
  115. package/dist/services/nomad-manager.js.map +1 -1
  116. package/dist/services/organize/applier.d.ts +46 -0
  117. package/dist/services/organize/applier.js +218 -0
  118. package/dist/services/organize/applier.js.map +1 -0
  119. package/dist/services/organize/rules.d.ts +57 -0
  120. package/dist/services/organize/rules.js +286 -0
  121. package/dist/services/organize/rules.js.map +1 -0
  122. package/dist/services/organize/scanner.d.ts +50 -0
  123. package/dist/services/organize/scanner.js +366 -0
  124. package/dist/services/organize/scanner.js.map +1 -0
  125. package/dist/services/organize/store.d.ts +14 -0
  126. package/dist/services/organize/store.js +82 -0
  127. package/dist/services/organize/store.js.map +1 -0
  128. package/dist/services/panel-manager.js +40 -11
  129. package/dist/services/panel-manager.js.map +1 -1
  130. package/dist/services/process-manager.js +3 -2
  131. package/dist/services/process-manager.js.map +1 -1
  132. package/dist/services/runtime/adapters/custom.js +56 -0
  133. package/dist/services/runtime/adapters/custom.js.map +1 -1
  134. package/dist/services/runtime/adapters/hermes.d.ts +4 -3
  135. package/dist/services/runtime/adapters/hermes.js +166 -64
  136. package/dist/services/runtime/adapters/hermes.js.map +1 -1
  137. package/dist/services/runtime/adapters/openclaw-routes.d.ts +8 -2
  138. package/dist/services/runtime/adapters/openclaw-routes.js +68 -0
  139. package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -1
  140. package/dist/services/runtime/adapters/openclaw.d.ts +118 -0
  141. package/dist/services/runtime/adapters/openclaw.js +1459 -49
  142. package/dist/services/runtime/adapters/openclaw.js.map +1 -1
  143. package/dist/services/runtime/instance.d.ts +1 -1
  144. package/dist/services/runtime/instance.js +1 -1
  145. package/dist/services/runtime/instance.js.map +1 -1
  146. package/dist/services/runtime/mcp-shims/anythingllm-shim.d.ts +46 -0
  147. package/dist/services/runtime/mcp-shims/anythingllm-shim.js +281 -0
  148. package/dist/services/runtime/mcp-shims/anythingllm-shim.js.map +1 -0
  149. package/dist/services/runtime/mcp-shims/drive-shim.d.ts +54 -0
  150. package/dist/services/runtime/mcp-shims/drive-shim.js +489 -0
  151. package/dist/services/runtime/mcp-shims/drive-shim.js.map +1 -0
  152. package/dist/services/runtime/types.d.ts +31 -0
  153. package/dist/services/setup-manager.js +190 -68
  154. package/dist/services/setup-manager.js.map +1 -1
  155. package/dist/services/suggestions.js.map +1 -1
  156. package/dist/services/update-manager.js +32 -14
  157. package/dist/services/update-manager.js.map +1 -1
  158. package/dist/services/webdav/server.d.ts +24 -0
  159. package/dist/services/webdav/server.js +420 -0
  160. package/dist/services/webdav/server.js.map +1 -0
  161. package/dist/services/webdav/xml-builder.d.ts +73 -0
  162. package/dist/services/webdav/xml-builder.js +156 -0
  163. package/dist/services/webdav/xml-builder.js.map +1 -0
  164. package/dist/services/workspace-builder.d.ts +29 -0
  165. package/dist/services/workspace-builder.js +188 -0
  166. package/dist/services/workspace-builder.js.map +1 -0
  167. package/dist/types.d.ts +61 -0
  168. package/dist/utils/path-locks.d.ts +30 -0
  169. package/dist/utils/path-locks.js +63 -0
  170. package/dist/utils/path-locks.js.map +1 -0
  171. package/dist/utils/path-safety.d.ts +41 -0
  172. package/dist/utils/path-safety.js +119 -0
  173. package/dist/utils/path-safety.js.map +1 -0
  174. package/dist/utils/safe-write.d.ts +24 -0
  175. package/dist/utils/safe-write.js +82 -0
  176. package/dist/utils/safe-write.js.map +1 -0
  177. package/install/jishu-install.sh +247 -35
  178. package/install/jishu-uninstall.sh +45 -5
  179. package/package.json +20 -2
  180. package/public/assets/ApiKeyField-CvyAOcJS.js +1 -0
  181. package/public/assets/Dashboard-AuJESBlJ.js +1 -0
  182. package/public/assets/{HermesChatPanel-_GHoklgo.js → HermesChatPanel-CByPREwb.js} +1 -1
  183. package/public/assets/HermesConfigForm-DRda8FKX.js +4 -0
  184. package/public/assets/InitPassword-ka4wNpM5.js +1 -0
  185. package/public/assets/InstanceDetail-Cg1nS8HX.js +92 -0
  186. package/public/assets/Login-aPajuQzf.js +1 -0
  187. package/public/assets/NewInstance-Dd1ebNIx.js +1 -0
  188. package/public/assets/ProviderRecommendations-DFmADQ7V.js +1 -0
  189. package/public/assets/Settings-BYQnbLYL.js +1 -0
  190. package/public/assets/Setup-D05lwDOV.js +1 -0
  191. package/public/assets/WeixinLoginPanel-D89kdhP4.js +9 -0
  192. package/public/assets/index-HSXCsceK.css +1 -0
  193. package/public/assets/index-bnBu0nlQ.js +19 -0
  194. package/public/assets/registry-C_qeFTkZ.js +2 -0
  195. package/public/assets/usePolling-Bn93fe7M.js +1 -0
  196. package/public/assets/{vendor-i18n-ucpM0OR0.js → vendor-i18n-flxcMVeP.js} +2 -2
  197. package/public/assets/{vendor-react-Bk1hRGiY.js → vendor-react-ZC5T_huj.js} +7 -7
  198. package/public/index.html +4 -4
  199. package/scripts/check-app-spec.mjs +18 -4
  200. package/scripts/check-colima-launchd.mjs +230 -0
  201. package/scripts/check-new-file-tests.mjs +230 -0
  202. package/scripts/check-quarantine-expiry.mjs +105 -0
  203. package/scripts/perf/README.md +49 -0
  204. package/scripts/perf/auth.js +99 -0
  205. package/scripts/perf/config.js +63 -0
  206. package/scripts/perf/instances.js +143 -0
  207. package/scripts/perf/proxy.js +96 -0
  208. package/scripts/smoke/files-w1.sh +142 -0
  209. package/scripts/smoke-backend.mjs +122 -0
  210. package/scripts/smoke-post-publish.mjs +346 -0
  211. package/public/assets/Dashboard-rkWp-CXd.js +0 -1
  212. package/public/assets/HermesConfigForm-anDnwUp_.js +0 -4
  213. package/public/assets/InitPassword-ZU9_-hDr.js +0 -1
  214. package/public/assets/InstanceDetail-CN0FH1aw.js +0 -92
  215. package/public/assets/Login-BItXqYAJ.js +0 -1
  216. package/public/assets/NewInstance-BousE6kY.js +0 -1
  217. package/public/assets/ProviderRecommendations-DFYj7Fb6.js +0 -1
  218. package/public/assets/Settings-Bttc6QmM.js +0 -1
  219. package/public/assets/Setup-Bsxx1zgj.js +0 -1
  220. package/public/assets/WeixinLoginPanel-DPZpAKgO.js +0 -9
  221. package/public/assets/index-8xZy1z5k.css +0 -1
  222. package/public/assets/index-Dw3HhUYE.js +0 -19
  223. package/public/assets/input-paste-CrNVAyOy.js +0 -1
  224. package/public/assets/providers-DtNXh9JD.js +0 -1
  225. package/public/assets/registry-5s2UB6is.js +0 -2
  226. package/public/assets/usePolling-Do5Erqm_.js +0 -1
@@ -64,6 +64,14 @@ requires:
64
64
  inject_as: "MCP_SERVERS"
65
65
  required: false
66
66
  cardinality: "many"
67
+ - capability: "files"
68
+ inject_as: "FILES_BROWSER_URL"
69
+ required: false
70
+ cardinality: "one"
71
+ - capability: "knowledge"
72
+ inject_as: "KNOWLEDGE_BASE_URL"
73
+ required: false
74
+ cardinality: "one"
67
75
 
68
76
  lifecycle:
69
77
  install:
@@ -69,4 +69,12 @@ requires:
69
69
  - capability: "mcp"
70
70
  inject_as: "MCP_SERVERS"
71
71
  required: false
72
- cardinality: "many"
72
+ cardinality: "many"
73
+ - capability: "files"
74
+ inject_as: "FILES_BROWSER_URL"
75
+ required: false
76
+ cardinality: "one"
77
+ - capability: "knowledge"
78
+ inject_as: "KNOWLEDGE_BASE_URL"
79
+ required: false
80
+ cardinality: "one"
@@ -87,6 +87,10 @@ requires:
87
87
  - capability: "search-searxng"
88
88
  inject_as: "SEARCH_API_BASE_URL"
89
89
  required: false
90
+ - capability: "files"
91
+ inject_as: "FILES_BROWSER_URL"
92
+ required: false
93
+ cardinality: "one"
90
94
 
91
95
  lifecycle:
92
96
  install:
@@ -20,7 +20,8 @@ tasks:
20
20
  memory: "512Mi"
21
21
  ports:
22
22
  - name: http
23
- port: 8080
23
+ port: 18080
24
+ container_port: 8080
24
25
  visibility: external
25
26
  volumes:
26
27
  - source: "~/.jishushell/apps/${app_id}/settings/settings.yml"
@@ -41,17 +42,17 @@ tasks:
41
42
  provides:
42
43
  - capability: "web-ui"
43
44
  task: "searxng"
44
- port: 8080
45
+ port: 18080
45
46
  protocol: "http"
46
47
  description: "SearXNG Web UI(legacy capability,请改用 web-searxng)"
47
48
  - capability: "web-searxng"
48
49
  task: "searxng"
49
- port: 8080
50
+ port: 18080
50
51
  protocol: "http"
51
52
  description: "SearXNG Web UI"
52
53
  - capability: "search-searxng"
53
54
  task: "searxng"
54
- port: 8080
55
+ port: 18080
55
56
  path: "/search"
56
57
  protocol: "http"
57
58
  description: "SearXNG 搜索 API,支持 JSON 格式 (/search?q=xxx&format=json)"
@@ -0,0 +1,471 @@
1
+ id: weknora-container
2
+ name: WeKnora
3
+ version: "1.0.0"
4
+ jishushell:
5
+ min_version: "0.5.15"
6
+ description: "Tencent 开源 RAG 知识库:文档解析 + 向量检索 + 对话式问答(5 容器单 Nomad TaskGroup)"
7
+ singleInstance: true
8
+
9
+ # 拓扑(每个 task 独立 docker netns,跨 task 经 host.docker.internal:<host-port>):
10
+ # 注:原始设计想用 Nomad group bridge mode 让 task 共享 netns 走 127.0.0.1,
11
+ # 但需要 /opt/cni/bin/ 下的 containernetworking 插件(Pi 默认没装)。退而用
12
+ # host 端口发布 + host.docker.internal 路由(panel `extra_hosts:host-gateway`
13
+ # 已 mapping 到 172.17.0.1 = docker0 bridge gateway)。
14
+ # 关键:5 个发布端口都设 `host_network: docker_bridge` 让 panel/Nomad 把
15
+ # docker-proxy 绑到 docker0 IP(172.17.0.1),peer 容器走 host.docker.internal
16
+ # 即 172.17.0.1 时打得通。要求 nomad.hcl 声明 `host_network "docker_bridge"
17
+ # { cidr = "172.17.0.0/16" }`(panel doctor 会自动写入)。
18
+ #
19
+ # weknora-ui (nginx :80) ─proxy_pass─► weknora-app :8080
20
+ # │ │
21
+ # │ ├─► paradedb :5432 (PG17 + pgvector + FTS5;同时承担 vector store)
22
+ # │ ├─► redis :6379 (任务队列 / 流式响应缓存)
23
+ # │ └─► docreader:50051 (gRPC:PDF / Word / Markdown 解析)
24
+ # │
25
+ # host :18092 ◄── published (visibility: external)
26
+ #
27
+ # 关键裁剪(相对官方 docker-compose):
28
+ # - RETRIEVE_DRIVER=postgres:复用 paradedb 的 pgvector,**不装 Qdrant / Milvus / Weaviate**(省 1 task + ~70MB 下载)
29
+ # - WEKNORA_SANDBOX_MODE=disabled:不装 weknora-sandbox(省 ~80MB;阉割 agent 工具沙箱执行,RAG 主流程不受影响)
30
+ # - 不装 Neo4j / MinIO / Langfuse / Jaeger / SearXNG / Doris / ClickHouse / Dex(都是 profile 才启的)
31
+ #
32
+ # 镜像总下载:~2.8 GB (arm64) / ~3.0 GB (amd64);解压磁盘 ~6.5 GB
33
+ # 稳态内存预算:~1.5–2.0 GB(4 GB Pi 紧张,建议 8 GB Pi 5 / x86 节点)
34
+
35
+ tasks:
36
+ # ────────────────────────────────────────────────────────────────
37
+ # 1) PostgreSQL(ParadeDB:PG17 + pgvector + ParadeDB BM25 全文)
38
+ # role: sidecar → prestart 起来并持续运行;service tasks 在所有
39
+ # sidecar Running 后再启动(但 Running ≠ Ready,weknora-app 自己
40
+ # 要靠连接重试兜住 DB init 的 30s 窗口)。
41
+ # ────────────────────────────────────────────────────────────────
42
+ - name: paradedb
43
+ role: sidecar
44
+ runtime: container
45
+ image: "paradedb/paradedb:v0.22.2-pg17"
46
+ user: "host"
47
+ env:
48
+ POSTGRES_USER: "weknora"
49
+ # ⚠️ 开发默认值。生产请改:
50
+ # docker exec -it <container> psql -U weknora -c "ALTER USER weknora WITH PASSWORD '<new>'"
51
+ # 并同步更新 weknora-app 的 DB_PASSWORD。
52
+ POSTGRES_PASSWORD: "weknora-dev-pg-pw"
53
+ POSTGRES_DB: "WeKnora"
54
+ PGDATA: "/var/lib/postgresql/data/pgdata"
55
+ resources:
56
+ cpu: "500m"
57
+ memory: "384Mi"
58
+ ports:
59
+ - name: pg
60
+ port: 18093
61
+ container_port: 5432
62
+ visibility: external
63
+ host_network: docker_bridge
64
+ volumes:
65
+ - source: "~/.jishushell/apps/${app_id}/postgres"
66
+ target: "/var/lib/postgresql/data"
67
+
68
+ # ────────────────────────────────────────────────────────────────
69
+ # 2) Redis(任务队列 + Stream Manager 状态)
70
+ # ────────────────────────────────────────────────────────────────
71
+ - name: redis
72
+ role: sidecar
73
+ runtime: container
74
+ image: "redis:7.0-alpine"
75
+ user: "host"
76
+ args:
77
+ - "redis-server"
78
+ - "--appendonly"
79
+ - "yes"
80
+ # 无密码:仅 group 内 127.0.0.1 可达,未发布到宿主。
81
+ # 如需密码,加 --requirepass <pw> 并同步设 weknora-app 的 REDIS_PASSWORD。
82
+ resources:
83
+ cpu: "100m"
84
+ memory: "96Mi"
85
+ ports:
86
+ - name: redis
87
+ port: 18094
88
+ container_port: 6379
89
+ visibility: external
90
+ host_network: docker_bridge
91
+ volumes:
92
+ - source: "~/.jishushell/apps/${app_id}/redis"
93
+ target: "/data"
94
+
95
+ # ────────────────────────────────────────────────────────────────
96
+ # 3) docreader(最大头:1.7 GB;Python + markitdown + PDF 渲染)
97
+ # weknora-app `depends_on: docreader (service_healthy)` 是 core
98
+ # 依赖,**不能砍**。
99
+ # ────────────────────────────────────────────────────────────────
100
+ - name: docreader
101
+ role: sidecar
102
+ runtime: container
103
+ image: "wechatopenai/weknora-docreader:latest"
104
+ # Image entrypoint uses `uv` package manager which writes to /.cache/uv;
105
+ # forcing host uid (1000:1000) gets Permission denied on the root-owned
106
+ # filesystem and the container exits 2. Run as root — image is read-only
107
+ # in the layers that matter; runtime writes go to /tmp/docreader (bind
108
+ # mount, panel-user owned).
109
+ user: "0:0"
110
+ env:
111
+ DOCREADER_IMAGE_OUTPUT_DIR: "/tmp/docreader"
112
+ MAX_FILE_SIZE_MB: "50"
113
+ DOCREADER_MARKITDOWN_MAX_WORKERS: "1"
114
+ DOCREADER_PDF_RENDER_MAX_WORKERS: "1"
115
+ DOCREADER_PDF_RENDER_DPI: "200"
116
+ DOCREADER_PDF_JPEG_QUALITY: "90"
117
+ resources:
118
+ cpu: "800m"
119
+ memory: "768Mi"
120
+ ports:
121
+ - name: grpc
122
+ port: 18095
123
+ container_port: 50051
124
+ visibility: external
125
+ host_network: docker_bridge
126
+ volumes:
127
+ # tmp 目录与 weknora-app 共享,docreader 写 / app 读(图片提取场景)。
128
+ - source: "~/.jishushell/apps/${app_id}/docreader-tmp"
129
+ target: "/tmp/docreader"
130
+
131
+ # ────────────────────────────────────────────────────────────────
132
+ # 4) WeKnora 后端 app(Go)
133
+ # ────────────────────────────────────────────────────────────────
134
+ - name: app
135
+ role: service
136
+ runtime: container
137
+ image: "wechatopenai/weknora-app:latest"
138
+ # Image entrypoint chowns /app/skills/preloaded; with host uid the
139
+ # chown fails with "Operation not permitted" and the container crashes.
140
+ # Bind-mounted /data/files is panel-user owned (1000) — Go binary opens
141
+ # it as root without issue.
142
+ user: "0:0"
143
+ # panel default is cap_drop:ALL; weknora-app entrypoint does
144
+ # `chown -R appuser /app/skills/preloaded` at startup → needs CHOWN.
145
+ # It then `su appuser` to drop to non-root → needs SETUID/SETGID/SETPCAP.
146
+ cap_add: ["CHOWN", "FOWNER", "DAC_OVERRIDE", "SETUID", "SETGID", "SETPCAP"]
147
+ env:
148
+ # ── 基础运行时 ──
149
+ GIN_MODE: "release"
150
+ LOG_LEVEL: "info"
151
+ TZ: "Asia/Shanghai"
152
+ WEKNORA_LANGUAGE: "zh-CN"
153
+ DISABLE_REGISTRATION: "false"
154
+
155
+ # ── 数据库(host_network: docker_bridge → 绑 docker0 IP,
156
+ # host.docker.internal=172.17.0.1 容器内可达) ──
157
+ DB_DRIVER: "postgres"
158
+ DB_HOST: "host.docker.internal"
159
+ DB_PORT: "18093"
160
+ DB_USER: "weknora"
161
+ DB_PASSWORD: "weknora-dev-pg-pw"
162
+ DB_NAME: "WeKnora"
163
+
164
+ # ── 向量检索:走 paradedb 的 pgvector(砍 Qdrant / Milvus / Weaviate) ──
165
+ RETRIEVE_DRIVER: "postgres"
166
+
167
+ # ── Redis ──
168
+ REDIS_ADDR: "host.docker.internal:18094"
169
+ REDIS_DB: "0"
170
+ REDIS_PREFIX: "stream:"
171
+ STREAM_MANAGER_TYPE: "redis"
172
+
173
+ # ── docreader gRPC ──
174
+ DOCREADER_ADDR: "host.docker.internal:18095"
175
+ DOCREADER_TRANSPORT: "grpc"
176
+
177
+ # ── 文件存储:local 模式,写到 bind-mounted /data/files ──
178
+ STORAGE_TYPE: "local"
179
+ LOCAL_STORAGE_BASE_DIR: "/data/files"
180
+ MAX_FILE_SIZE_MB: "50"
181
+
182
+ # ── Sandbox:关。Agent 工具调用执行能力不可用,RAG 主流程不受影响。 ──
183
+ # 如需开启:(a) 把 weknora-sandbox 也加进 tasks[];(b) 改为
184
+ # WEKNORA_SANDBOX_MODE=docker;(c) 注意 sandbox 需要 docker.sock 挂载,
185
+ # Nomad 调度的容器内不一定有权限——可能需要额外设计。
186
+ WEKNORA_SANDBOX_MODE: "disabled"
187
+
188
+ # ── 安全密钥 ⚠️ 开发默认值,生产前必改 ──
189
+ # 推荐:openssl rand -hex 32 重新生成;同步改前端 NEXTAUTH_SECRET 之类。
190
+ JWT_SECRET: "weknora-dev-jwt-secret-CHANGE-ME-IN-PROD"
191
+ TENANT_AES_KEY: "weknora-dev-tenant-key-32bytes!!"
192
+ SYSTEM_AES_KEY: "weknora-dev-system-key-32bytes!!"
193
+
194
+ # ── LLM provider:留空,让用户在 WeKnora UI 里手动配。 ──
195
+ # 想用 panel 内嵌 LLM proxy(推荐)的话,UI 里填:
196
+ # base_url: http://host.docker.internal:8090/proxy/v1
197
+ # api_key: <从 panel /instances/:id 拿到的 sk-js-*>
198
+ # 这样审计 / 限流 / 上游切换都收敛在 panel 一层。
199
+ OLLAMA_BASE_URL: ""
200
+
201
+ # ── Tracing / Observability:全关 ──
202
+ LANGFUSE_ENABLED: "false"
203
+ OTEL_TRACES_EXPORTER: "none"
204
+ OTEL_METRICS_EXPORTER: "none"
205
+ OTEL_LOGS_EXPORTER: "none"
206
+ ENABLE_GRAPH_RAG: "false"
207
+ NEO4J_ENABLE: "false"
208
+
209
+ # ── 并发 ──
210
+ CONCURRENCY_POOL_SIZE: "5"
211
+
212
+ # ── SSRF 白名单:默认走 panel 反代,无需对外。 ──
213
+ SSRF_WHITELIST: ""
214
+ SSRF_WHITELIST_EXTRA: ""
215
+ resources:
216
+ cpu: "600m"
217
+ memory: "640Mi"
218
+ ports:
219
+ - name: http
220
+ # Published on docker0 so the ui task can reach backend via
221
+ # host.docker.internal:18096 (no shared netns on Pi w/o CNI).
222
+ port: 18096
223
+ container_port: 8080
224
+ visibility: external
225
+ host_network: docker_bridge
226
+ volumes:
227
+ # 知识库附件落盘。与 ~/.jishushell/files/ 故意分离 ——
228
+ # WeKnora 自己管文件元数据 / RAG 索引,避免与 panel W3 FTS5 打架。
229
+ - source: "~/.jishushell/apps/${app_id}/files"
230
+ target: "/data/files"
231
+
232
+ # ────────────────────────────────────────────────────────────────
233
+ # 5) WeKnora 前端 UI(nginx + Vue dist)
234
+ # ⚠️ 镜像不支持 BASE_URL 子路径 → 不走 panel /apps/weknora/* 反代,
235
+ # 用端口直连 18092。子路径要走需 fork 镜像(vite.config base + nginx
236
+ # location prefix),暂列为后续工作。
237
+ # ────────────────────────────────────────────────────────────────
238
+ - name: ui
239
+ role: service
240
+ runtime: container
241
+ image: "wechatopenai/weknora-ui:latest"
242
+ # nginx entrypoint needs to mkdir /var/cache/nginx/client_temp and
243
+ # rewrite /etc/nginx/conf.d/default.conf via envsubst — both require root.
244
+ # Host uid breaks both steps and the container crashloops.
245
+ user: "0:0"
246
+ # nginx master spawns workers as uid 101 (nginx user) and chowns the
247
+ # cache dir to it — needs CHOWN to do so even when master is root.
248
+ cap_add: ["CHOWN", "SETGID", "SETUID"]
249
+ env:
250
+ MAX_FILE_SIZE_MB: "50"
251
+ APP_HOST: "host.docker.internal"
252
+ APP_PORT: "18096"
253
+ APP_SCHEME: "http"
254
+ resources:
255
+ cpu: "100m"
256
+ memory: "48Mi"
257
+ ports:
258
+ - name: http
259
+ # 18092 在 panel 18xxx 范围内(filebrowser 18088 / openclaw-gw 18790)。
260
+ # 避开 OpenWebUI 3000、SearXNG 8080、panel 8090。
261
+ port: 18092
262
+ container_port: 80
263
+ visibility: external
264
+ volumes:
265
+ # 覆盖镜像内的 nginx 模板:上游模板带 `add_header X-Frame-Options
266
+ # SAMEORIGIN`,panel 实例详情页 iframe (origin=panel:8090) 嵌
267
+ # WeKnora UI (origin=panel:18092) 会被浏览器拒绝。我们这份完全
268
+ # 照搬上游 location 块,只去掉 X-Frame-Options/CSP 限制,保留
269
+ # ${APP_HOST}/${APP_PORT}/${APP_SCHEME}/${MAX_FILE_SIZE} 由镜像
270
+ # docker-entrypoint.sh envsubst。
271
+ - source: "~/.jishushell/apps/${app_id}/nginx/default.conf.template"
272
+ target: "/etc/nginx/templates/default.conf.template"
273
+ readonly: true
274
+ health:
275
+ http:
276
+ path: /
277
+ port: 80
278
+ interval: "15s"
279
+ timeout: "5s"
280
+ retries: 6
281
+ start_period: "60s" # 等 paradedb 初始化 + weknora-app boot + nginx 上线
282
+
283
+ provides:
284
+ # ⚠️ Capability 命名特意避开 `web-<slug>` 和 `<slug>-ui` 这两种 panel 顶层
285
+ # `/apps/<slug>/*` 反代会命中的模式(详见 src/server.ts:69 resolveAppSlugUpstream)。
286
+ # 原因:panel 反代**不去掉** `/apps/<slug>` 前缀(server.ts:382 注释),原样
287
+ # 转发给上游;而 WeKnora 前端镜像的 nginx 只 listen `/`、vite build 也没设
288
+ # `base`——任何 `/apps/weknora/*` 请求到了 ui 容器都会 404。
289
+ #
290
+ # 因此用 `knowledge-weknora`(业务命名、非通配前缀),让它**只**进 capability
291
+ # registry 供未来 agent `requires:` 注入使用,**不**触发 panel 顶层反代。
292
+ # 用户访问 UI 走端口直连:http://<host>:18092/。
293
+ - capability: "knowledge-weknora"
294
+ task: "ui"
295
+ port: 18092
296
+ path: "/"
297
+ protocol: "http"
298
+ visibility: "external"
299
+ # 强制 iframe 走 panel 反代而不是端口直连。原因:
300
+ # 1. 用户从 panel 8090 同源加载详情页,corp 防火墙 / VPN / 混合内容
301
+ # 策略可能让 8090 通但 18092 不通(典型:"refused to connect")。
302
+ # 2. nginx SAMEORIGIN/CSP 即便去掉了,浏览器 Private Network Access
303
+ # 仍可能拒绝跨网段 iframe;走 panel 反代后 iframe src 与 panel
304
+ # 同源,绕开所有边界检查。
305
+ # 3. WeKnora 前端 vite build 没设 `base`,绝对路径 `/api/...` 直接
306
+ # 打到 panel API → 但反代会把 base 改成 /api/instances/.../provides/
307
+ # /knowledge-weknora/,后续相对 fetch 正确(panel 反代有 base 重写)。
308
+ # Direct mode: iframe loads http://<host>:18092/ instead of the panel
309
+ # capability proxy. The proxy path approach kept tripping over WeKnora's
310
+ # axios 401 interceptor, which hard-codes `window.location.href = '/login'`
311
+ # and bounces the iframe to the panel root login page. Rewriting that
312
+ # literal at the proxy works for the assignment but the bundle has
313
+ # additional indirect navigations (vue-router fallback when pushState is
314
+ # blocked, internal pinia store actions) that aren't reachable from a
315
+ # text rewrite — same-origin iframe vs. direct iframe tradeoff favors
316
+ # direct here because the dev/internal browser already reaches 18092
317
+ # successfully (popout link confirmed working).
318
+ embedded: "direct"
319
+ description: "WeKnora 知识库 Web UI"
320
+
321
+ lifecycle:
322
+ install:
323
+ # 镜像按尺寸升序下载:小的先稳,大的(docreader 1.7GB)放最后,
324
+ # 万一失败下次重试时小的全部 skip,从大的断点续。
325
+ - downloadImage: "redis:7.0-alpine"
326
+ - downloadImage: "wechatopenai/weknora-ui:latest"
327
+ - downloadImage: "wechatopenai/weknora-app:latest"
328
+ - downloadImage: "paradedb/paradedb:v0.22.2-pg17"
329
+ # docreader 单独给 30 分钟总超时 + 30 分钟 idle 超时(1.7GB 内含 400MB+ 的
330
+ # 大 layer;Pi 带宽 ~2 MB/s 下单 layer 下载耗时可超 panel 默认 180s idle
331
+ # → 误判 stalled。设 30 分钟 idle 给慢网充足时间)。
332
+ - downloadImage: "wechatopenai/weknora-docreader:latest"
333
+ timeout_ms: 1800000
334
+ idle_timeout_ms: 1800000
335
+
336
+ - mkdir: "~/.jishushell/apps/${app_id}/postgres"
337
+ - mkdir: "~/.jishushell/apps/${app_id}/redis"
338
+ - mkdir: "~/.jishushell/apps/${app_id}/docreader-tmp"
339
+ - mkdir: "~/.jishushell/apps/${app_id}/files"
340
+ - mkdir: "~/.jishushell/apps/${app_id}/nginx"
341
+ # 写自定义 nginx 模板(去掉 X-Frame-Options 让 panel 实例详情页能
342
+ # iframe 嵌入)。单引号 heredoc 关掉 shell 展开,保留 ${APP_HOST}/
343
+ # ${APP_PORT}/${APP_SCHEME}/${MAX_FILE_SIZE} 由镜像 envsubst 替换。
344
+ - run: |
345
+ set -e
346
+ TPL="$HOME/.jishushell/apps/${app_id}/nginx/default.conf.template"
347
+ cat > "$TPL" <<'NGX'
348
+ server {
349
+ listen 80;
350
+ server_name localhost;
351
+
352
+ client_max_body_size ${MAX_FILE_SIZE};
353
+
354
+ gzip on;
355
+ gzip_min_length 1024;
356
+ gzip_comp_level 6;
357
+ gzip_types text/plain text/css application/json application/javascript
358
+ application/xml text/xml application/x-javascript;
359
+
360
+ # X-Frame-Options 故意不发:panel 实例详情页 (origin=panel:8090)
361
+ # 要 iframe 嵌入本服务 (origin=panel:18092),原版 SAMEORIGIN
362
+ # 会被浏览器拒。其余安全头照旧。
363
+ add_header X-Content-Type-Options nosniff always;
364
+ add_header Referrer-Policy strict-origin-when-cross-origin always;
365
+
366
+ location /assets/ {
367
+ root /usr/share/nginx/html;
368
+ expires max;
369
+ add_header Cache-Control "public, max-age=31536000, immutable";
370
+ }
371
+
372
+ location = /files {
373
+ proxy_pass ${APP_SCHEME}://${APP_HOST}:${APP_PORT}/files;
374
+ proxy_http_version 1.1;
375
+ proxy_set_header Host $host;
376
+ proxy_set_header X-Real-IP $remote_addr;
377
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
378
+ }
379
+
380
+ location /api/ {
381
+ proxy_pass ${APP_SCHEME}://${APP_HOST}:${APP_PORT}/api/;
382
+ proxy_http_version 1.1;
383
+ proxy_set_header Host $host;
384
+ proxy_set_header X-Real-IP $remote_addr;
385
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
386
+ proxy_set_header Connection "";
387
+ proxy_buffering off;
388
+ proxy_cache off;
389
+ proxy_read_timeout 3600s;
390
+ proxy_send_timeout 3600s;
391
+ proxy_connect_timeout 30s;
392
+ proxy_next_upstream error timeout http_502 http_503 http_504;
393
+ proxy_next_upstream_tries 3;
394
+ }
395
+
396
+ location / {
397
+ root /usr/share/nginx/html;
398
+ try_files $uri $uri/ /index.html;
399
+ add_header Cache-Control "no-cache, must-revalidate";
400
+ }
401
+ }
402
+ NGX
403
+ chmod 644 "$TPL"
404
+ echo "[install] wrote nginx template (no X-Frame-Options) → $TPL"
405
+
406
+ pre_start:
407
+ # 幂等:start/restart 都过这条路径,目录被误删可自愈。
408
+ - mkdir: "~/.jishushell/apps/${app_id}/postgres"
409
+ - mkdir: "~/.jishushell/apps/${app_id}/redis"
410
+ - mkdir: "~/.jishushell/apps/${app_id}/docreader-tmp"
411
+ - mkdir: "~/.jishushell/apps/${app_id}/files"
412
+ - mkdir: "~/.jishushell/apps/${app_id}/nginx"
413
+ - run: |
414
+ set -e
415
+ TPL="$HOME/.jishushell/apps/${app_id}/nginx/default.conf.template"
416
+ if [ ! -f "$TPL" ]; then
417
+ cat > "$TPL" <<'NGX'
418
+ server {
419
+ listen 80;
420
+ server_name localhost;
421
+ client_max_body_size ${MAX_FILE_SIZE};
422
+ gzip on;
423
+ gzip_min_length 1024;
424
+ gzip_comp_level 6;
425
+ gzip_types text/plain text/css application/json application/javascript
426
+ application/xml text/xml application/x-javascript;
427
+ add_header X-Content-Type-Options nosniff always;
428
+ add_header Referrer-Policy strict-origin-when-cross-origin always;
429
+ location /assets/ {
430
+ root /usr/share/nginx/html;
431
+ expires max;
432
+ add_header Cache-Control "public, max-age=31536000, immutable";
433
+ }
434
+ location = /files {
435
+ proxy_pass ${APP_SCHEME}://${APP_HOST}:${APP_PORT}/files;
436
+ proxy_http_version 1.1;
437
+ proxy_set_header Host $host;
438
+ proxy_set_header X-Real-IP $remote_addr;
439
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
440
+ }
441
+ location /api/ {
442
+ proxy_pass ${APP_SCHEME}://${APP_HOST}:${APP_PORT}/api/;
443
+ proxy_http_version 1.1;
444
+ proxy_set_header Host $host;
445
+ proxy_set_header X-Real-IP $remote_addr;
446
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
447
+ proxy_set_header Connection "";
448
+ proxy_buffering off;
449
+ proxy_cache off;
450
+ proxy_read_timeout 3600s;
451
+ proxy_send_timeout 3600s;
452
+ proxy_connect_timeout 30s;
453
+ proxy_next_upstream error timeout http_502 http_503 http_504;
454
+ proxy_next_upstream_tries 3;
455
+ }
456
+ location / {
457
+ root /usr/share/nginx/html;
458
+ try_files $uri $uri/ /index.html;
459
+ add_header Cache-Control "no-cache, must-revalidate";
460
+ }
461
+ }
462
+ NGX
463
+ chmod 644 "$TPL"
464
+ fi
465
+
466
+ uninstall:
467
+ - deleteImage: "wechatopenai/weknora-docreader:latest"
468
+ - deleteImage: "paradedb/paradedb:v0.22.2-pg17"
469
+ - deleteImage: "wechatopenai/weknora-app:latest"
470
+ - deleteImage: "wechatopenai/weknora-ui:latest"
471
+ - deleteImage: "redis:7.0-alpine"