@descix/cli 1.0.17 → 1.0.18

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.
@@ -10,7 +10,7 @@ This document covers how AI agents interact with the DeSciX platform via MCP (Mo
10
10
 
11
11
  ## 1. Architecture Overview
12
12
 
13
- DeSciX operates as a **Federated MCP Service Mesh**. The `DeSciX_Cloud` backend acts as a broker that aggregates tools from all registered microservices into a unified catalog.
13
+ DeSciX operates as a **Federated MCP Service Mesh**. The DeSciX backend acts as a broker that aggregates tools from all registered microservices into a unified catalog.
14
14
 
15
15
  **Key Innovation:** AI agents discover and invoke capabilities across the entire mesh without knowing where individual services are hosted.
16
16
 
@@ -24,7 +24,7 @@ AI Agent (Cursor/MCP Client)
24
24
  execute_remote_command
25
25
  │
26
26
  ▼
27
- DeSciX_Cloud (Federated Broker)
27
+ DeSciX Backend (Federated Broker)
28
28
  │
29
29
  ├──► Service 1 (Powch)
30
30
  ├──► Service 2 (SmartModel)
@@ -42,9 +42,9 @@ MCP provides the communication protocol between AI agents and the DeSciX platfor
42
42
  **Key Tools:**
43
43
  - `tell_me_how` - Semantic tool discovery
44
44
  - `execute_remote_command` - Execute any backend command
45
- - `descix_init` - Initialize local workspace
46
- - `chat_with_kb` - Query knowledge bases
47
- - `search_knowledge_base` - Search specific KBs
45
+ - `descix_doctor` - CLI-local startup diagnostic (auth, workspace, tools, warnings)
46
+ - `ask_question_to_app` - RAG chat with an app's knowledge base (synthesized answer, cited)
47
+ - `query_knowledge_base` - Raw vector search, returns chunks
48
48
 
49
49
  ### 2.2 Cursor/AI Agent Integration
50
50
 
@@ -91,13 +91,17 @@ Once signed in, `tell_me_how` is the **primary entry point** for discovering pla
91
91
 
92
92
  **Rule:** Sign in, then ask `tell_me_how` first, then execute the recommended command.
93
93
 
94
- ### 3.2 Three Scopes
94
+ ### 3.2 Scopes
95
+
96
+ The validated `tell_me_how` scope enum has five values:
95
97
 
96
98
  | Scope | Description | Use Case |
97
99
  |-------|-------------|----------|
98
- | `entitlements` (default) | Only tools user has access to | Production usage |
100
+ | `entitlements` (default) | Only tools the user has access to | Production usage |
99
101
  | `project` | Tools filtered by workspace.json | Working within a project |
100
102
  | `discovery` | All available tools | Exploring capabilities |
103
+ | `bootstrap` | Deterministic first-call on-ramp: platform summary, caller context, credit balance, essential tool schemas (no vector search; `question` is optional for this scope only) | First contact / first call in a session |
104
+ | `artifact` | Deterministic build/reproduce provenance for a published app (npm package + spec, artifact/notebook URLs, runnable `npx` commands), no vector search | "How do I build on / reproduce this app?" |
101
105
 
102
106
  ### 3.3 CLI Usage
103
107
 
@@ -151,7 +155,7 @@ After `descix quickstart` completes:
151
155
 
152
156
  ### 4.1 Federated MCP Broker
153
157
 
154
- `DeSciX_Cloud` aggregates tools from all registered microservices:
158
+ The DeSciX backend aggregates tools from all registered microservices:
155
159
 
156
160
  ```
157
161
  Microservice A
@@ -161,7 +165,7 @@ Microservice A
161
165
  Registers with Core
162
166
  │
163
167
  ▼
164
- DeSciX_Cloud (Broker)
168
+ DeSciX Backend (Broker)
165
169
  └── Aggregated tools/list
166
170
  │
167
171
  ▼
@@ -199,14 +203,11 @@ execute_remote_command({
199
203
 
200
204
  ### 4.3 Service Registration
201
205
 
202
- Services self-register with the broker:
206
+ Services self-register with the broker in one step — registration also vectorizes the README you
207
+ pass, so there is no separate developer-facing vectorize step:
203
208
 
204
209
  ```bash
205
- # Register service manifest
206
- descix microservice register -m ./manifest.json
207
-
208
- # Vectorize SERVICE_README for discovery
209
- descix microservice vectorize -r SERVICE_README.md
210
+ descix microservice register -r SERVICE_README.md
210
211
  ```
211
212
 
212
213
  ### 4.4 The execute_remote_command Pattern
@@ -309,11 +310,13 @@ When `--scope project` is used:
309
310
 
310
311
  ### 6.1 KB Operations via tell_me_how
311
312
 
312
- The new SDK V2 KB commands are discoverable:
313
+ `tell_me_how` can be asked about KB sync in plain language, but the actionable answer for a
314
+ developer is always the CLI verb, not the raw backend command names (`kb_sync_chunks` etc. are
315
+ internal to the backend, not something the CLI calls directly by name):
313
316
 
314
317
  ```bash
315
318
  descix tell-me-how "How do I sync my knowledge base?"
316
- # Returns: kb_sync_chunks, kb_get_chunk_ids, kb_delete_chunks
319
+ # The developer-facing command either way: descix kb corpus sync
317
320
  ```
318
321
 
319
322
  ### 6.2 workspace.json from Hydration
@@ -324,7 +327,7 @@ descix tell-me-how "How do I sync my knowledge base?"
324
327
  {
325
328
  "env": { "apiUrl": "https://dev.descix.net", "products": [ /* one entry per app */ ] },
326
329
  "driveConfig": {
327
- "base_folder_id": "..." // For tell_me_how project scope
330
+ "base_folder_id": "..." // Only used by `descix drive pull/push` — unrelated to tell_me_how scope
328
331
  }
329
332
  }
330
333
  ```
@@ -334,9 +337,9 @@ descix tell-me-how "How do I sync my knowledge base?"
334
337
  Custom services integrate with the same pattern:
335
338
 
336
339
  1. Create `SERVICE_README_{name}.md`
337
- 2. Register with `descix microservice register`
338
- 3. Vectorize with `descix microservice vectorize`
339
- 4. Tools become discoverable via `tell_me_how`
340
+ 2. Register with `descix microservice register -r SERVICE_README_{name}.md` — this both publishes
341
+ the manifest AND vectorizes the README in one step
342
+ 3. Tools become discoverable via `tell_me_how`
340
343
 
341
344
  ---
342
345
 
@@ -355,7 +358,8 @@ Custom services integrate with the same pattern:
355
358
  1. **Document all commands in SERVICE_README** - Required for discovery
356
359
  2. **Use clear descriptions** - "Use when:" is crucial for semantic matching
357
360
  3. **Include examples** - Helps AI agents understand usage
358
- 4. **Register after changes** - Re-vectorize when README updates
361
+ 4. **Re-register after README changes** - `descix microservice register -r <file>` re-vectorizes
362
+ automatically; there is no separate vectorize step
359
363
 
360
364
  ### 7.3 Common Patterns
361
365
 
@@ -407,22 +411,11 @@ cd /path/to/workspace
407
411
 
408
412
  ### 8.3 "Command not found"
409
413
 
410
- **Cause:** Service not registered or command deprecated.
414
+ **Cause:** Service not registered, or the README wasn't vectorized.
411
415
 
412
416
  **Solution:**
413
- 1. Verify service is registered: `descix microservice list`
414
- 2. Check if command was deprecated in V2
415
- 3. Use `tell_me_how --scope discovery` to find alternatives
416
-
417
- ---
418
-
419
- ## 9. File References
420
-
421
- | Component | Path |
422
- |-----------|------|
423
- | MCP Tools | `DeSciX_Core/descix-cli/bin/mcp-server.js` |
424
- | tell_me_how Implementation | `DeSciX_Cloud/microservice/services/commandHandlers/ragCommands.js` |
425
- | execute_remote_command | `DeSciX_Cloud/microservice/services/apiFront.js` |
426
- | SERVICE_README Template | `DeSciX_Core/descix-cli/templates/scaffolds/microservice/templates/SERVICE_README_TEMPLATE.md` |
427
- | Workspace Config | `DeSciX_Core/descix-cli/lib/workspace-config.js` |
428
- | Service Registration | `DeSciX_Core/descix-cli/bin/descix.js` |
417
+ 1. Re-run `descix microservice register -r SERVICE_README_<name>.md` — it re-publishes the
418
+ manifest and re-vectorizes the README (`descix microservice list` exists to enumerate
419
+ registered services, but it is an admin-only command, not something a developer runs)
420
+ 2. Check `descix microservice health <name>` to confirm the service itself is reachable
421
+ 3. Use `descix tell-me-how --scope discovery "..."` to find alternatives
@@ -160,13 +160,12 @@ descix site status -c egpt -a egpt-mydocs # site status/list need both when
160
160
 
161
161
  ---
162
162
 
163
- ## 7. File References
164
-
165
- | Component | Path | Description |
166
- |-----------|------|-------------|
167
- | WorkspaceConfig | `DeSciX_Core/descix-cli/lib/workspace-config.js` | the loader, the v2.1 writer, `registerApp`, `detectContext` |
168
- | Origin resolution | `DeSciX_Core/descix-cli/lib/origin.js` | flag → `DESCIX_API_URL` → `env.apiUrl` → default |
169
- | GlobalConfig | `DeSciX_Core/descix-cli/lib/global-config.js` | user-level settings (`~/.descixrc`) |
170
- | Config commands | `DeSciX_Core/descix-cli/lib/commands/config.js` | `config init/set-env/set-*` |
171
- | Wallet file | `DeSciX_Core/descix-cli/lib/wallet-file.js` | `.descix/wallet.json` location |
172
- | Corpus sync | `DeSciX_Core/descix-cli/lib/commands/corpus.js` | manifests, sync-state |
163
+ ## 7. Where each concept lives (conceptual, not a file map)
164
+
165
+ | Concept | Owner |
166
+ |---|---|
167
+ | Workspace loading, the v2.1 writer, app registration, context detection | `WorkspaceConfig`, internal to `@descix/cli` |
168
+ | Origin resolution precedence | flag → `DESCIX_API_URL` → `env.apiUrl` → default (`descix config` commands) |
169
+ | User-level settings (`~/.descixrc`) | `GlobalConfig`, internal to `@descix/cli` |
170
+ | `.descix/wallet.json` | written by `descix login` |
171
+ | Corpus manifests, sync-state | `descix kb corpus` commands, internal to `@descix/cli` |
package/bin/descix.js CHANGED
@@ -35,6 +35,7 @@ import { registerAllRetiredKbSync, CANONICAL_KB_SYNC } from '../lib/commands/ret
35
35
  import { runStatus } from '../lib/commands/status.js';
36
36
  import { refreshCommunityIdentity, printIdentityReceipt } from '../lib/commands/communityIdentity.js';
37
37
  import { runAppInit } from '../lib/commands/appInit.js';
38
+ import { assertKnownCommandForHelp } from '../lib/help-guard.js';
38
39
  import { runDoctor } from '../lib/commands/doctor.js';
39
40
  import { runHealth } from '../lib/commands/health.js';
40
41
  import * as kbCommands from '../lib/commands/kb.js';
@@ -4650,6 +4651,10 @@ if (!adminMode && isHelpInvocation(program, rawArgv, { valueFlags: ['--env', '--
4650
4651
  }
4651
4652
  }
4652
4653
 
4654
+ // A command that does not exist must not appear to have help (see lib/help-guard.js). This runs
4655
+ // before the parse, because Commander resolves --help before it resolves the command.
4656
+ assertKnownCommandForHelp(program, process.argv.slice(2));
4657
+
4653
4658
  // Parse arguments
4654
4659
  await program.parseAsync(process.argv);
4655
4660
 
@@ -0,0 +1,85 @@
1
+ /**
2
+ * A COMMAND THAT DOES NOT EXIST MUST NOT APPEAR TO HAVE HELP.
3
+ *
4
+ * Commander resolves `--help` before it resolves the command, so `descix update --help` printed the
5
+ * TOP-LEVEL help and exited 0 — indistinguishable, to a reader or a script, from a real verb with
6
+ * help. `descix update` alone correctly says `error: unknown command 'update'`.
7
+ *
8
+ * That exit 0 is not only wrong, it TAUGHT something wrong: the daita-sdk docs tell readers that
9
+ * `site upload --help` "silently prints top-level help" and to use `help <sub>` instead. It does no
10
+ * such thing for a real command; the author had been probing a command that did not exist (devx
11
+ * review 2026-09-19, I2 → S5).
12
+ *
13
+ * This guard runs ONLY when a help flag is present, so every other path keeps Commander's own
14
+ * behaviour (it already exits non-zero for an unknown command without `--help`).
15
+ */
16
+
17
+ const HELP_FLAGS = new Set(['-h', '--help']);
18
+
19
+ /** Does this option consume the next argv token as its value? */
20
+ function takesValue(option) {
21
+ return Boolean(option && option.required);
22
+ }
23
+
24
+ function findOption(command, token) {
25
+ const name = token.split('=')[0];
26
+ return command.options.find((o) => o.short === name || o.long === name);
27
+ }
28
+
29
+ function findSubcommand(command, token) {
30
+ return command.commands.find(
31
+ (c) => c.name() === token || (typeof c.aliases === 'function' && c.aliases().includes(token)),
32
+ );
33
+ }
34
+
35
+ /**
36
+ * Walk argv down the command tree and return the first token that should name a subcommand but does
37
+ * not. Returns null when every command token resolves — including when a command takes positional
38
+ * arguments (a command with no subcommands ends the walk, so `descix chat hello` is not "unknown").
39
+ *
40
+ * @param {import('commander').Command} program
41
+ * @param {string[]} argv arguments after the node binary and script (process.argv.slice(2))
42
+ * @returns {{token: string, parent: import('commander').Command}|null}
43
+ */
44
+ export function findUnknownCommand(program, argv) {
45
+ let command = program;
46
+ for (let i = 0; i < argv.length; i++) {
47
+ const token = argv[i];
48
+ if (token === '--') break;
49
+ if (token.startsWith('-')) {
50
+ if (takesValue(findOption(command, token)) && !token.includes('=')) i++;
51
+ continue;
52
+ }
53
+ // A command with no subcommands takes positional arguments from here on.
54
+ if (command.commands.length === 0) break;
55
+ const sub = findSubcommand(command, token);
56
+ if (!sub) return { token, parent: command };
57
+ command = sub;
58
+ }
59
+ return null;
60
+ }
61
+
62
+ /** The command names `parent` actually has, for the "did you mean" line. */
63
+ function nameList(parent) {
64
+ return parent.commands.map((c) => c.name()).sort();
65
+ }
66
+
67
+ /**
68
+ * When argv asks for help on a command that does not exist, refuse by name and exit 1.
69
+ *
70
+ * @param {import('commander').Command} program
71
+ * @param {string[]} argv
72
+ * @param {{ error: (msg: string) => void, exit: (code: number) => void }} io
73
+ */
74
+ export function assertKnownCommandForHelp(program, argv, io = { error: console.error, exit: process.exit }) {
75
+ if (!argv.some((a) => HELP_FLAGS.has(a))) return;
76
+ const unknown = findUnknownCommand(program, argv);
77
+ if (!unknown) return;
78
+
79
+ const path = [];
80
+ for (let c = unknown.parent; c && c.parent; c = c.parent) path.unshift(c.name());
81
+ const where = path.length ? `'descix ${path.join(' ')}'` : 'descix';
82
+ io.error(`error: unknown command '${unknown.token}'`);
83
+ io.error(`${where} has: ${nameList(unknown.parent).join(', ')}`);
84
+ io.exit(1);
85
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@descix/cli",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "DeSciX CLI and MCP Server - Unified command-line interface for DeSciX platform",
5
5
  "repository": {
6
6
  "type": "git",
@@ -226,8 +226,9 @@ const user = await powch.auth();
226
226
  ### KB Integration
227
227
 
228
228
  If docs already exist (`docs/`, `README.md`, SDK reference files):
229
- - Copy markdown files to `kb/General/` for the sync pipeline
230
- - Keep originals as the source of truth — sync from there
229
+ - Name the docs' folder as a source in a corpus manifest (`.descix/manifests/<KB>.json`), then run
230
+ `descix kb corpus sync`. The docs stay exactly where they are — there is no copy step and no
231
+ required KB folder.
231
232
  - Ask: "I see docs in `docs/`. Want me to use those as your knowledge base?"
232
233
 
233
234
  ### Decision Guide
@@ -236,7 +237,7 @@ If docs already exist (`docs/`, `README.md`, SDK reference files):
236
237
  |-----------------|---------------|-------------|
237
238
  | HTML/JS app with `index.html` | Serve as-is, add DeSciXAppSDK.js | Use any `docs/` or `*.md` files |
238
239
  | React/Vite app | Wrap root in `<AppShell>` | Use `docs/` or README |
239
- | SDK package with docs + demo | Serve the SDK's demo page | Copy docs to `kb/General/` |
240
+ | SDK package with docs + demo | Serve the SDK's demo page | Name docs folder in a corpus manifest |
240
241
  | Docs only (no frontend) | Skip or create minimal site | Docs ARE the KB |
241
242
  | Empty repo | Scaffold from scratch | Create starter KB doc |
242
243
 
@@ -244,7 +245,8 @@ If docs already exist (`docs/`, `README.md`, SDK reference files):
244
245
 
245
246
  Every app has three parts:
246
247
  - `site/` — Frontend (any framework: React, VitePress, vanilla HTML)
247
- - `kb/General/` — Knowledge base source docs (markdown files)
248
+ - A corpus manifest (`.descix/manifests/<KB>.json`) — names the git-tracked docs `descix kb corpus
249
+ sync` publishes; there is no required KB folder
248
250
  - `microservice/` — Backend service (optional)
249
251
 
250
252
  ## App Context
@@ -165,13 +165,13 @@ unverified step — see `.descix/sdk-assets/reference/local-dev.md` §3.3.
165
165
  `DeSciXAppSDK.js` is GENERATED (from `descix-app-sdk/templates/DeSciXAppSDK.template.js`, with a `--check` drift gate) — copy it in, never hand-edit it; a local patch forks the bridge and stops inheriting its fixes.
166
166
  - **React/Vite app:** Wrap root in `<AppShell appId="{{appId}}">` from `@descix/app-sdk/AppShell`.
167
167
  - **Auth only (no DeSciX UI):** Use `PowchClient` from `@descix/app-sdk/powch-client`.
168
- - **Existing docs:** Copy `docs/*.md` to `kb/General/` for sync. Keep originals as source of truth.
168
+ - **Existing docs:** Name the docs' folder as a source in a corpus manifest (`.descix/manifests/<KB>.json`), then `descix kb corpus sync`. Docs stay where they are — no copy step.
169
169
  - **Empty repo:** Scaffold from scratch.
170
170
 
171
171
  ## App Structure
172
172
 
173
173
  - `site/` — Frontend (any framework)
174
- - `kb/General/` — Knowledge base source docs (markdown)
174
+ - A corpus manifest (`.descix/manifests/<KB>.json`) — names the git-tracked docs `descix kb corpus sync` publishes (no required folder)
175
175
  - `microservice/` — Backend service (optional)
176
176
 
177
177
  ## Context
@@ -165,13 +165,13 @@ unverified step — see `.descix/sdk-assets/reference/local-dev.md` §3.3.
165
165
  `DeSciXAppSDK.js` is GENERATED (from `descix-app-sdk/templates/DeSciXAppSDK.template.js`, with a `--check` drift gate) — copy it in, never hand-edit it; a local patch forks the bridge and stops inheriting its fixes.
166
166
  - **React/Vite app:** Wrap root in `<AppShell appId="{{appId}}">` from `@descix/app-sdk/AppShell`.
167
167
  - **Auth only (no DeSciX UI):** Use `PowchClient` from `@descix/app-sdk/powch-client`.
168
- - **Existing docs:** Copy `docs/*.md` to `kb/General/` for sync. Keep originals as source of truth.
168
+ - **Existing docs:** Name the docs' folder as a source in a corpus manifest (`.descix/manifests/<KB>.json`), then `descix kb corpus sync`. Docs stay where they are — no copy step.
169
169
  - **Empty repo:** Scaffold from scratch.
170
170
 
171
171
  ## App Structure
172
172
 
173
173
  - `site/` — Frontend (any framework)
174
- - `kb/General/` — Knowledge base source docs (markdown)
174
+ - A corpus manifest (`.descix/manifests/<KB>.json`) — names the git-tracked docs `descix kb corpus sync` publishes (no required folder)
175
175
  - `microservice/` — Backend service (optional)
176
176
 
177
177
  ## Context
@@ -165,13 +165,13 @@ unverified step — see `.descix/sdk-assets/reference/local-dev.md` §3.3.
165
165
  `DeSciXAppSDK.js` is GENERATED (from `descix-app-sdk/templates/DeSciXAppSDK.template.js`, with a `--check` drift gate) — copy it in, never hand-edit it; a local patch forks the bridge and stops inheriting its fixes.
166
166
  - **React/Vite app:** Wrap root in `<AppShell appId="{{appId}}">` from `@descix/app-sdk/AppShell`.
167
167
  - **Auth only (no DeSciX UI):** Use `PowchClient` from `@descix/app-sdk/powch-client`.
168
- - **Existing docs:** Copy `docs/*.md` to `kb/General/` for sync. Keep originals as source of truth.
168
+ - **Existing docs:** Name the docs' folder as a source in a corpus manifest (`.descix/manifests/<KB>.json`), then `descix kb corpus sync`. Docs stay where they are — no copy step.
169
169
  - **Empty repo:** Scaffold from scratch.
170
170
 
171
171
  ## App Structure
172
172
 
173
173
  - `site/` — Frontend (any framework)
174
- - `kb/General/` — Knowledge base source docs (markdown)
174
+ - A corpus manifest (`.descix/manifests/<KB>.json`) — names the git-tracked docs `descix kb corpus sync` publishes (no required folder)
175
175
  - `microservice/` — Backend service (optional)
176
176
 
177
177
  ## Context