chainlesschain 0.44.0 → 0.45.1

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/README.md CHANGED
@@ -226,7 +226,7 @@ chainlesschain skill sources # Show skill layer paths and counts
226
226
 
227
227
  #### CLI Command Skill Packs
228
228
 
229
- Automatically wraps 62 CLI commands into 9 Agent-callable domain skill packs:
229
+ Automatically wraps 63 CLI commands into 9 Agent-callable domain skill packs:
230
230
 
231
231
  ```bash
232
232
  chainlesschain skill sync-cli # Generate/update all 9 CLI skill packs
@@ -247,17 +247,17 @@ chainlesschain skill run cli-enterprise-pack "org list"
247
247
  chainlesschain skill run cli-integration-pack "mcp servers"
248
248
  ```
249
249
 
250
- | Pack | Mode | Commands |
251
- |------|------|----------|
252
- | `cli-knowledge-pack` | direct | note, search, memory, session, import, export |
253
- | `cli-identity-pack` | direct | did, auth, audit |
254
- | `cli-infra-pack` | direct | setup, start, stop, status, services, config, doctor, db |
255
- | `cli-ai-query-pack` | llm-query | ask, llm, instinct, tokens |
256
- | `cli-agent-mode-pack` | agent | agent, chat, cowork |
257
- | `cli-web3-pack` | direct | wallet, p2p, sync, did |
258
- | `cli-security-pack` | direct | encrypt, decrypt, audit, pqc |
259
- | `cli-enterprise-pack` | direct | org, plugin, lowcode, compliance |
260
- | `cli-integration-pack` | hybrid | mcp, browse, cli-anything, serve |
250
+ | Pack | Mode | Commands |
251
+ | ---------------------- | --------- | -------------------------------------------------------- |
252
+ | `cli-knowledge-pack` | direct | note, search, memory, session, import, export |
253
+ | `cli-identity-pack` | direct | did, auth, audit |
254
+ | `cli-infra-pack` | direct | setup, start, stop, status, services, config, doctor, db |
255
+ | `cli-ai-query-pack` | llm-query | ask, llm, instinct, tokens |
256
+ | `cli-agent-mode-pack` | agent | agent, chat, cowork |
257
+ | `cli-web3-pack` | direct | wallet, p2p, sync, did |
258
+ | `cli-security-pack` | direct | encrypt, decrypt, audit, pqc |
259
+ | `cli-enterprise-pack` | direct | org, plugin, lowcode, compliance |
260
+ | `cli-integration-pack` | hybrid | mcp, browse, cli-anything, serve, ui |
261
261
 
262
262
  ---
263
263
 
@@ -569,11 +569,11 @@ chainlesschain skill run comfyui-video '{"prompt":"a cat walking","workflow":"wo
569
569
  chainlesschain skill run audio-gen "你好,欢迎使用 ChainlessChain"
570
570
  ```
571
571
 
572
- | Skill | Description |
573
- |-------|-------------|
572
+ | Skill | Description |
573
+ | --------------- | --------------------------------------------------------------------- |
574
574
  | `comfyui-image` | ComfyUI REST API image generation (txt2img/img2img, custom workflows) |
575
- | `comfyui-video` | ComfyUI + AnimateDiff video generation (requires workflow JSON) |
576
- | `audio-gen` | AI TTS: auto-selects edge-tts → piper-tts → ElevenLabs → OpenAI |
575
+ | `comfyui-video` | ComfyUI + AnimateDiff video generation (requires workflow JSON) |
576
+ | `audio-gen` | AI TTS: auto-selects edge-tts → piper-tts → ElevenLabs → OpenAI |
577
577
 
578
578
  Also creates a `workflows/` directory with README for saving ComfyUI workflow JSON files.
579
579
 
@@ -590,11 +590,11 @@ chainlesschain skill run doc-edit '{"input_file":"report.md","instruction":"优
590
590
  chainlesschain skill run doc-edit '{"input_file":"data.xlsx","instruction":"首字母大写"}'
591
591
  ```
592
592
 
