@descix/cli 1.0.7 → 1.0.8

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 (40) hide show
  1. package/README.md +1 -1
  2. package/agent-assets/guides/README.md +1 -1
  3. package/agent-assets/guides/dynamic-site-pattern.md +7 -16
  4. package/agent-assets/instructions/app-asset-validation.md +1 -1
  5. package/agent-assets/reference/architecture.md +20 -25
  6. package/agent-assets/reference/local-dev.md +1 -6
  7. package/agent-assets/reference/mcp-integration.md +15 -9
  8. package/agent-assets/reference/workspace-config.md +2 -2
  9. package/bin/descix.js +204 -547
  10. package/lib/command-visibility.js +213 -0
  11. package/lib/commands/corpus.js +2 -5
  12. package/lib/commands/kb.js +2 -2
  13. package/lib/commands/retired-kb-sync.js +5 -27
  14. package/lib/commands/status.js +0 -9
  15. package/lib/sdk-assets.js +28 -0
  16. package/lib/verb-invokes.generated.json +233 -0
  17. package/lib/workspace-config.js +9 -44
  18. package/package.json +6 -2
  19. package/templates/agent-claude.md +1 -3
  20. package/templates/agent-cline.md +1 -2
  21. package/templates/agent-copilot.md +1 -2
  22. package/templates/agent-cursor.md +1 -2
  23. package/templates/scaffolds/microservice/SERVICE_README_sdk.md +1 -1
  24. package/templates/scaffolds/microservice/templates/SERVICE_README_TEMPLATE.md +2 -3
  25. package/agent-assets/rules/descix_mcp.template.mdc +0 -243
  26. package/lib/commands/briefer/errors.js +0 -88
  27. package/lib/commands/briefer/index.js +0 -322
  28. package/lib/commands/briefer/sources/canonical-sources.js +0 -129
  29. package/lib/commands/briefer/sources/entitlements.js +0 -220
  30. package/lib/commands/briefer/sources/environments.js +0 -205
  31. package/lib/commands/briefer/sources/identifiers.js +0 -214
  32. package/lib/commands/briefer/sources/microservice-deploy.js +0 -267
  33. package/lib/commands/briefer/sources/routing.js +0 -275
  34. package/lib/commands/briefer/sources/what-is-not.js +0 -223
  35. package/lib/commands/briefer/stitcher.js +0 -134
  36. package/lib/commands/briefer/util/source-reader.js +0 -502
  37. package/lib/commands/mcp.js +0 -273
  38. package/lib/commands/update.js +0 -581
  39. package/lib/wizard/setup.js +0 -585
  40. package/templates/descix_mcp.mdc +0 -122
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Command Visibility — the PUBLIC-vs-admin CLI help listing.
3
+ *
4
+ * CEO ruling (verbatim): "The microservice manifest consumed by DeSciX core should determine
5
+ * what gets exposed via MCP (and therefore CLI listing should be easily exposed there too for
6
+ * the core itself) - shouldn't we reuse that surface." And: "It's not a worry that admin
7
+ * commands can be discovered by normal users but rather we are trying to avoid the flood of
8
+ * noise so it is acceptable to have two lists that can be derived from the same manifest."
9
+ *
10
+ * THE CLASS COMES FROM THE SERVER AT RUNTIME (`get_command_surface`, guest-allowed) — there is
11
+ * NO committed class table in this repo. The only thing committed here is
12
+ * lib/verb-invokes.generated.json, a CLI-owned fact ("this verb invokes these commands"),
13
+ * regenerated by scripts/generate-verb-invokes.mjs from bin/descix.js + lib/** itself.
14
+ *
15
+ * A verb is hidden from the default listing when it invokes at least one command AND every
16
+ * command it invokes is classified 'admin' by the server. A verb with no recorded invokes
17
+ * (local-only, or a verb whose only invoke call sites are dynamic — see
18
+ * scripts/lib/verb-invoke-graph.mjs) stays visible: absence of information is not evidence of
19
+ * admin-only-ness. A GROUP (a command with children and no action of its own) is hidden when
20
+ * every one of its children ends up hidden — hiding is transitive up the tree, computed
21
+ * bottom-up from the LIVE commander tree (never a second, hand-kept tree).
22
+ *
23
+ * Hiding is LISTING ONLY. A hidden verb still EXECUTES normally when typed; the server's own
24
+ * permission gate (checkCommandPermission) is the actual enforcement, unchanged by this file.
25
+ */
26
+ import fs from 'fs/promises';
27
+ import path from 'path';
28
+ import os from 'os';
29
+ import VERB_INVOKES from './verb-invokes.generated.json' with { type: 'json' };
30
+
31
+ const CACHE_PATH = path.join(os.homedir(), '.descix', 'command-surface-cache.json');
32
+ /** Short TTL: this is a LISTING convenience cache, not a security boundary — a stale read only
33
+ * ever risks showing (or hiding) a help row for a few minutes, never changes what executes. */
34
+ const CACHE_TTL_MS = 5 * 60 * 1000;
35
+
36
+ /**
37
+ * ONE explicit, CLI-owned declaration: Drive content authoring (`descix drive pull/push`) needs
38
+ * infrastructure admin credentials (Google ADC / a Drive service account) that `get_command_surface`
39
+ * has no visibility into — it is not gated by any COMMAND_PERMISSIONS entry the server classifies
40
+ * 'admin', so it can never be derived from the manifest. Per the CEO's ruling these stay OUT of
41
+ * the public CLI listing (internal Drive authoring still uses them — hidden, never deleted). The
42
+ * `drive` group itself is included for clarity; it would also be hidden automatically once both
43
+ * of its children are (see applyVisibility's group rule), but naming it here keeps this ONE set
44
+ * the single place that answers "why is drive hidden" rather than splitting the answer across a
45
+ * declaration and an inference.
46
+ */
47
+ export const INFRA_ADMIN_HIDDEN_PATHS = new Set(['drive', 'drive pull', 'drive push']);
48
+
49
+ /** @returns {Record<string,string[]>} the committed, generated verb -> invoked-commands map. */
50
+ export function getVerbInvokeMap() {
51
+ return VERB_INVOKES;
52
+ }
53
+
54
+ /**
55
+ * Fetch the server's per-command visibility surface as a guest (no login needed).
56
+ * @param {import('./api-client.js').DeSciXApiClient} apiClient
57
+ * @returns {Promise<{ service: string, manifest_hash: string, commands: Record<string,'public'|'admin'> }>}
58
+ */
59
+ export async function fetchCommandSurface(apiClient) {
60
+ const resp = await apiClient.invoke('get_command_surface', {}, { allowGuest: true });
61
+ const msg = resp?.message || resp;
62
+ if (!msg || typeof msg.commands !== 'object' || msg.commands === null) {
63
+ throw new Error(`get_command_surface returned an unexpected shape: ${JSON.stringify(resp)}`);
64
+ }
65
+ return msg;
66
+ }
67
+
68
+ async function readCache() {
69
+ try {
70
+ const raw = await fs.readFile(CACHE_PATH, 'utf8');
71
+ return JSON.parse(raw);
72
+ } catch {
73
+ return {};
74
+ }
75
+ }
76
+
77
+ async function writeCache(cache) {
78
+ try {
79
+ await fs.mkdir(path.dirname(CACHE_PATH), { recursive: true });
80
+ await fs.writeFile(CACHE_PATH, JSON.stringify(cache, null, 2), 'utf8');
81
+ } catch {
82
+ // Best-effort. A cache write failure must never break help output — the caller already has
83
+ // the freshly-fetched surface in hand and can render with it regardless.
84
+ }
85
+ }
86
+
87
+ /**
88
+ * The server surface for `origin`, from the user-level cache (keyed by origin, short TTL) when
89
+ * fresh, else fetched live and cached. Throws if the fetch fails (network down, old server
90
+ * without the command, etc.) — the caller decides what "help shows everything" means.
91
+ *
92
+ * @param {string} origin
93
+ * @param {import('./api-client.js').DeSciXApiClient} apiClient
94
+ * @returns {Promise<{ commands: Record<string,'public'|'admin'>, fromCache: boolean }>}
95
+ */
96
+ export async function getCommandSurface(origin, apiClient) {
97
+ const cache = await readCache();
98
+ const entry = cache[origin];
99
+ if (entry && typeof entry.fetchedAt === 'number' && (Date.now() - entry.fetchedAt) < CACHE_TTL_MS) {
100
+ return { commands: entry.surface.commands, fromCache: true };
101
+ }
102
+ const surface = await fetchCommandSurface(apiClient);
103
+ cache[origin] = { surface, fetchedAt: Date.now() };
104
+ await writeCache(cache);
105
+ return { commands: surface.commands, fromCache: false };
106
+ }
107
+
108
+ /**
109
+ * Should a single LEAF verb (identified by its full space-joined path, e.g. "kb corpus sync") be
110
+ * hidden from the default listing, given the server's command->visibility surface?
111
+ *
112
+ * @param {string} verbPath
113
+ * @param {Record<string,'public'|'admin'>} surfaceCommands
114
+ * @returns {boolean}
115
+ */
116
+ export function shouldHideLeaf(verbPath, surfaceCommands) {
117
+ if (INFRA_ADMIN_HIDDEN_PATHS.has(verbPath)) return true;
118
+ const invokes = VERB_INVOKES[verbPath];
119
+ if (!invokes || invokes.length === 0) return false; // no recorded invokes -> stays visible
120
+ return invokes.every((cmd) => surfaceCommands[cmd] === 'admin');
121
+ }
122
+
123
+ /**
124
+ * Apply hide/show to the LIVE commander tree rooted at `program`, bottom-up. Never reads or
125
+ * builds a second command tree — `cmd.commands` / `cmd._actionHandler` (commander's own runtime
126
+ * state) is the only source of "what verbs exist and how they nest", so this can never drift
127
+ * from the tree `--help` actually renders.
128
+ *
129
+ * @param {import('commander').Command} program
130
+ * @param {Record<string,'public'|'admin'>} surfaceCommands
131
+ */
132
+ export function applyVisibility(program, surfaceCommands) {
133
+ function visit(cmd, pathTokens) {
134
+ const verbPath = pathTokens.join(' ');
135
+ const hasChildren = Array.isArray(cmd.commands) && cmd.commands.length > 0;
136
+ // ADDITIVE ONLY. Some commands are registered `{ hidden: true }` by the CLI itself for
137
+ // reasons that have nothing to do with server admin-gating — see the retired-surface
138
+ // registrations in lib/commands/retired-kb-sync.js, each a deliberate loud-refusal stub kept
139
+ // out of the default listing so it doesn't clutter it, while still working and refusing
140
+ // clearly when typed. This layer may HIDE a visible command; it must never REVEAL a command
141
+ // the CLI already chose to hide. MEASURED: an early version unconditionally overwrote
142
+ // `_hidden`, which un-hid a retired-surface stub the moment its verb had no generated-map
143
+ // entry (it invokes no /apifront command at all, so its invoke list is empty).
144
+ const alreadyHidden = !!cmd._hidden;
145
+
146
+ if (hasChildren) {
147
+ let allChildrenHidden = true;
148
+ for (const child of cmd.commands) {
149
+ const childHidden = visit(child, [...pathTokens, child.name()]);
150
+ if (!childHidden) allChildrenHidden = false;
151
+ }
152
+ if (pathTokens.length === 0) return false; // never hide the root program
153
+ if (cmd._actionHandler) {
154
+ // A command that is BOTH a group and its own runnable leaf (not used in this CLI today,
155
+ // but commander allows it) is judged as a leaf: its own invokes decide it, independent
156
+ // of its children.
157
+ const hidden = alreadyHidden || shouldHideLeaf(verbPath, surfaceCommands);
158
+ cmd._hidden = hidden;
159
+ return hidden;
160
+ }
161
+ cmd._hidden = alreadyHidden || allChildrenHidden;
162
+ return cmd._hidden;
163
+ }
164
+
165
+ if (pathTokens.length === 0) return false; // the root has no children in practice, but guard anyway
166
+ const hidden = alreadyHidden || shouldHideLeaf(verbPath, surfaceCommands);
167
+ cmd._hidden = hidden;
168
+ return hidden;
169
+ }
170
+ visit(program, []);
171
+ }
172
+
173
+ /**
174
+ * Is this invocation one that will render `--help` output? Only these fetch the network — every
175
+ * other invocation must stay fast and offline-safe.
176
+ *
177
+ * Recognizes: `-h` / `--help` anywhere, `help` in subcommand position, a bare invocation (no positional tokens once
178
+ * global flags are stripped), and a "bare group" invocation (the resolved command has children
179
+ * but no action handler of its own — e.g. `descix app` with no subcommand, which commander
180
+ * renders as help even though the CLI never called outputHelp() itself).
181
+ *
182
+ * @param {import('commander').Command} program
183
+ * @param {string[]} argv - process.argv.slice(2)
184
+ * @param {{ valueFlags?: string[], booleanFlags?: string[] }} [globalFlags]
185
+ * @returns {boolean}
186
+ */
187
+ export function isHelpInvocation(program, argv, globalFlags = {}) {
188
+ if (argv.length === 0) return true;
189
+ if (argv.includes('-h') || argv.includes('--help')) return true;
190
+ if (argv.includes('-V') || argv.includes('--version')) return false; // prints a version, renders no listing
191
+
192
+ const valueFlags = new Set(globalFlags.valueFlags || []);
193
+ const booleanFlags = new Set(globalFlags.booleanFlags || []);
194
+ const positional = [];
195
+ for (let i = 0; i < argv.length; i++) {
196
+ const tok = argv[i];
197
+ if (valueFlags.has(tok)) { i++; continue; }
198
+ if (booleanFlags.has(tok)) continue;
199
+ if (tok.startsWith('-')) continue; // an option belonging to whatever command it turns out to be
200
+ positional.push(tok);
201
+ }
202
+ if (positional.length === 0) return true;
203
+
204
+ let cmd = program;
205
+ for (const tok of positional) {
206
+ if (cmd._actionHandler) break; // reached a leaf; remaining tokens are ITS args, not subcommands
207
+ if (tok === 'help') return true; // commander's help subcommand, only in subcommand position
208
+ const next = (cmd.commands || []).find((c) => c.name() === tok || (c.aliases && c.aliases().includes(tok)));
209
+ if (!next) return false; // unresolvable path — commander's own error path, not ours to fetch for
210
+ cmd = next;
211
+ }
212
+ return !cmd._actionHandler;
213
+ }
@@ -452,16 +452,13 @@ export async function runCorpusSync(apiClient, options) {
452
452
  const missingKbNames = requestedKbNames.filter(name => !registeredKbNames.has(name));
453
453
  if (missingKbNames.length > 0) {
454
454
  // Hard-fail: every KB we are about to sync into must already be registered in Firestore.
455
- // No hardcoded fallback. `app init` is the verb that actually creates a KB on a
456
- // git-mode app (init_git_mode_kb, bin/descix.js:1163). `kb create` is Drive-mode
457
- // wired (create_skeleton_kb, :2087) and fails here — filed as its own defect.
455
+ // No hardcoded fallback. `app init --kb` is the verb that creates a KB (init_git_mode_kb).
458
456
  spinner.fail(`Unregistered KB(s) for app "${appId}"`);
459
457
  throw new Error(
460
458
  `KnowledgeBase document(s) missing in Firestore for app "${appId}": ${missingKbNames.join(', ')}.\n` +
461
459
  `Registered KBs for this app: ${[...registeredKbNames].join(', ') || '(none)'}.\n` +
462
460
  `Syncing vectors into Pinecone without a matching KB doc would orphan them (chat queries hard-fail).\n` +
463
- `Fix: run \`descix app init -a ${appId}\` — it creates the KB via init_git_mode_kb and needs no Drive folder.\n` +
464
- `(\`descix kb create\` currently routes through create_skeleton_kb and FAILS on a git-mode app.)`
461
+ `Fix: run \`descix app init -a ${appId} --kb <kb_name>\` for each missing KB — it creates the KB and needs no Drive folder.`
465
462
  );
466
463
  }
467
464
 
@@ -179,9 +179,9 @@ export async function runKbPush(apiClient, options) {
179
179
  const onConflictPrompt = options.interactive ? async (fileName, fileInfo) => {
180
180
  spinner.stop();
181
181
  requireInteractive({
182
- what: 'descix kb push --interactive',
182
+ what: 'descix drive push --interactive',
183
183
  question: `File "${fileName}" exists in Drive. Overwrite or skip?`,
184
- nonInteractiveForm: ['descix kb push # without --interactive, conflicts resolve without a prompt']
184
+ nonInteractiveForm: ['descix drive push # without --interactive, conflicts resolve without a prompt']
185
185
  });
186
186
  const { action } = await inquirer.prompt([{
187
187
  type: 'list',
@@ -19,20 +19,17 @@
19
19
  export const CANONICAL_KB_SYNC = 'descix kb corpus sync';
20
20
 
21
21
  /** The verb that creates a KB — `kb corpus sync`'s dependency (I4). */
22
- export const CANONICAL_KB_CREATE = 'descix kb create';
22
+ export const CANONICAL_KB_CREATE = 'descix app init --kb <kb_name>';
23
23
 
24
24
  /**
25
25
  * Every KB-sync surface retired by ws-devplane-cli-kb-surface-single-canonical-sync.
26
26
  * `invocation` is what a user types; `parent` is the commander parent it hung off.
27
27
  */
28
28
  export const RETIRED_KB_SYNC_SURFACES = [
29
- { id: 'sync', parent: 'program', name: 'sync', invocation: 'descix sync', registered: true },
30
- { id: 'sync.kb', parent: 'sync', name: 'kb', invocation: 'descix sync kb', registered: true },
31
- { id: 'kb.chunk', parent: 'kb', name: 'chunk', invocation: 'descix kb chunk', registered: true },
32
- { id: 'kb.sync', parent: 'kb', name: 'sync', invocation: 'descix kb sync', registered: true },
33
- // registered:false -- `update` survives for app/site, so this one is a dispatcher branch
34
- // inside the live `update` command rather than a commander registration of its own.
35
- { id: 'update.kb', parent: 'update', name: 'kb', invocation: 'descix update kb', registered: false },
29
+ { id: 'sync', parent: 'program', name: 'sync', invocation: 'descix sync' },
30
+ { id: 'sync.kb', parent: 'sync', name: 'kb', invocation: 'descix sync kb' },
31
+ { id: 'kb.chunk', parent: 'kb', name: 'chunk', invocation: 'descix kb chunk' },
32
+ { id: 'kb.sync', parent: 'kb', name: 'sync', invocation: 'descix kb sync' },
36
33
  ];
37
34
 
38
35
  /** Implementations deleted with those surfaces. No exported symbol survives without a caller (I3). */
@@ -61,24 +58,6 @@ export function retiredKbSyncMessage(invocation) {
61
58
  );
62
59
  }
63
60
 
64
- /**
65
- * Refuse a retired invocation LOUDLY and exit non-zero.
66
- *
67
- * MEASURED, not assumed: a `throw` from updateAuto is NOT swallowed — updateAuto's own catch
68
- * prints the message before rethrowing, so both forms reach the user and exit 1. This exists
69
- * for two smaller, real reasons: (1) ONE owner for the refusal, so the dispatcher branch and
70
- * updateAuto's kb branch cannot drift into different wording or different exit codes; and
71
- * (2) a deliberate retirement is not a crash, so it should not be framed as "✖ Update failed".
72
- *
73
- * @param {string} invocation - the retired invocation, e.g. 'descix update kb'
74
- * @param {(s:string)=>string} red - chalk.red or equivalent
75
- * @returns {never}
76
- */
77
- export function refuseRetiredKbSync(invocation, red) {
78
- console.error(red(`\n❌ ${retiredKbSyncMessage(invocation)}\n`));
79
- process.exit(1);
80
- }
81
-
82
61
  /**
83
62
  * Register a retired invocation so it exits NON-ZERO naming the canonical surface.
84
63
  * Accepts and ignores any args/options the old surface took, so an old script fails with
@@ -120,7 +99,6 @@ export function registerRetiredKbSync(parent, name, invocation, red) {
120
99
  export function registerAllRetiredKbSync(roots, red) {
121
100
  const byId = { ...roots };
122
101
  for (const s of RETIRED_KB_SYNC_SURFACES) {
123
- if (!s.registered) continue;
124
102
  const parent = byId[s.parent];
125
103
  if (!parent) {
126
104
  throw new Error(
@@ -206,15 +206,6 @@ export async function runStatus(options = {}) {
206
206
  console.log(`Service Key: ${chalk.gray('None')} (dev-overrides.json)`);
207
207
  }
208
208
 
209
- // Check for MCP rules
210
- const rulesPath = path.join(checkDir, '.cursor', 'rules', 'descix_mcp.mdc');
211
- try {
212
- await fs.access(rulesPath);
213
- console.log(`MCP Rules: ${chalk.green('Deployed')} (.cursor/rules/descix_mcp.mdc)`);
214
- } catch {
215
- console.log(`MCP Rules: ${chalk.gray('Not Deployed')}`);
216
- }
217
-
218
209
  // Check gcloud
219
210
  const gcloudStatus = await checkGcloud();
220
211
  if (gcloudStatus.installed) {
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The SDK's agent assets (instructions, guides, reference) ship inside this package at
3
+ * agent-assets/. `pullSdkAssets` copies them into a workspace at .descix/sdk-assets/ so a local AI
4
+ * agent can read them. A missing source is a broken install and throws; it is never skipped.
5
+ */
6
+ import * as fs from 'fs/promises';
7
+ import * as path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ /** agent-assets/ at the package root, one level above lib/. */
11
+ export const SDK_ASSETS_SOURCE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'agent-assets');
12
+
13
+ /**
14
+ * Copy the package's agent-assets/ to <workspaceRoot>/.descix/sdk-assets/.
15
+ * @param {string} workspaceRoot
16
+ * @returns {Promise<string>} the target directory
17
+ * @throws when the package's agent-assets/ is absent or the copy fails
18
+ */
19
+ export async function pullSdkAssets(workspaceRoot) {
20
+ const target = path.join(workspaceRoot, '.descix', 'sdk-assets');
21
+ try {
22
+ await fs.access(SDK_ASSETS_SOURCE);
23
+ } catch {
24
+ throw new Error(`SDK agent assets are missing from this install (${SDK_ASSETS_SOURCE}). Reinstall @descix/cli.`);
25
+ }
26
+ await fs.cp(SDK_ASSETS_SOURCE, target, { recursive: true });
27
+ return target;
28
+ }
@@ -0,0 +1,233 @@
1
+ {
2
+ "admin-login": [
3
+ "admin_bootstrap_login"
4
+ ],
5
+ "airdrop execute-queue": [
6
+ "airdrop_execute_queue"
7
+ ],
8
+ "app delete": [
9
+ "delete_app"
10
+ ],
11
+ "app init": [
12
+ "create_app_for_community",
13
+ "get_product_context",
14
+ "init_git_mode_kb"
15
+ ],
16
+ "app invite": [
17
+ "create_app_invite"
18
+ ],
19
+ "app list": [
20
+ "fetch_my_purchases"
21
+ ],
22
+ "app media-upload": [
23
+ "get_asset_upload_token"
24
+ ],
25
+ "app open": [],
26
+ "app set-api-url": [
27
+ "update_app_metadata"
28
+ ],
29
+ "app set-default-model": [
30
+ "clear_app_default_model",
31
+ "set_app_default_model"
32
+ ],
33
+ "app set-listed": [
34
+ "update_app"
35
+ ],
36
+ "app set-localpath": [],
37
+ "app set-name": [
38
+ "update_app"
39
+ ],
40
+ "app set-port": [],
41
+ "app set-price": [
42
+ "update_app_metadata"
43
+ ],
44
+ "app set-repo": [
45
+ "set_app_repo"
46
+ ],
47
+ "app set-site": [],
48
+ "app sync-assets": [
49
+ "sync_app_assets"
50
+ ],
51
+ "app unmap": [],
52
+ "buy chains": [],
53
+ "buy poll": [
54
+ "get_quote_status"
55
+ ],
56
+ "buy quote": [
57
+ "create_crypto_quote"
58
+ ],
59
+ "buy status": [
60
+ "get_quote_status"
61
+ ],
62
+ "chat": [
63
+ "ask_multiple_apps",
64
+ "ask_question_to_app"
65
+ ],
66
+ "clone": [
67
+ "get_repo_credentials"
68
+ ],
69
+ "community check-token": [
70
+ "check_token_symbol_available"
71
+ ],
72
+ "community contract": [
73
+ "get_contract_details"
74
+ ],
75
+ "community create": [
76
+ "create_community_skeleton"
77
+ ],
78
+ "community delete": [
79
+ "delete_community"
80
+ ],
81
+ "community deploy-token": [
82
+ "deploy_contract"
83
+ ],
84
+ "community info": [
85
+ "get_community"
86
+ ],
87
+ "community link-token": [
88
+ "link_contract_to_community"
89
+ ],
90
+ "community list": [
91
+ "find_communities"
92
+ ],
93
+ "community rename": [
94
+ "rename_community"
95
+ ],
96
+ "config init": [],
97
+ "config set-dev-certs": [],
98
+ "config set-env": [],
99
+ "config set-gateway-port": [],
100
+ "config set-powch-url": [],
101
+ "config set-site-url": [],
102
+ "config set-url": [],
103
+ "config show": [],
104
+ "credits balance": [
105
+ "get_credit_balance"
106
+ ],
107
+ "credits buy": [
108
+ "create_stripe_checkout_session"
109
+ ],
110
+ "credits grant": [
111
+ "grant_credits"
112
+ ],
113
+ "credits history": [
114
+ "get_credit_history"
115
+ ],
116
+ "credits refund": [
117
+ "refund_credits"
118
+ ],
119
+ "doctor": [],
120
+ "drive pull": [],
121
+ "drive push": [],
122
+ "health": [],
123
+ "init": [
124
+ "find_communities",
125
+ "resolve_invite"
126
+ ],
127
+ "kb clear-override-model": [
128
+ "clear_kb_model_override"
129
+ ],
130
+ "kb corpus status": [],
131
+ "kb corpus sync": [
132
+ "get_kb_rag_status",
133
+ "get_product_context",
134
+ "kb_delete_chunks",
135
+ "kb_list_file_ids",
136
+ "kb_sync_chunks",
137
+ "list_knowledge_bases"
138
+ ],
139
+ "kb delete": [
140
+ "delete_knowledge_base"
141
+ ],
142
+ "kb doctor": [
143
+ "get_kb_rag_status"
144
+ ],
145
+ "kb list": [
146
+ "list_knowledge_bases"
147
+ ],
148
+ "kb set-override-model": [
149
+ "set_kb_model_override"
150
+ ],
151
+ "login": [
152
+ "device_check_status",
153
+ "device_request_login",
154
+ "sync_auto_purchases"
155
+ ],
156
+ "logout": [],
157
+ "mcp execute": [],
158
+ "mcp-serve": [],
159
+ "microservice health": [
160
+ "service_health_check"
161
+ ],
162
+ "microservice init": [],
163
+ "microservice list": [
164
+ "list_services"
165
+ ],
166
+ "microservice register": [
167
+ "register_service"
168
+ ],
169
+ "microservice register-delegate": [
170
+ "fetch_my_purchases",
171
+ "register_delegate"
172
+ ],
173
+ "microservice reload": [
174
+ "reload_service_manifests"
175
+ ],
176
+ "microservice restart": [],
177
+ "microservice vectorize": [
178
+ "vectorize_service_readme"
179
+ ],
180
+ "new-chat": [],
181
+ "purchases": [
182
+ "fetch_my_purchases"
183
+ ],
184
+ "quickstart": [
185
+ "device_check_status",
186
+ "device_request_login",
187
+ "find_communities",
188
+ "resolve_invite",
189
+ "sync_auto_purchases"
190
+ ],
191
+ "reconnect": [
192
+ "reconnect_by_wallet"
193
+ ],
194
+ "referral create": [
195
+ "generate_referral_code"
196
+ ],
197
+ "role create": [
198
+ "create_role"
199
+ ],
200
+ "serve": [],
201
+ "site delete": [
202
+ "delete_site_files"
203
+ ],
204
+ "site init": [],
205
+ "site list": [
206
+ "list_site_files"
207
+ ],
208
+ "site status": [
209
+ "get_site_manifest"
210
+ ],
211
+ "site upload": [
212
+ "confirm_site_deploy",
213
+ "get_site_build_config",
214
+ "get_site_deploy_token"
215
+ ],
216
+ "stats": [
217
+ "get_user_community_stats"
218
+ ],
219
+ "status": [],
220
+ "store generate-summary": [
221
+ "generate_entity_summary"
222
+ ],
223
+ "store search": [
224
+ "search_store"
225
+ ],
226
+ "tell-me-how": [
227
+ "tell_me_how"
228
+ ],
229
+ "whoami": [
230
+ "fetch_my_purchases",
231
+ "validate_session"
232
+ ]
233
+ }