siclaw 0.1.1 → 0.1.2

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 (267) hide show
  1. package/README.md +74 -114
  2. package/dist/agentbox/gateway-client.d.ts +2 -1
  3. package/dist/agentbox/gateway-client.js +6 -2
  4. package/dist/agentbox/gateway-client.js.map +1 -1
  5. package/dist/agentbox/http-server.js +184 -19
  6. package/dist/agentbox/http-server.js.map +1 -1
  7. package/dist/agentbox/resource-handlers.d.ts +1 -0
  8. package/dist/agentbox/resource-handlers.js +23 -23
  9. package/dist/agentbox/resource-handlers.js.map +1 -1
  10. package/dist/agentbox/session.js +85 -5
  11. package/dist/agentbox/session.js.map +1 -1
  12. package/dist/agentbox-main.d.ts +2 -1
  13. package/dist/agentbox-main.js +65 -18
  14. package/dist/agentbox-main.js.map +1 -1
  15. package/dist/cli-credentials.d.ts +1 -0
  16. package/dist/cli-credentials.js +109 -0
  17. package/dist/cli-credentials.js.map +1 -0
  18. package/dist/cli-first-run.d.ts +11 -0
  19. package/dist/cli-first-run.js +99 -0
  20. package/dist/cli-first-run.js.map +1 -0
  21. package/dist/cli-main.js +33 -11
  22. package/dist/cli-main.js.map +1 -1
  23. package/dist/cli-setup.d.ts +5 -11
  24. package/dist/cli-setup.js +12 -225
  25. package/dist/cli-setup.js.map +1 -1
  26. package/dist/core/agent-factory.d.ts +4 -0
  27. package/dist/core/agent-factory.js +102 -151
  28. package/dist/core/agent-factory.js.map +1 -1
  29. package/dist/core/config.d.ts +10 -3
  30. package/dist/core/config.js +11 -95
  31. package/dist/core/config.js.map +1 -1
  32. package/dist/core/extensions/deep-investigation.d.ts +2 -1
  33. package/dist/core/extensions/deep-investigation.js +144 -24
  34. package/dist/core/extensions/deep-investigation.js.map +1 -1
  35. package/dist/core/extensions/setup.d.ts +8 -0
  36. package/dist/core/extensions/setup.js +669 -0
  37. package/dist/core/extensions/setup.js.map +1 -0
  38. package/dist/core/llm-proxy.js +7 -3
  39. package/dist/core/llm-proxy.js.map +1 -1
  40. package/dist/core/mcp-client.d.ts +0 -10
  41. package/dist/core/mcp-client.js +0 -65
  42. package/dist/core/mcp-client.js.map +1 -1
  43. package/dist/core/prompt.d.ts +1 -1
  44. package/dist/core/prompt.js +42 -5
  45. package/dist/core/prompt.js.map +1 -1
  46. package/dist/core/provider-presets.d.ts +14 -0
  47. package/dist/core/provider-presets.js +81 -0
  48. package/dist/core/provider-presets.js.map +1 -0
  49. package/dist/cron/cron-coordinator.d.ts +2 -0
  50. package/dist/cron/cron-coordinator.js +46 -14
  51. package/dist/cron/cron-coordinator.js.map +1 -1
  52. package/dist/cron/cron-executor.js +33 -8
  53. package/dist/cron/cron-executor.js.map +1 -1
  54. package/dist/cron/cron-scheduler.d.ts +1 -1
  55. package/dist/cron/gateway-client.d.ts +5 -0
  56. package/dist/cron/gateway-client.js +43 -8
  57. package/dist/cron/gateway-client.js.map +1 -1
  58. package/dist/cron-main.js +39 -9
  59. package/dist/cron-main.js.map +1 -1
  60. package/dist/gateway/agentbox/client.d.ts +11 -0
  61. package/dist/gateway/agentbox/client.js +18 -0
  62. package/dist/gateway/agentbox/client.js.map +1 -1
  63. package/dist/gateway/agentbox/k8s-spawner.d.ts +11 -2
  64. package/dist/gateway/agentbox/k8s-spawner.js +95 -52
  65. package/dist/gateway/agentbox/k8s-spawner.js.map +1 -1
  66. package/dist/gateway/agentbox/local-spawner.d.ts +1 -1
  67. package/dist/gateway/agentbox/local-spawner.js +4 -2
  68. package/dist/gateway/agentbox/local-spawner.js.map +1 -1
  69. package/dist/gateway/agentbox/manager.d.ts +0 -10
  70. package/dist/gateway/agentbox/manager.js +11 -30
  71. package/dist/gateway/agentbox/manager.js.map +1 -1
  72. package/dist/gateway/agentbox/types.d.ts +6 -4
  73. package/dist/gateway/cron/cron-service.d.ts +49 -0
  74. package/dist/gateway/cron/cron-service.js +259 -0
  75. package/dist/gateway/cron/cron-service.js.map +1 -0
  76. package/dist/gateway/db/init-schema.js +44 -0
  77. package/dist/gateway/db/init-schema.js.map +1 -1
  78. package/dist/gateway/db/migrate-sqlite.js +73 -4
  79. package/dist/gateway/db/migrate-sqlite.js.map +1 -1
  80. package/dist/gateway/db/repositories/chat-repo.d.ts +56 -2
  81. package/dist/gateway/db/repositories/chat-repo.js +132 -2
  82. package/dist/gateway/db/repositories/chat-repo.js.map +1 -1
  83. package/dist/gateway/db/repositories/config-repo.d.ts +31 -2
  84. package/dist/gateway/db/repositories/config-repo.js +57 -7
  85. package/dist/gateway/db/repositories/config-repo.js.map +1 -1
  86. package/dist/gateway/db/repositories/env-repo.d.ts +14 -0
  87. package/dist/gateway/db/repositories/env-repo.js +15 -2
  88. package/dist/gateway/db/repositories/env-repo.js.map +1 -1
  89. package/dist/gateway/db/repositories/model-config-repo.js +6 -5
  90. package/dist/gateway/db/repositories/model-config-repo.js.map +1 -1
  91. package/dist/gateway/db/repositories/skill-repo.d.ts +0 -5
  92. package/dist/gateway/db/repositories/skill-review-repo.d.ts +1 -0
  93. package/dist/gateway/db/repositories/skill-review-repo.js +4 -1
  94. package/dist/gateway/db/repositories/skill-review-repo.js.map +1 -1
  95. package/dist/gateway/db/repositories/skill-version-repo.js +0 -1
  96. package/dist/gateway/db/repositories/skill-version-repo.js.map +1 -1
  97. package/dist/gateway/db/repositories/system-config-repo.d.ts +1 -1
  98. package/dist/gateway/db/repositories/system-config-repo.js +2 -1
  99. package/dist/gateway/db/repositories/system-config-repo.js.map +1 -1
  100. package/dist/gateway/db/repositories/user-env-config-repo.d.ts +13 -0
  101. package/dist/gateway/db/repositories/user-env-config-repo.js +11 -0
  102. package/dist/gateway/db/repositories/user-env-config-repo.js.map +1 -1
  103. package/dist/gateway/db/repositories/workspace-repo.d.ts +3 -2
  104. package/dist/gateway/db/repositories/workspace-repo.js +6 -2
  105. package/dist/gateway/db/repositories/workspace-repo.js.map +1 -1
  106. package/dist/gateway/db/schema-mysql.d.ts +473 -51
  107. package/dist/gateway/db/schema-mysql.js +35 -4
  108. package/dist/gateway/db/schema-mysql.js.map +1 -1
  109. package/dist/gateway/db/schema-sqlite.d.ts +522 -57
  110. package/dist/gateway/db/schema-sqlite.js +38 -6
  111. package/dist/gateway/db/schema-sqlite.js.map +1 -1
  112. package/dist/gateway/db/schema.d.ts +471 -51
  113. package/dist/gateway/db/schema.js +1 -1
  114. package/dist/gateway/db/schema.js.map +1 -1
  115. package/dist/gateway/metrics-aggregator.d.ts +65 -0
  116. package/dist/gateway/metrics-aggregator.js +244 -0
  117. package/dist/gateway/metrics-aggregator.js.map +1 -0
  118. package/dist/gateway/plugins/channel-bridge.d.ts +4 -1
  119. package/dist/gateway/plugins/channel-bridge.js +78 -86
  120. package/dist/gateway/plugins/channel-bridge.js.map +1 -1
  121. package/dist/gateway/rpc-methods.d.ts +4 -2
  122. package/dist/gateway/rpc-methods.js +852 -166
  123. package/dist/gateway/rpc-methods.js.map +1 -1
  124. package/dist/gateway/security/cert-manager.d.ts +2 -2
  125. package/dist/gateway/security/cert-manager.js +4 -2
  126. package/dist/gateway/security/cert-manager.js.map +1 -1
  127. package/dist/gateway/server.d.ts +4 -8
  128. package/dist/gateway/server.js +297 -261
  129. package/dist/gateway/server.js.map +1 -1
  130. package/dist/gateway/skills/file-writer.js +17 -11
  131. package/dist/gateway/skills/file-writer.js.map +1 -1
  132. package/dist/gateway/skills/script-evaluator.js +12 -9
  133. package/dist/gateway/skills/script-evaluator.js.map +1 -1
  134. package/dist/gateway/web/dist/assets/index-0p17ZeTP.js +740 -0
  135. package/dist/gateway/web/dist/assets/index-9eP6nPUq.js +741 -0
  136. package/dist/gateway/web/dist/assets/index-9eP6nPUq.js.map +1 -0
  137. package/dist/gateway/web/dist/assets/index-DyowBCEj.css +1 -0
  138. package/dist/gateway/web/dist/assets/index-PDK5JJDO.css +1 -0
  139. package/dist/gateway/web/dist/index.html +2 -2
  140. package/dist/gateway-main.js +27 -10
  141. package/dist/gateway-main.js.map +1 -1
  142. package/dist/memory/embeddings.js +5 -4
  143. package/dist/memory/embeddings.js.map +1 -1
  144. package/dist/memory/indexer.d.ts +23 -3
  145. package/dist/memory/indexer.js +235 -23
  146. package/dist/memory/indexer.js.map +1 -1
  147. package/dist/memory/schema.js +15 -1
  148. package/dist/memory/schema.js.map +1 -1
  149. package/dist/memory/types.d.ts +18 -0
  150. package/dist/memory/types.js +6 -1
  151. package/dist/memory/types.js.map +1 -1
  152. package/dist/shared/detect-language.d.ts +12 -0
  153. package/dist/shared/detect-language.js +78 -0
  154. package/dist/shared/detect-language.js.map +1 -0
  155. package/dist/shared/diagnostic-events.d.ts +70 -0
  156. package/dist/shared/diagnostic-events.js +38 -0
  157. package/dist/shared/diagnostic-events.js.map +1 -0
  158. package/dist/shared/local-collector.d.ts +56 -0
  159. package/dist/shared/local-collector.js +284 -0
  160. package/dist/shared/local-collector.js.map +1 -0
  161. package/dist/shared/metrics-types.d.ts +64 -0
  162. package/dist/shared/metrics-types.js +25 -0
  163. package/dist/shared/metrics-types.js.map +1 -0
  164. package/dist/shared/metrics.d.ts +19 -0
  165. package/dist/shared/metrics.js +185 -0
  166. package/dist/shared/metrics.js.map +1 -0
  167. package/dist/shared/path-utils.d.ts +15 -0
  168. package/dist/shared/path-utils.js +23 -0
  169. package/dist/shared/path-utils.js.map +1 -0
  170. package/dist/shared/retry.d.ts +35 -0
  171. package/dist/shared/retry.js +61 -0
  172. package/dist/shared/retry.js.map +1 -0
  173. package/dist/tools/command-sets.d.ts +18 -2
  174. package/dist/tools/command-sets.js +207 -32
  175. package/dist/tools/command-sets.js.map +1 -1
  176. package/dist/tools/command-validator.d.ts +56 -0
  177. package/dist/tools/command-validator.js +357 -0
  178. package/dist/tools/command-validator.js.map +1 -0
  179. package/dist/tools/create-skill.js +26 -1
  180. package/dist/tools/create-skill.js.map +1 -1
  181. package/dist/tools/credential-list.js +1 -23
  182. package/dist/tools/credential-list.js.map +1 -1
  183. package/dist/tools/credential-manager.d.ts +98 -0
  184. package/dist/tools/credential-manager.js +313 -0
  185. package/dist/tools/credential-manager.js.map +1 -0
  186. package/dist/tools/deep-search/engine.js +184 -127
  187. package/dist/tools/deep-search/engine.js.map +1 -1
  188. package/dist/tools/deep-search/prompts.d.ts +10 -2
  189. package/dist/tools/deep-search/prompts.js +37 -36
  190. package/dist/tools/deep-search/prompts.js.map +1 -1
  191. package/dist/tools/deep-search/schemas.d.ts +87 -0
  192. package/dist/tools/deep-search/schemas.js +85 -0
  193. package/dist/tools/deep-search/schemas.js.map +1 -0
  194. package/dist/tools/deep-search/sub-agent.d.ts +21 -0
  195. package/dist/tools/deep-search/sub-agent.js +153 -4
  196. package/dist/tools/deep-search/sub-agent.js.map +1 -1
  197. package/dist/tools/deep-search/tool.js +1 -0
  198. package/dist/tools/deep-search/tool.js.map +1 -1
  199. package/dist/tools/deep-search/types.d.ts +2 -0
  200. package/dist/tools/deep-search/types.js.map +1 -1
  201. package/dist/tools/dp-tools.js +29 -5
  202. package/dist/tools/dp-tools.js.map +1 -1
  203. package/dist/tools/exec-utils.d.ts +85 -0
  204. package/dist/tools/exec-utils.js +294 -0
  205. package/dist/tools/exec-utils.js.map +1 -0
  206. package/dist/tools/fork-skill.js +14 -2
  207. package/dist/tools/fork-skill.js.map +1 -1
  208. package/dist/tools/investigation-feedback.d.ts +3 -0
  209. package/dist/tools/investigation-feedback.js +71 -0
  210. package/dist/tools/investigation-feedback.js.map +1 -0
  211. package/dist/tools/manage-schedule.js +16 -6
  212. package/dist/tools/manage-schedule.js.map +1 -1
  213. package/dist/tools/netns-script.js +27 -281
  214. package/dist/tools/netns-script.js.map +1 -1
  215. package/dist/tools/node-exec.d.ts +2 -14
  216. package/dist/tools/node-exec.js +18 -225
  217. package/dist/tools/node-exec.js.map +1 -1
  218. package/dist/tools/node-script.js +14 -168
  219. package/dist/tools/node-script.js.map +1 -1
  220. package/dist/tools/pod-exec.d.ts +1 -1
  221. package/dist/tools/pod-exec.js +10 -26
  222. package/dist/tools/pod-exec.js.map +1 -1
  223. package/dist/tools/pod-nsenter-exec.js +21 -225
  224. package/dist/tools/pod-nsenter-exec.js.map +1 -1
  225. package/dist/tools/pod-script.js +10 -19
  226. package/dist/tools/pod-script.js.map +1 -1
  227. package/dist/tools/restricted-bash.d.ts +1 -17
  228. package/dist/tools/restricted-bash.js +38 -252
  229. package/dist/tools/restricted-bash.js.map +1 -1
  230. package/dist/tools/run-skill.d.ts +3 -1
  231. package/dist/tools/run-skill.js +21 -1
  232. package/dist/tools/run-skill.js.map +1 -1
  233. package/dist/tools/script-resolver.d.ts +3 -1
  234. package/dist/tools/script-resolver.js +74 -30
  235. package/dist/tools/script-resolver.js.map +1 -1
  236. package/dist/tools/update-skill.js +17 -6
  237. package/dist/tools/update-skill.js.map +1 -1
  238. package/package.json +4 -2
  239. package/siclaw.mjs +10 -1
  240. package/skills/core/cluster-events/SKILL.md +1 -1
  241. package/skills/core/deep-investigation/SKILL.md +11 -0
  242. package/skills/core/deployment-rollout-debug/SKILL.md +1 -1
  243. package/skills/core/dns-debug/SKILL.md +1 -0
  244. package/skills/core/meta.json +12 -1
  245. package/skills/core/networkpolicy-debug/SKILL.md +332 -0
  246. package/skills/core/node-logs/scripts/get-node-logs.sh +19 -9
  247. package/skills/core/pod-pending-debug/SKILL.md +1 -0
  248. package/skills/core/quota-debug/SKILL.md +203 -0
  249. package/skills/core/service-debug/SKILL.md +1 -0
  250. package/skills/core/statefulset-debug/SKILL.md +280 -0
  251. package/skills/core/volcano-diagnose-pod/SKILL.md +196 -0
  252. package/skills/core/volcano-diagnose-pod/scripts/diagnose-pod.sh +175 -0
  253. package/skills/core/volcano-gang-scheduling/SKILL.md +299 -0
  254. package/skills/core/volcano-job-diagnose/SKILL.md +319 -0
  255. package/skills/core/volcano-job-diagnose/scripts/diagnose-job.sh +253 -0
  256. package/skills/core/volcano-node-resources/SKILL.md +334 -0
  257. package/skills/core/volcano-node-resources/scripts/get-node-resources.sh +281 -0
  258. package/skills/core/volcano-queue-diagnose/SKILL.md +294 -0
  259. package/skills/core/volcano-queue-diagnose/scripts/diagnose-queue.sh +283 -0
  260. package/skills/core/volcano-resource-insufficient/SKILL.md +315 -0
  261. package/skills/core/volcano-scheduler-config/SKILL.md +371 -0
  262. package/skills/core/volcano-scheduler-config/scripts/get-scheduler-config.sh +297 -0
  263. package/skills/core/volcano-scheduler-logs/SKILL.md +241 -0
  264. package/skills/core/volcano-scheduler-logs/scripts/get-scheduler-logs.sh +159 -0
  265. package/skills/platform/create-skill/SKILL.md +35 -3
  266. package/skills/platform/manage-skill/SKILL.md +9 -2
  267. package/skills/platform/update-skill/SKILL.md +17 -6