593
- | Skill | Description |
594
- |-------|-------------|
595
- | `doc-generate` | AI-generated structured documents: md/html/docx/pdf, 4 styles (report/proposal/manual/readme) |
596
- | `libre-convert` | LibreOffice headless conversion: docx/pdf/html/odt/pptx/xlsx/png |
597
- | `doc-edit` | AI edit existing docs: md/txt/html (direct LLM), docx (pandoc/soffice), xlsx (openpyxl, formulas preserved), pptx (python-pptx, charts preserved) |
593
+ | Skill | Description |
594
+ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
595
+ | `doc-generate` | AI-generated structured documents: md/html/docx/pdf, 4 styles (report/proposal/manual/readme) |
596
+ | `libre-convert` | LibreOffice headless conversion: docx/pdf/html/odt/pptx/xlsx/png |
597
+ | `doc-edit` | AI edit existing docs: md/txt/html (direct LLM), docx (pandoc/soffice), xlsx (openpyxl, formulas preserved), pptx (python-pptx, charts preserved) |
598
598
 
599
599
  Requirements: `winget install pandoc` (for docx), `winget install LibreOffice.LibreOffice` (for PDF/format conversion).
600
600
 
@@ -1007,6 +1007,36 @@ chainlesschain serve --project /path/to/project # Default project root f
1007
1007
 
1008
1008
  ---
1009
1009
 
1010
+ ## Web Management Interface (v0.45.0)
1011
+
1012
+ ### `chainlesschain ui`
1013
+
1014
+ Open a browser-based Web management interface — no extra software required.
1015
+
1016
+ ```bash
1017
+ chainlesschain ui # Auto-detect mode, open browser
1018
+ chainlesschain ui --port 18810 # Custom HTTP port
1019
+ chainlesschain ui --ws-port 18800 # Custom WebSocket port
1020
+ chainlesschain ui --no-open # Start server without opening browser
1021
+ chainlesschain ui --token <secret> # Enable WebSocket auth token
1022
+ chainlesschain ui --host 0.0.0.0 # Bind to all interfaces (remote access)
1023
+ ```
1024
+
1025
+ **Two modes** (auto-detected based on current directory):
1026
+
1027
+ | Mode | Trigger | Description |
1028
+ | ---------------- | -------------------------------------------- | -------------------------------------------------------------- |
1029
+ | **Project mode** | Run from a directory with `.chainlesschain/` | AI automatically loads project context (rules, skills, config) |
1030
+ | **Global mode** | Run from any non-project directory | General-purpose AI management panel |
1031
+
1032
+ **Features**: streaming Markdown output, session management (new/switch/history), Agent/Chat mode toggle, slot-filling interactive dialogs, auto-reconnect (3s), Token auth.
1033
+
1034
+ **Ports**: HTTP 18810 (Web UI page), WebSocket 18800 (reuses `chainlesschain serve` infrastructure).
1035
+
1036
+ **Security**: JSON config embedded with XSS-safe Unicode escaping (`\u003c`/`\u003e`); Token auth via `--token`.
1037
+
1038
+ ---
1039
+
1010
1040
  ## Global Options
1011
1041
 
