@descix/cli 1.0.16 → 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.
@@ -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
+ }
@@ -190,11 +190,15 @@
190
190
  "fetch_my_purchases"
191
191
  ],
192
192
  "quickstart": [
193
+ "create_app_for_community",
193
194
  "device_check_status",
194
195
  "device_request_login",
195
196
  "find_communities",
197
+ "get_product_context",
198
+ "init_git_mode_kb",
196
199
  "resolve_invite",
197
- "sync_auto_purchases"
200
+ "sync_auto_purchases",
201
+ "update_community_metadata"
198
202
  ],
199
203
  "reconnect": [
200
204
  "reconnect_by_wallet"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@descix/cli",
3
- "version": "1.0.16",
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",
@@ -84,15 +84,18 @@ Use `find_communities` and `list_apps_for_community` to show options, then ask:
84
84
  > "Which community and app should this project target?"
85
85
 
86
86
  ### Checkpoint 3: Environment
87
- > "Should this run against local dev backend (localhost:4000) or hosted API?"
87
+ > "Should this app be built against DEV (https://dev.descix.net) or production?"
88
+
89
+ Pin the choice before anything else; every later command reads it from the workspace.
88
90
 
89
91
  ### Canonical Setup Commands (run in terminal after checkpoints)
90
92
  ```bash
91
- descix whoami # confirm identity
92
- descix app list # see available apps
93
- descix init -c <community> -a <app> -p . # create workspace.json
94
- descix app init -a <app> -c <community> # register app on platform
93
+ descix --env dev config init # pin the environment (omit --env dev for production)
94
+ descix login # sign in
95
+ descix app init -a <name> -c <community> # create the app; the platform issues its id
95
96
  ```
97
+ `app init` prints the app id the platform issued (with `-c` it is `<community>-<name>`). Use that
98
+ id, not the name, as `-a` in every later command.
96
99
 
97
100
  ### Checkpoint 4: Content Strategy
98
101
  > "Should I create a starter KB doc now, or wait for your domain docs?"
@@ -223,8 +226,9 @@ const user = await powch.auth();
223
226
  ### KB Integration
224
227
 
225
228
  If docs already exist (`docs/`, `README.md`, SDK reference files):
226
- - Copy markdown files to `kb/General/` for the sync pipeline
227
- - 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.
228
232
  - Ask: "I see docs in `docs/`. Want me to use those as your knowledge base?"
229
233
 
230
234
  ### Decision Guide
@@ -233,7 +237,7 @@ If docs already exist (`docs/`, `README.md`, SDK reference files):
233
237
  |-----------------|---------------|-------------|
234
238
  | HTML/JS app with `index.html` | Serve as-is, add DeSciXAppSDK.js | Use any `docs/` or `*.md` files |
235
239
  | React/Vite app | Wrap root in `<AppShell>` | Use `docs/` or README |
236
- | 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 |
237
241
  | Docs only (no frontend) | Skip or create minimal site | Docs ARE the KB |
238
242
  | Empty repo | Scaffold from scratch | Create starter KB doc |
239
243
 
@@ -241,7 +245,8 @@ If docs already exist (`docs/`, `README.md`, SDK reference files):
241
245
 
242
246
  Every app has three parts:
243
247
  - `site/` — Frontend (any framework: React, VitePress, vanilla HTML)
244
- - `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
245
250
  - `microservice/` — Backend service (optional)
246
251
 
247
252
  ## App Context
@@ -56,15 +56,15 @@ Ask the user at each checkpoint — don't assume:
56
56
 
57
57
  1. **Objective:** "Explore existing apps or build something new?"
58
58
  2. **Community/App:** Use `find_communities` + `list_apps_for_community`, then ask which to target
59
- 3. **Environment:** "Local dev (localhost:4000) or hosted API?" (Skip if `app.json` has `api_url`)
59
+ 3. **Environment:** "Build against DEV (https://dev.descix.net) or production?" Pin it first.
60
60
 
61
61
  Canonical setup commands:
62
62
  ```bash
63
- descix whoami # confirm identity
64
- descix app list # see available apps
65
- descix init -c <community> -a <app> -p . # create workspace.json
66
- descix app init -a <app> -c <community> # register app on platform
63
+ descix --env dev config init # pin the environment (omit --env dev for production)
64
+ descix login # sign in
65
+ descix app init -a <name> -c <community> # create the app; the platform issues its id
67
66
  ```
67
+ `app init` prints the issued id (`<community>-<name>` with `-c`); use it as `-a` from then on.
68
68
 
69
69
  4. **Content strategy:** "Create starter KB now or wait for your docs?"
70
70
  5. **Frontend scope:** "Plain HTML or a framework (React, VitePress)?"
@@ -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
@@ -56,15 +56,15 @@ Ask the user at each checkpoint — don't assume:
56
56
 
57
57
  1. **Objective:** "Explore existing apps or build something new?"
58
58
  2. **Community/App:** Use `find_communities` + `list_apps_for_community`, then ask which to target
59
- 3. **Environment:** "Local dev (localhost:4000) or hosted API?" (Skip if `app.json` has `api_url`)
59
+ 3. **Environment:** "Build against DEV (https://dev.descix.net) or production?" Pin it first.
60
60
 
61
61
  Canonical setup commands:
62
62
  ```bash
63
- descix whoami # confirm identity
64
- descix app list # see available apps
65
- descix init -c <community> -a <app> -p . # create workspace.json
66
- descix app init -a <app> -c <community> # register app on platform
63
+ descix --env dev config init # pin the environment (omit --env dev for production)
64
+ descix login # sign in
65
+ descix app init -a <name> -c <community> # create the app; the platform issues its id
67
66
  ```
67
+ `app init` prints the issued id (`<community>-<name>` with `-c`); use it as `-a` from then on.
68
68
 
69
69
  4. **Content strategy:** "Create starter KB now or wait for your docs?"
70
70
  5. **Frontend scope:** "Plain HTML or a framework (React, VitePress)?"
@@ -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
@@ -56,15 +56,15 @@ Ask the user at each checkpoint — don't assume:
56
56
 
57
57
  1. **Objective:** "Explore existing apps or build something new?"
58
58
  2. **Community/App:** Use `find_communities` + `list_apps_for_community`, then ask which to target
59
- 3. **Environment:** "Local dev (localhost:4000) or hosted API?" (Skip if `app.json` has `api_url`)
59
+ 3. **Environment:** "Build against DEV (https://dev.descix.net) or production?" Pin it first.
60
60
 
61
61
  Canonical setup commands:
62
62
  ```bash
63
- descix whoami # confirm identity
64
- descix app list # see available apps
65
- descix init -c <community> -a <app> -p . # create workspace.json
66
- descix app init -a <app> -c <community> # register app on platform
63
+ descix --env dev config init # pin the environment (omit --env dev for production)
64
+ descix login # sign in
65
+ descix app init -a <name> -c <community> # create the app; the platform issues its id
67
66
  ```
67
+ `app init` prints the issued id (`<community>-<name>` with `-c`); use it as `-a` from then on.
68
68
 
69
69
  4. **Content strategy:** "Create starter KB now or wait for your docs?"
70
70
  5. **Frontend scope:** "Plain HTML or a framework (React, VitePress)?"
@@ -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