package/README.md CHANGED
@@ -4,32 +4,37 @@
4
4
 
5
5
  # Siclaw
6
6
 
7
- **AI Agent platform for SRE — the collaborative AI foundation for your team**
7
+ **Read-only investigation copilot for SRE teams**
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/siclaw?logo=npm)](https://www.npmjs.com/package/siclaw)
10
10
  [![CI](https://github.com/scitix/siclaw/actions/workflows/ci.yml/badge.svg)](https://github.com/scitix/siclaw/actions/workflows/ci.yml)
11
11
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
12
12
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
13
13
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
14
+ [![Slack](https://img.shields.io/badge/Slack-Join%20Community-4A154B?logo=slack&logoColor=white)](https://join.slack.com/t/siclaw-scitix/shared_invite/zt-3rrsoc2ic-JIfbfvT1_04sqgQorSRfmw)
14
15
 
16
+ [Website](https://www.siclaw.ai) | [Documentation](https://docs.siclaw.ai) | [Slack](https://join.slack.com/t/siclaw-scitix/shared_invite/zt-3rrsoc2ic-JIfbfvT1_04sqgQorSRfmw)
15
17
 
16
18
  </div>
17
19
 
18
20
  ---
19
21
 
20
- Siclaw is an AI Agent platform for DevOps / SRE, inspired by [OpenClaw](https://github.com/openclaw) and designed to be the collaborative AI foundation for engineering teams. Unlike general-purpose coding agents, Siclaw is built for **read-only infrastructure diagnostics** the agent observes, analyzes, and reports, but never mutates your environment directly. When remediation is needed, Siclaw integrates with your existing change management systems to execute changes through established, auditable workflows. Describe a problem in plain language and the agent runs kubectl, reads logs, traces network paths, and delivers a root-cause analysis — from a terminal, a web UI, or your team's IM workspace.
22
+ Siclaw is an open-source AI agent for DevOps and SRE teams. It is built for **read-only infrastructure diagnostics**: gather evidence, form hypotheses, validate them, and return a clear root-cause analysis without changing your environment directly. Describe a problem in plain language and Siclaw investigates it from the terminal, the web UI, or your team's chat channels.
23
+
24
+ <div align="center">
25
+ <img src="docs/assets/demo.gif" alt="Siclaw Demo" width="800" />
26
+ <p><em>Deep investigation: diagnosing a CrashLoopBackOff in seconds</em></p>
27
+ </div>
21
28
 
22
29
  ## Features
23
30
 
24
- - **Deep Investigation** — Hypothesis-driven 4-phase diagnostic engine (context gathering hypothesis generation parallel validation → root-cause conclusion), bringing Deep Research to SRE with cross-system, multi-dimensional fault analysis
25
- - **Investigation Memory** — Accumulates structured knowledge from every deep investigation into a local hybrid store (vector + full-text); surfaces relevant past experience during hypothesis generation so the agent gets smarter with every incident resolved
26
- - **Security Governance** — Strict permission layer between agent and infrastructure: read-only by default, command whitelist, write operations require per-item approval, credentials isolated by workspace — zero accidental mutations in production
27
- - **Team Collaboration** — Multi-workspace, multi-user management (SSO/OAuth2), isolated AgentBox sandboxes per user, designed for multi-team, multi-environment enterprise scenarios
28
- - **Alert-Driven Operations** — Webhook triggers connect to your existing monitoring stack (Prometheus, PagerDuty, custom), automatically launching agent investigations when alerts fire
29
- - **Scheduled Tasks** — Cron-based recurring jobs for routine health checks, periodic diagnostics, or any agent task — manageable via Web UI or natural language
30
- - **Skill System** — AI-generated diagnostic skills with automated risk-level review, supporting creation, forking, and hot-reload via Web UI or natural language — organize across core / team / personal tiers to codify your team's operational expertise into reusable, shareable runbooks
31
- - **Extensible** — [MCP](https://modelcontextprotocol.io) tool servers for custom data source integrations
32
- - **Multi-Channel Access** — Terminal TUI, Web UI, or IM bots (Slack, Discord, Telegram, Lark)
31
+ - **Deep Investigation** — A 4-phase workflow for evidence gathering, hypothesis testing, and root-cause analysis
32
+ - **Investigation Memory** — Learns from past incidents to improve future investigations
33
+ - **Read-Only by Default** — Investigates and recommends next steps without changing your environment directly
34
+ - **Team Workflows** — Shared web UI, credentials, channels, triggers, and scheduled patrols
35
+ - **Reusable Skills** — Turn repeated diagnostic playbooks into reviewable runbooks
36
+ - **Extensible** — Connect external tools and data sources through [MCP](https://modelcontextprotocol.io)
37
+ - **Multi-Channel Access** — Use Siclaw from the terminal, web UI, or chat channels
33
38
 
34
39
  ## Architecture
35
40
 
@@ -44,28 +49,33 @@ Siclaw is an AI Agent platform for DevOps / SRE, inspired by [OpenClaw](https://
44
49
 
45
50
  - **Node.js >= 22.12.0** — [Download](https://nodejs.org/)
46
51
  - **npm** — Comes with Node.js
47
- - **kubectl** + **kubeconfig** Required for Kubernetes diagnostics only ([Install guide](https://kubernetes.io/docs/tasks/tools/)); not needed for TUI or Local Server mode without K8s access
52
+ - **kubectl** — Optional, only needed if you want Siclaw to investigate Kubernetes clusters
48
53
 
49
54
  ## Quick Start
50
55
 
51
- Siclaw supports three deployment profiles. Pick the one that fits your use case.
56
+ Siclaw supports three deployment profiles. For local usage, start from a dedicated working directory because Siclaw stores most runtime data in `.siclaw/` relative to where you launch it.
57
+
58
+ ```bash
59
+ mkdir -p ~/siclaw-work
60
+ cd ~/siclaw-work
61
+ ```
52
62
 
53
63
  ### 1. TUI Mode — Personal, local, lowest barrier
54
64
 
55
65
  Run the agent directly in your terminal. No server, no database. All operations are read-only by default — safe to run on your workstation.
56
66
 
57
67
  ```bash
58
- # Install
59
- npm install siclaw
68
+ # Install globally
69
+ npm install -g siclaw
60
70
 
61
71
  # Run (interactive — prompts for LLM provider on first launch)
62
- npx siclaw
72
+ siclaw
63
73
 
64
74
  # Single-shot
65
- npx siclaw --prompt "Why is pod nginx-abc in CrashLoopBackOff?"
75
+ siclaw --prompt "Why is pod nginx-abc in CrashLoopBackOff?"
66
76
 
67
77
  # Continue last session
68
- npx siclaw --continue
78
+ siclaw --continue
69
79
  ```
70
80
 
71
81
  <details>
@@ -73,7 +83,7 @@ npx siclaw --continue
73
83
 
74
84
  ```bash
75
85
  git clone https://github.com/scitix/siclaw.git && cd siclaw
76
- npm ci && npm run build
86
+ npm ci && npm run build:web && npm run build
77
87
  npm link # register `siclaw` command globally
78
88
 
79
89
  siclaw # TUI mode
@@ -88,17 +98,18 @@ siclaw --prompt "..." # single-shot mode
88
98
 
89
99
  ### 2. Local Server — VM or laptop, recommended for daily use
90
100
 
91
- A lightweight web UI backed by SQLite. No MySQL, no Docker required — just start the server and configure everything in the browser. Siclaw enforces strict read-only access by default (command whitelist, no write operations without approval), so you can safely deploy it on your own workstation without worrying about unintended changes to your clusters.
101
+ A lightweight web UI backed by SQLite. No MySQL, no Docker required.
92
102
 
93
103
  ```bash
94
- npm install siclaw
104
+ npm install -g siclaw
95
105
 
96
- # Start the server (SQLite database is created automatically)
97
- npx siclaw local
106
+ # Start the server
107
+ siclaw local
98
108
 
99
109
  # Open http://localhost:3000
100
110
  # Login: admin / admin (default credentials)
101
- # Go to Settings to configure your LLM provider
111
+ # Configure providers in Models
112
+ # Import kubeconfigs in Credentials
102
113
  ```
103
114
 
104
115
  <details>
@@ -106,7 +117,7 @@ npx siclaw local
106
117
 
107
118
  ```bash
108
119
  git clone https://github.com/scitix/siclaw.git && cd siclaw
109
- npm ci && npm run build && npm run build:web
120
+ npm ci && npm run build:web && npm run build
110
121
  npm link # register `siclaw` command globally
111
122
 
112
123
  siclaw local # start local server
@@ -116,43 +127,47 @@ siclaw local # start local server
116
127
 
117
128
  </details>
118
129
 
119
- The server uses SQLite by default and auto-generates a JWT secret on first run. All configuration — LLM providers, models, credentials is done through the **Settings** page in the web UI.
130
+ On first startup, Siclaw creates a local admin account:
131
+
132
+ - Username: `admin`
133
+ - Password: `admin`
134
+
135
+ Set `SICLAW_ADMIN_PASSWORD` before first launch if you want a different bootstrap password.
120
136
 
121
137
  ### 3. Kubernetes — Team / enterprise
122
138
 
123
- Full multi-user deployment with isolated AgentBox pods, SSO, and IM channels. Just prepare a MySQL database and deploy with Helm:
139
+ Production deployment uses Helm plus three container images: `gateway`, `agentbox`, and `cron`.
140
+
141
+ Build and push images if you are using your own registry:
124
142
 
125
143
  ```bash
126
- helm upgrade --install siclaw ./helm/siclaw \
127
- --namespace siclaw --create-namespace \
128
- --set database.url="mysql://user:pass@host:3306/siclaw"
144
+ make docker REGISTRY=registry.example.com/myteam TAG=latest
145
+ make push REGISTRY=registry.example.com/myteam TAG=latest
129
146
  ```
130
147
 
131
- <details>
132
- <summary><b>Using a custom image registry</b></summary>
133
-
134
- If you need to build and push images to your own registry:
148
+ Then deploy the chart with a MySQL URL:
135
149
 
136
150
  ```bash
137
- # Build and push images
138
- make docker push REGISTRY=registry.example.com/myteam
139
-
140
- # Deploy with custom registry
141
151
  helm upgrade --install siclaw ./helm/siclaw \
142
- --namespace siclaw --create-namespace \
143
- --set image.registry="registry.example.com/myteam" \
152
+ --namespace siclaw \
153
+ --create-namespace \
154
+ --set image.registry=registry.example.com/myteam \
155
+ --set image.tag=latest \
144
156
  --set database.url="mysql://user:pass@host:3306/siclaw"
145
157
  ```
146
158
 
147
- </details>
148
-
149
- See [`helm/siclaw/`](helm/siclaw/) for values reference, and [`k8s/README.md`](k8s/README.md) for the full deployment guide.
159
+ The default chart exposes the Gateway Service on service port `80` and NodePort `31000`.
150
160
 
151
161
  ## Configuration
152
162
 
153
- ### settings.json (TUI mode)
163
+ ### TUI / CLI
164
+
165
+ - TUI reads `.siclaw/config/settings.json`
166
+ - The first-run wizard can generate this file for you
167
+ - Kubernetes credentials should be imported through `/setup`
168
+ - Investigation reports are written to `~/.siclaw/reports/`
154
169
 
155
- Minimal example — copy `settings.example.json` to `.siclaw/config/settings.json`:
170
+ Minimal example:
156
171
 
157
172
  ```json
158
173
  {
@@ -160,82 +175,28 @@ Minimal example — copy `settings.example.json` to `.siclaw/config/settings.jso
160
175
  "default": {
161
176
  "baseUrl": "https://api.openai.com/v1",
162
177
  "apiKey": "sk-YOUR-KEY",
178
+ "api": "openai-completions",
163
179
  "models": [{ "id": "gpt-4o", "name": "GPT-4o" }]
164
180
  }
165
181
  }
166
182
  }
167
183
  ```
168
184
 
169
- <details>
170
- <summary><b>Full settings.json reference</b></summary>
171
-
172
- ```json
173
- {
174
- "providers": {
175
- "provider-name": {
176
- "baseUrl": "https://api.example.com/v1",
177
- "apiKey": "your-key",
178
- "api": "openai-completions",
179
- "authHeader": true,
180
- "models": [
181
- {
182
- "id": "model-id",
183
- "name": "Display Name",
184
- "reasoning": false,
185
- "contextWindow": 128000,
186
- "maxTokens": 16384,
187
- "cost": { "input": 2.5, "output": 10.0, "cacheRead": 0.5, "cacheWrite": 3.0 }
188
- }
189
- ]
190
- }
191
- },
192
- "default": { "provider": "provider-name", "modelId": "model-id" },
193
- "embedding": {
194
- "baseUrl": "https://api.example.com/v1",
195
- "apiKey": "your-key",
196
- "model": "BAAI/bge-m3",
197
- "dimensions": 1024
198
- },
199
- "mcpServers": {
200
- "server-name": {
201
- "command": "npx",
202
- "args": ["-y", "@some/mcp-server"]
203
- }
204
- },
205
- "debugImage": "busybox:latest",
206
- "debug": false
207
- }
208
- ```
209
-
210
- </details>
211
-
212
- <details>
213
- <summary><b>IM Channels — Slack / Discord / Telegram / Lark</b></summary>
214
-
215
- ### Slack
216
-
217
- Configure a Slack bot in **Settings > Channels**. You'll need:
218
- - Bot token and signing secret from the [Slack API](https://api.slack.com/apps)
219
-
220
- ### Discord
185
+ ### Local Server / Kubernetes
221
186
 
222
- Configure a Discord bot in **Settings > Channels**. You'll need:
223
- - Bot token from the [Discord Developer Portal](https://discord.com/developers/applications)
224
- - Scopes: `bot`, `messages.read`
187
+ - Configure providers in the **Models** page
188
+ - Import kubeconfigs, API tokens, and SSH credentials in **Credentials**
189
+ - Configure Slack, Lark, Discord, and Telegram in **Channels**
190
+ - Create inbound webhook endpoints in **Triggers**
191
+ - Configure MCP servers in **MCP Servers**
225
192
 
226
- ### Telegram
193
+ ## Documentation
227
194
 
228
- Configure a Telegram bot in **Settings > Channels**. You'll need:
229
- - Bot token from [@BotFather](https://t.me/BotFather)
230
-
231
- ### Lark
232
-
233
- Configure a Lark bot in **Settings > Channels** of the web UI. You'll need:
234
- - App ID and App Secret from the [Lark Open Platform](https://open.larksuite.com/)
235
- - Event subscription URL: `https://your-domain/api/channels/feishu/event`
236
- - Scopes: `im:message`, `im:message.group_at_msg`, `im:resource`
237
-
238
- </details>
195
+ - [Getting Started](https://docs.siclaw.ai/start/getting-started)
196
+ - [CLI & Local Server](https://docs.siclaw.ai/install/cli)
197
+ - [Kubernetes Deployment](https://docs.siclaw.ai/install/kubernetes)
198
+ - [LLM Providers](https://docs.siclaw.ai/configuration/providers)
199
+ - [MCP Servers](https://docs.siclaw.ai/configuration/mcp)
239
200
 
240
201
  ## Tech Stack
241
202
 
@@ -253,11 +214,10 @@ Configure a Lark bot in **Settings > Channels** of the web UI. You'll need:
253
214
 
254
215
  ## Community
255
216
 
217
+ - [Slack](https://join.slack.com/t/siclaw-scitix/shared_invite/zt-3rrsoc2ic-JIfbfvT1_04sqgQorSRfmw) — Chat with the team and other users
256
218
  - [GitHub Issues](https://github.com/scitix/siclaw/issues) — Bug reports and feature requests
257
219
  - [GitHub Discussions](https://github.com/scitix/siclaw/discussions) — Questions, ideas, and general discussion
258
220
 
259
- <!-- TODO: Add Discord invite link once server is created -->
260
-
261
221
  ## Contributing
262
222
 
263
223
  See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, architecture overview, and pull request guidelines.
@@ -16,6 +16,7 @@ export interface CronJob {
16
16
  description?: string | null;
17
17
  lastRunAt?: string | null;
18
18
  lastResult?: string | null;
19
+ workspaceId?: string | null;
19
20
  }
20
21
  export declare class GatewayClient {
21
22
  private gatewayUrl;
@@ -28,7 +29,7 @@ export declare class GatewayClient {
28
29
  /**
29
30
  * List cron jobs for a user
30
31
  */
31
- listCronJobs(userId: string): Promise<CronJob[]>;
32
+ listCronJobs(userId: string, workspaceId?: string): Promise<CronJob[]>;
32
33
  /**
33
34
  * Return a GatewayClientLike adapter for use with resource handlers.
34
35
  * Keeps `request()` private while exposing a minimal interface.
@@ -40,8 +40,12 @@ export class GatewayClient {
40
40
  /**
41
41
  * List cron jobs for a user
42
42
  */
43
- async listCronJobs(userId) {
44
- const data = await this.request(`/api/internal/cron-list?userId=${encodeURIComponent(userId)}`, "GET");
43
+ async listCronJobs(userId, workspaceId) {
44
+ let url = `/api/internal/cron-list?userId=${encodeURIComponent(userId)}`;
45
+ if (workspaceId) {
46
+ url += `&workspaceId=${encodeURIComponent(workspaceId)}`;
47
+ }
48
+ const data = await this.request(url, "GET");
45
49
  return data.jobs || [];
46
50
  }
47
51
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-client.js","sourceRoot":"","sources":["../../src/agentbox/gateway-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway-client.js","sourceRoot":"","sources":["../../src/agentbox/gateway-client.ts"],"names":[],"mappings":"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"}
@@ -11,17 +11,44 @@ import { hasOpenAIProvider, ensureProxy } from "../core/llm-proxy.js";
11
11
  import { deepSearchEvents } from "../tools/deep-search/events.js";
12
12
  import { createChecklist, buildActivationMessage } from "../tools/dp-tools.js";
13
13
  import { loadConfig } from "../core/config.js";
14
+ import { emitDiagnostic } from "../shared/diagnostic-events.js";
15
+ import { checkMetricsAuth } from "../shared/metrics.js"; // also registers metrics subscriber (side-effect)
14
16
  import { GatewayClient } from "./gateway-client.js";
15
17
  import { getResourceHandler } from "./resource-handlers.js";
16
18
  import { RESOURCE_DESCRIPTORS } from "../shared/resource-sync.js";
19
+ import { detectLanguage } from "../shared/detect-language.js";
20
+ import { resolveUnderDir } from "../shared/path-utils.js";
17
21
  /**
18
22
  * Parse JSON body
19
23
  */
24
+ const MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB
25
+ const BODY_TIMEOUT_MS = 30_000; // 30s
20
26
  async function parseJsonBody(req) {
21
27
  return new Promise((resolve, reject) => {
22
28
  let body = "";
23
- req.on("data", (chunk) => (body += chunk));
29
+ let size = 0;
30
+ let timedOut = false;
31
+ const timer = setTimeout(() => {
32
+ timedOut = true;
33
+ req.destroy();
34
+ reject(new Error("Body read timeout"));
35
+ }, BODY_TIMEOUT_MS);
36
+ req.on("data", (chunk) => {
37
+ if (timedOut)
38
+ return;
39
+ size += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
40
+ if (size > MAX_BODY_SIZE) {
41
+ clearTimeout(timer);
42
+ req.destroy();
43
+ reject(new Error(`Body exceeds ${MAX_BODY_SIZE} byte limit`));
44
+ return;
45
+ }
46
+ body += chunk;
47
+ });
24
48
  req.on("end", () => {
49
+ clearTimeout(timer);
50
+ if (timedOut)
51
+ return;
25
52
  try {
26
53
  resolve(body ? JSON.parse(body) : {});
27
54
  }
@@ -29,7 +56,10 @@ async function parseJsonBody(req) {
29
56
  reject(new Error("Invalid JSON"));
30
57
  }
31
58
  });
32
- req.on("error", reject);
59
+ req.on("error", (err) => {
60
+ clearTimeout(timer);
61
+ reject(err);
62
+ });
33
63
  });
34
64
  }
35
65
  /**
@@ -91,7 +121,56 @@ export function createHttpServer(sessionManager) {
91
121
  handler,
92
122
  });
93
123
  }
124
+ // ── Credential materialization helper (shared by prompt and reload-credentials) ──
125
+ // Writes new files with .new suffix first, then atomically renames them into place.
126
+ // This prevents data loss if the process crashes between delete and write.
127
+ function materializeCredentials(payload, kubeconfigRef) {
128
+ const credDir = path.resolve(process.cwd(), loadConfig().paths.credentialsDir);
129
+ fs.mkdirSync(credDir, { recursive: true });
130
+ // Phase 1: Write new files with .new suffix (staging)
131
+ const stagedFiles = [];
132
+ for (const file of payload.files) {
133
+ const resolved = resolveUnderDir(credDir, file.name);
134
+ const staged = resolved + ".new";
135
+ fs.writeFileSync(staged, file.content, file.mode ? { mode: file.mode } : undefined);
136
+ stagedFiles.push(file.name);
137
+ }
138
+ // Stage manifest
139
+ const manifestPath = path.join(credDir, "manifest.json");
140
+ fs.writeFileSync(manifestPath + ".new", JSON.stringify(payload.manifest, null, 2));
141
+ // Phase 2: Remove old files
142
+ for (const entry of fs.readdirSync(credDir)) {
143
+ if (entry.endsWith(".new"))
144
+ continue; // skip staged files
145
+ fs.rmSync(path.join(credDir, entry), { recursive: true });
146
+ }
147
+ // Phase 3: Rename staged files into place (atomic per-file on same filesystem)
148
+ for (const file of payload.files) {
149
+ const resolved = resolveUnderDir(credDir, file.name);
150
+ fs.renameSync(resolved + ".new", resolved);
151
+ }
152
+ fs.renameSync(manifestPath + ".new", manifestPath);
153
+ kubeconfigRef.credentialsDir = credDir;
154
+ return payload.files.length;
155
+ }
94
156
  // ==================== Routes ====================
157
+ /**
158
+ * GET /metrics - Prometheus metrics endpoint
159
+ */
160
+ addRoute("GET", "/metrics", async (req, res) => {
161
+ if (!checkMetricsAuth(req, res))
162
+ return;
163
+ const { metricsRegistry } = await import("../shared/metrics.js");
164
+ res.writeHead(200, { "Content-Type": metricsRegistry.contentType });
165
+ res.end(await metricsRegistry.metrics());
166
+ });
167
+ /**
168
+ * GET /api/internal/metrics-snapshot - export metrics snapshot for Gateway pull (K8s mode)
169
+ */
170
+ addRoute("GET", "/api/internal/metrics-snapshot", async (_req, res) => {
171
+ const { localCollector } = await import("../shared/local-collector.js");
172
+ sendJson(res, 200, localCollector.exportSnapshot());
173
+ });
95
174
  /**
96
175
  * GET /health - health check
97
176
  */
@@ -128,22 +207,21 @@ export function createHttpServer(sessionManager) {
128
207
  return;
129
208
  }
130
209
  const managed = await sessionManager.getOrCreate(body.sessionId, body.mode, body.brainType);
131
- // Materialize credential files from payload (sent by gateway in prompt body)
132
- if (body.credentials?.files?.length) {
133
- const credDir = path.resolve(process.cwd(), loadConfig().paths.credentialsDir);
134
- fs.mkdirSync(credDir, { recursive: true });
135
- // Clear existing files
136
- for (const entry of fs.readdirSync(credDir)) {
137
- fs.rmSync(path.join(credDir, entry), { recursive: true });
138
- }
139
- // Write credential files
140
- for (const file of body.credentials.files) {
141
- fs.writeFileSync(path.join(credDir, file.name), file.content, file.mode ? { mode: file.mode } : undefined);
142
- }
143
- // Write manifest
144
- fs.writeFileSync(path.join(credDir, "manifest.json"), JSON.stringify(body.credentials.manifest, null, 2));
145
- managed.kubeconfigRef.credentialsDir = credDir;
146
- console.log(`[agentbox-http] Materialized ${body.credentials.files.length} credential files to ${credDir}`);
210
+ // Materialize credential files from payload (sent by gateway in prompt body).
211
+ // Always call when credentials payload is present — even with empty files
212
+ // so stale credential files from prior sessions are cleaned up.
213
+ if (body.credentials) {
214
+ try {
215
+ const count = materializeCredentials(body.credentials, managed.kubeconfigRef);
216
+ if (count > 0) {
217
+ console.log(`[agentbox-http] Materialized ${count} credential files`);
218
+ }
219
+ }
220
+ catch (err) {
221
+ console.error(`[agentbox-http] Failed to materialize credentials for session ${managed.id}:`, err);
222
+ sendJson(res, 500, { error: "Failed to materialize credentials" });
223
+ return;
224
+ }
147
225
  }
148
226
  // Dynamically register provider config from gateway DB (before findModel)
149
227
  if (body.modelConfig && body.modelProvider && managed.brain.registerProvider) {
@@ -238,10 +316,52 @@ export function createHttpServer(sessionManager) {
238
316
  console.log(`[agentbox-http] DP exited for SDK brain, session ${managed.id}`);
239
317
  }
240
318
  }
319
+ // --- Language detection: inject explicit instruction so model doesn't guess ---
320
+ const detectedLang = detectLanguage(body.text);
321
+ if (detectedLang !== "English") {
322
+ promptText = `[System: respond in ${detectedLang}]\n${promptText}`;
323
+ }
324
+ // Programmatically update PROFILE.md Language field (code-level, not model-dependent).
325
+ // Only update on non-English detection to avoid flapping: English is the default,
326
+ // so we only persist when the user actively uses another language.
327
+ if (detectedLang !== "English") {
328
+ try {
329
+ const cfg = loadConfig();
330
+ const userDataDir = process.env.SICLAW_USER_DATA_DIR || cfg.paths.userDataDir;
331
+ const profilePath = path.resolve(userDataDir, "memory", "PROFILE.md");
332
+ if (fs.existsSync(profilePath)) {
333
+ const content = fs.readFileSync(profilePath, "utf-8");
334
+ const currentLangMatch = content.match(/\*\*Language\*\*:\s*(.+)/i);
335
+ const currentLang = currentLangMatch?.[1]?.trim();
336
+ if (currentLang !== detectedLang) {
337
+ const updated = content.replace(/(\*\*Language\*\*:\s*).+/i, `$1${detectedLang}`);
338
+ fs.writeFileSync(profilePath, updated);
339
+ }
340
+ }
341
+ }
342
+ catch { /* best-effort, don't block prompt */ }
343
+ }
241
344
  // Execute prompt asynchronously; notify SSE to close on completion
242
- console.log(`[agentbox-http] Starting prompt for session ${managed.id}`);
345
+ console.log(`[agentbox-http] Starting prompt for session ${managed.id} [lang=${detectedLang}]`);
346
+ // Metrics: snapshot stats before prompt for delta calculation
347
+ const prevStats = managed.brain.getSessionStats();
348
+ const promptStartTime = Date.now();
349
+ let promptOutcome = "completed";
243
350
  const actuallyFinish = () => {
244
351
  managed._promptDone = true;
352
+ // Emit prompt metrics via diagnostic event bus
353
+ const currStats = managed.brain.getSessionStats();
354
+ const model = managed.brain.getModel();
355
+ emitDiagnostic({
356
+ type: "prompt_complete",
357
+ sessionId: managed.id,
358
+ prev: prevStats,
359
+ curr: currStats,
360
+ model,
361
+ durationMs: Date.now() - promptStartTime,
362
+ outcome: promptOutcome,
363
+ userId: sessionManager.userId,
364
+ });
245
365
  // Stop buffering
246
366
  if (managed._bufferUnsub) {
247
367
  managed._bufferUnsub();
@@ -281,9 +401,11 @@ export function createHttpServer(sessionManager) {
281
401
  };
282
402
  managed.brain.prompt(promptText).then(() => {
283
403
  console.log(`[agentbox-http] Prompt completed for session ${managed.id}`);
404
+ promptOutcome = "completed";
284
405
  onPromptFinish();
285
406
  }).catch((err) => {
286
407
  console.error(`[agentbox-http] Prompt error for session ${managed.id}:`, err);
408
+ promptOutcome = "error";
287
409
  onPromptFinish();
288
410
  });
289
411
  sendJson(res, 200, { ok: true, sessionId: managed.id, brainType: managed.brainType });
@@ -528,6 +650,49 @@ export function createHttpServer(sessionManager) {
528
650
  }
529
651
  });
530
652
  }
653
+ /**
654
+ * POST /api/reload-credentials — push-based credential update from Gateway
655
+ *
656
+ * Accepts the same {manifest, files} payload as the prompt body's credentials
657
+ * field and re-materializes credential files on disk. This allows the Gateway
658
+ * to push credential changes (kubeconfig upload/delete, credential CRUD)
659
+ * without waiting for the next prompt.
660
+ */
661
+ addRoute("POST", "/api/reload-credentials", async (req, res) => {
662
+ const body = (await parseJsonBody(req));
663
+ if (!body.manifest) {
664
+ sendJson(res, 400, { error: "Missing 'manifest' field" });
665
+ return;
666
+ }
667
+ // Each AgentBox pod serves exactly one user (one-pod-per-workspace in K8s mode,
668
+ // one in-process instance per user in local mode). All sessions within this
669
+ // AgentBox belong to the same user, so updating any session's kubeconfigRef is correct.
670
+ const sessions = sessionManager.list();
671
+ const kubeconfigRef = sessions.length > 0
672
+ ? sessions[0].kubeconfigRef
673
+ : { credentialsDir: undefined };
674
+ const payload = { manifest: body.manifest, files: body.files ?? [] };
675
+ try {
676
+ // Use atomic materializeCredentials for both populate and clear paths
677
+ const count = materializeCredentials(payload, kubeconfigRef);
678
+ if (count > 0) {
679
+ console.log(`[agentbox-http] Credentials reloaded: ${count} files materialized`);
680
+ }
681
+ else {
682
+ console.log("[agentbox-http] Credentials cleared (empty payload)");
683
+ }
684
+ }
685
+ catch (err) {
686
+ console.error("[agentbox-http] Failed to reload credentials:", err);
687
+ sendJson(res, 500, { error: "Failed to materialize credentials" });
688
+ return;
689
+ }
690
+ // Update kubeconfigRef on all active sessions
691
+ for (const session of sessions) {
692
+ session.kubeconfigRef.credentialsDir = kubeconfigRef.credentialsDir;
693
+ }
694
+ sendJson(res, 200, { ok: true, count: payload.files.length });
695
+ });
531
696
  /**
532
697
  * GET /api/models - list available models (read from settings.json)
533
698
  */