1012
1042
  ```bash
@@ -1088,22 +1118,22 @@ npm run test:e2e # End-to-end tests
1088
1118
 
1089
1119
  ### Test Coverage
1090
1120
 
1091
- | Category | Files | Tests | Status |
1092
- | ------------------------------ | ------- | -------- | --------------- |
1093
- | Unit — lib modules | 70 | 1700+ | All passing |
1094
- | Unit — commands | 17 | 400+ | All passing |
1095
- | Unit — runtime | 1 | 6 | All passing |
1096
- | Unit — WS sessions | 9 | 156 | All passing |
1097
- | Unit — Skill Packs | 2 | 57+ | All passing |
1098
- | Unit — AI Templates | 2 | 130+ | All passing |
1099
- | Integration | 13 | 230+ | All passing |
1100
- | Integration — WS session | 1 | 12 | All passing |
1101
- | Integration — AI Handlers | 2 | 100+ | All passing |
1102
- | E2E | 15 | 260+ | All passing |
1103
- | E2E — Skill Packs | 1 | 23+ | All passing |
1104
- | E2E — AI Templates | 4 | 65+ | All passing |
1105
- | Core packages (external) | — | 118 | All passing |
1106
- | **CLI Total** | **132** | **3056** | **All passing** |
1121
+ | Category | Files | Tests | Status |
1122
+ | ------------------------- | ------- | -------- | --------------- |
1123
+ | Unit — lib modules | 70 | 1700+ | All passing |
1124
+ | Unit — commands | 17 | 400+ | All passing |
1125
+ | Unit — runtime | 1 | 6 | All passing |
1126
+ | Unit — WS sessions | 9 | 156 | All passing |
1127
+ | Unit — Skill Packs | 2 | 57+ | All passing |
1128
+ | Unit — AI Templates | 2 | 130+ | All passing |
1129
+ | Integration | 13 | 230+ | All passing |
1130
+ | Integration — WS session | 1 | 12 | All passing |
1131
+ | Integration — AI Handlers | 2 | 100+ | All passing |
1132
+ | E2E | 15 | 260+ | All passing |
1133
+ | E2E — Skill Packs | 1 | 23+ | All passing |
1134
+ | E2E — AI Templates | 4 | 65+ | All passing |
1135
+ | Core packages (external) | — | 118 | All passing |
1136
+ | **CLI Total** | **132** | **3056** | **All passing** |
1107
1137
 
1108
1138
  ## License
1109
1139
 
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chainlesschain",
3
- "version": "0.44.0",
3
+ "version": "0.45.1",
4
4
  "description": "CLI for ChainlessChain - install, configure, and manage your personal AI management system",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,169 @@
1
+ /**
2
+ * ui command — start a local web management UI
3
+ * chainlesschain ui [--port] [--ws-port] [--host] [--no-open] [--token]
4
+ *
5
+ * Project mode (run from a dir with .chainlesschain/): project-scoped chat UI
6
+ * Global mode (run from any other dir): global management panel
7
+ */
8
+
9
+ import { execSync } from "child_process";
10
+ import path from "path";
11
+ import chalk from "chalk";
12
+ import { logger } from "../lib/logger.js";
13
+ import { ChainlessChainWSServer } from "../lib/ws-server.js";
14
+ import { WSSessionManager } from "../lib/ws-session-manager.js";
15
+ import { createWebUIServer } from "../lib/web-ui-server.js";
16
+ import { bootstrap } from "../runtime/bootstrap.js";
17
+ import { findProjectRoot, loadProjectConfig } from "../lib/project-detector.js";
18
+
19
+ /**
20
+ * Open a URL in the system default browser (cross-platform).
21
+ */
22
+ function openBrowser(url) {
23
+ try {
24
+ const platform = process.platform;
25
+ if (platform === "win32") {
26
+ execSync(`start "" "${url}"`, { stdio: "ignore" });
27
+ } else if (platform === "darwin") {
28
+ execSync(`open "${url}"`, { stdio: "ignore" });
29
+ } else {
30
+ execSync(`xdg-open "${url}"`, { stdio: "ignore" });
31
+ }
32
+ } catch (_err) {
33
+ // Non-critical — user can open manually
34
+ }
35
+ }
36
+
37
+ export function registerUiCommand(program) {
38
+ program
39
+ .command("ui")
40
+ .description("Start a local web management UI (project or global mode)")
41
+ .option("-p, --port <port>", "HTTP server port", "18810")
42
+ .option("--ws-port <port>", "WebSocket server port", "18800")
43
+ .option("-H, --host <host>", "Bind host", "127.0.0.1")
44
+ .option("--no-open", "Do not open browser automatically")
45
+ .option(
46
+ "--token <token>",
47
+ "Authentication token for WebSocket (recommended for security)",
48
+ )
49
+ .action(async (opts) => {
50
+ const httpPort = parseInt(opts.port, 10);
51
+ const wsPort = parseInt(opts.wsPort, 10);
52
+ const host = opts.host;
53
+
54
+ if (isNaN(httpPort) || httpPort < 1 || httpPort > 65535) {
55
+ logger.error("Invalid --port. Must be between 1 and 65535.");
56
+ process.exit(1);
57
+ }
58
+ if (isNaN(wsPort) || wsPort < 1 || wsPort > 65535) {
59
+ logger.error("Invalid --ws-port. Must be between 1 and 65535.");
60
+ process.exit(1);
61
+ }
62
+
63
+ // ── Detect project context ────────────────────────────────────────────
64
+ const projectRoot = findProjectRoot(process.cwd());
65
+ const projectConfig = projectRoot ? loadProjectConfig(projectRoot) : null;
66
+ const projectName =
67
+ projectConfig?.name ||
68
+ (projectRoot ? path.basename(projectRoot) : null);
69
+ const mode = projectRoot ? "project" : "global";
70
+
71
+ // ── Bootstrap headless runtime ────────────────────────────────────────
72
+ let db = null;
73
+ try {
74
+ const ctx = await bootstrap({ skipDb: false });
75
+ db = ctx.db?.getDb?.() || null;
76
+ } catch (_err) {
77
+ logger.log(
78
+ chalk.yellow(
79
+ " Warning: Database not available, sessions will be in-memory only",
80
+ ),
81
+ );
82
+ }
83
+
84
+ // ── Start WebSocket server ────────────────────────────────────────────
85
+ const sessionManager = new WSSessionManager({
86
+ db,
87
+ defaultProjectRoot: projectRoot || process.cwd(),
88
+ });
89
+
90
+ const wsServer = new ChainlessChainWSServer({
91
+ port: wsPort,
92
+ host,
93
+ token: opts.token || null,
94
+ maxConnections: 20,
95
+ timeout: 60000,
96
+ sessionManager,
97
+ });
98
+
99
+ try {
100
+ await wsServer.start();
101
+ } catch (err) {
102
+ logger.error(`Failed to start WebSocket server: ${err.message}`);
103
+ process.exit(1);
104
+ }
105
+
106
+ // ── Start HTTP server ─────────────────────────────────────────────────
107
+ const httpServer = createWebUIServer({
108
+ wsPort,
109
+ wsToken: opts.token || null,
110
+ wsHost: host === "0.0.0.0" ? "127.0.0.1" : host,
111
+ projectRoot,
112
+ projectName,
113
+ mode,
114
+ });
115
+
116
+ try {
117
+ await new Promise((resolve, reject) => {
118
+ httpServer.listen(httpPort, host, () => resolve());
119
+ httpServer.on("error", reject);
120
+ });
121
+ } catch (err) {
122
+ logger.error(`Failed to start HTTP server: ${err.message}`);
123
+ process.exit(1);
124
+ }
125
+
126
+ // ── Print startup info ────────────────────────────────────────────────
127
+ const uiUrl = `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${httpPort}`;
128
+
129
+ logger.log("");
130
+ logger.log(chalk.bold(" ChainlessChain Web UI"));
131
+ logger.log("");
132
+ if (mode === "project") {
133
+ logger.log(
134
+ ` Mode: ${chalk.cyan("project")} ${chalk.dim(projectRoot)}`,
135
+ );
136
+ if (projectName) {
137
+ logger.log(` Project: ${chalk.green(projectName)}`);
138
+ }
139
+ } else {
140
+ logger.log(` Mode: ${chalk.cyan("global")}`);
141
+ }
142
+ logger.log(` UI: ${chalk.cyan(uiUrl)}`);
143
+ logger.log(` WS: ${chalk.dim(`ws://${host}:${wsPort}`)}`);
144
+ logger.log(
145
+ ` Auth: ${opts.token ? chalk.green("enabled") : chalk.yellow("disabled")}`,
146
+ );
147
+ logger.log("");
148
+ logger.log(chalk.dim(" Press Ctrl+C to stop"));
149
+ logger.log("");
150
+
151
+ // ── Open browser ──────────────────────────────────────────────────────
152
+ if (opts.open !== false) {
153
+ openBrowser(uiUrl);
154
+ }
155
+
156
+ // ── Graceful shutdown ─────────────────────────────────────────────────
157
+ const shutdown = async () => {
158
+ logger.log("\n" + chalk.yellow("Shutting down UI server..."));
159
+ await Promise.all([
160
+ new Promise((resolve) => httpServer.close(resolve)),
161
+ wsServer.stop(),
162
+ ]);
163
+ process.exit(0);
164
+ };
165
+
166
+ process.on("SIGINT", shutdown);
167
+ process.on("SIGTERM", shutdown);
168
+ });
169
+ }
package/src/index.js CHANGED
@@ -86,6 +86,9 @@ import { registerCliAnythingCommand } from "./commands/cli-anything.js";
86
86
  // WebSocket Server Interface
87
87
  import { registerServeCommand } from "./commands/serve.js";
88
88
 
89
+ // Web UI
90
+ import { registerUiCommand } from "./commands/ui.js";
91
+
89
92
  export function createProgram() {
90
93
  const program = new Command();
91
94
 
@@ -201,5 +204,8 @@ export function createProgram() {
201
204
  // WebSocket Server Interface
202
205
  registerServeCommand(program);
203
206
 
207
+ // Web UI
208
+ registerUiCommand(program);
209
+
204
210
  return program;
205
211
  }