@descix/cli 1.0.16 → 1.0.17

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/bin/descix.js CHANGED
@@ -34,6 +34,7 @@ import { createPromptSession } from '../lib/interactive.js';
34
34
  import { registerAllRetiredKbSync, CANONICAL_KB_SYNC } from '../lib/commands/retired-kb-sync.js';
35
35
  import { runStatus } from '../lib/commands/status.js';
36
36
  import { refreshCommunityIdentity, printIdentityReceipt } from '../lib/commands/communityIdentity.js';
37
+ import { runAppInit } from '../lib/commands/appInit.js';
37
38
  import { runDoctor } from '../lib/commands/doctor.js';
38
39
  import { runHealth } from '../lib/commands/health.js';
39
40
  import * as kbCommands from '../lib/commands/kb.js';
@@ -1082,131 +1083,7 @@ appCommand
1082
1083
  try {
1083
1084
  const apiClient = new DeSciXApiClient();
1084
1085
  await requireAuth(apiClient);
1085
- let appId = options.app;
1086
- const kbId = options.kb || 'General';
1087
-
1088
- // Refuse an unusable -p BEFORE anything is written — server-side included. The same
1089
- // resolver the workspace loader applies on every read decides it, so a value accepted here
1090
- // is one the next read accepts too. Refusing only at registration came AFTER a `-c` create,
1091
- // leaving a platform app with no local registration (measured 2026-09-18, daita-docs).
1092
- const workspaceConfig = await WorkspaceConfig.tryLoad();
1093
- if (options.path) {
1094
- resolveWorkspacePath(workspaceConfig?.workspaceRoot || process.cwd(), options.path, appId);
1095
- }
1096
-
1097
- // Resolve community_id from the Products registry to learn whether the app exists yet.
1098
- let communityId;
1099
- try {
1100
- const productCtx = await apiClient.invoke('get_product_context', { app_id: appId });
1101
- communityId = (productCtx.message || productCtx).community_id;
1102
- } catch (e) {
1103
- // Not in Products — either we create it below (-c given) or we fail loud.
1104
- }
1105
-
1106
- if (!communityId) {
1107
- if (!options.community) {
1108
- throw new Error(
1109
- `App '${appId}' does not exist yet. Pass -c <community> to create it: ` +
1110
- `descix app init -a ${appId} -c <community> [-s <short>]`
1111
- );
1112
- }
1113
- // CREATE leg — the canonical server path. It composes the unique app_id
1114
- // ({community}-{short}) and is authoritative; we never compose it client-side.
1115
- const response = await apiClient.invoke('create_app_for_community', {
1116
- community_id: options.community,
1117
- app_name: appId,
1118
- short_name: options.short || undefined,
1119
- create_skeleton: false,
1120
- overwrite: options.overwrite,
1121
- });
1122
- const created = response.message || response;
1123
- appId = created.app_id || appId;
1124
- communityId = created.community_id || options.community;
1125
- console.log(chalk.green(`\n✅ App created: ${appId}`));
1126
- console.log(chalk.gray(` Products: Products/${appId}`));
1127
- console.log(chalk.gray(` Firestore: Community/${communityId}/Apps/${appId}`));
1128
- } else if (options.community && options.community !== communityId) {
1129
- throw new Error(
1130
- `App '${appId}' already exists in community '${communityId}', not '${options.community}'. ` +
1131
- `Omit -c to initialize the existing app.`
1132
- );
1133
- }
1134
-
1135
- // 1. Workspace.json — register app if not already mapped
1136
- const alreadyMapped = workspaceConfig?.getAppByAppId(appId);
1137
- let appPath = alreadyMapped?.absolutePath;
1138
-
1139
- if (alreadyMapped && options.path) {
1140
- throw new Error(
1141
- `App '${appId}' is already mapped to '${alreadyMapped.localPath}'. ` +
1142
- `Use 'descix app set-localpath -a ${appId} -p <new-path>' to update.`
1143
- );
1144
- }
1145
-
1146
- if (!alreadyMapped) {
1147
- const localPath = options.path || '.';
1148
- const wsRoot = workspaceConfig?.workspaceRoot || process.cwd();
1149
- const cfg = workspaceConfig || new WorkspaceConfig({}, wsRoot);
1150
- cfg.registerApp(communityId, appId, { localPath, kbId });
1151
- await cfg.save(wsRoot);
1152
- appPath = path.resolve(wsRoot, localPath);
1153
- console.log(chalk.gray(` workspace.json updated: ${appId} → ${localPath}`));
1154
- }
1155
-
1156
- // 2. Create app folder structure (site, microservice, assets)
1157
- if (appPath) {
1158
- const siteDir = path.join(appPath, 'site');
1159
- const msDir = path.join(appPath, 'microservice');
1160
- const assetsDir = path.join(appPath, 'assets');
1161
- await fs.mkdir(siteDir, { recursive: true });
1162
- await fs.mkdir(msDir, { recursive: true });
1163
- await fs.mkdir(assetsDir, { recursive: true });
1164
-
1165
- // Create template asset files if they don't exist
1166
- const siPath = path.join(assetsDir, 'system_instructions.md');
1167
- const descPath = path.join(assetsDir, 'app_description.md');
1168
- try {
1169
- await fs.access(siPath);
1170
- } catch {
1171
- await fs.writeFile(siPath, `# System Instructions for ${appId}\n\nYou are an AI assistant for the ${appId} application.\n`);
1172
- }
1173
- try {
1174
- await fs.access(descPath);
1175
- } catch {
1176
- await fs.writeFile(descPath, `# ${appId}\n\nApplication description goes here.\n`);
1177
- }
1178
- console.log(chalk.gray(` Created: site/, microservice/, assets/`));
1179
- }
1180
-
1181
- // 3. Create KnowledgeBase Firestore doc (Git Mode — no Drive required)
1182
- const kbResponse = await apiClient.invoke('init_git_mode_kb', { app_id: appId, kb_name: kbId });
1183
- const kbResult = kbResponse.message || kbResponse;
1184
-
1185
- console.log(chalk.green(`\n✓ ${appId} initialized`));
1186
- console.log(chalk.gray(` Community: ${communityId}`));
1187
-
1188
- // A community's OWN app (app_id == community_id) mirrors its token symbol and icon from the
1189
- // env-invariant descix-chain registry into this environment (CEO 2026-09-19). The app is
1190
- // already initialized; a refusal here (not an admin of the community, or the community not in
1191
- // the registry) is reported with the command that retries it, not treated as an init failure.
1192
- if (appId === communityId) {
1193
- try {
1194
- printIdentityReceipt(communityId, await refreshCommunityIdentity(apiClient, communityId));
1195
- } catch (err) {
1196
- console.log(chalk.yellow(`\n ⚠ Community identity not mirrored: ${err.message}`));
1197
- console.log(chalk.gray(` Retry with: descix community refresh-identity -c ${communityId}`));
1198
- }
1199
- }
1200
- console.log(chalk.gray(` KB: ${kbId} — ${kbResult.created ? 'created' : 'already exists'}\n`));
1201
- console.log(chalk.gray(` (every app is guaranteed a default KB at creation; an empty one`));
1202
- console.log(chalk.gray(` says so rather than answering from general knowledge)\n`));
1203
- console.log(chalk.cyan('Next steps:'));
1204
- // The manifest lives in THIS app's registered directory — never a guessed `apps/<id>/`,
1205
- // which named a path that does not exist for any app registered elsewhere.
1206
- const manifestPath = path.join(appPath, '.descix', 'manifests', `${kbId}.json`);
1207
- console.log(chalk.gray(` Create a corpus manifest at ${path.relative(process.cwd(), manifestPath) || manifestPath}`));
1208
- console.log(chalk.gray(` then run:`));
1209
- console.log(chalk.white(` descix kb corpus sync -a ${appId}\n`));
1086
+ await runAppInit(apiClient, options);
1210
1087
  } catch (error) {
1211
1088
  console.error(chalk.red(error.message));
1212
1089
  process.exit(1);
@@ -4581,10 +4458,10 @@ devCertsCommand
4581
4458
 
4582
4459
  program
4583
4460
  .command('quickstart')
4584
- .description('One-command setup: auth → workspace → agent files → MCP config')
4461
+ .description('One-command setup: sign in → workspace → app (with -c and -a) → agent files → MCP config')
4585
4462
  .option('-u, --url <url>', 'API URL override')
4586
- .option('-c, --community <id>', 'Community ID for the new workspace')
4587
- .option('-a, --app <name>', 'App name for the new workspace')
4463
+ .option('-c, --community <id>', 'Community to create the app in')
4464
+ .option('-a, --app <name>', 'Name of the app to create (the platform issues its id; see app init)')
4588
4465
  .option('-y, --yes', 'Skip the confirmation — with -c and -a, quickstart runs without a terminal')
4589
4466
  .action(async (options) => {
4590
4467
  // Every failure prints as a message and exits 1 — never a stack trace. A new developer's AI
@@ -4652,11 +4529,26 @@ program
4652
4529
  // same one-owner rule that fixed the check above.
4653
4530
  const targetRoot = existingRoot || workspaceRoot;
4654
4531
 
4655
- // Step 3: Generate agent instruction files
4656
- console.log(chalk.cyan('\n📋 Generating Agent Instructions\n'));
4657
- const written = await generateAgentFiles(targetRoot);
4658
- for (const f of written) {
4659
- console.log(chalk.green(` ✓ ${f}`));
4532
+ // Step 3: The app, and the agent instruction files that state its id. The id is the
4533
+ // platform's, so the files are written only once the workspace names one it issued: from the
4534
+ // workspace when an app is already registered, or by `app init` (the one owner, which writes
4535
+ // them itself) when -c and -a name the app to create.
4536
+ const { readIdentity, isIdentityNamed } = await import('../lib/workspace-identity.js');
4537
+ const wsRaw = JSON.parse(await fs.readFile(path.join(targetRoot, '.descix', 'workspace.json'), 'utf-8'));
4538
+ if (isIdentityNamed(readIdentity(wsRaw))) {
4539
+ console.log(chalk.cyan('\n📋 Generating Agent Instructions\n'));
4540
+ const written = await generateAgentFiles(targetRoot);
4541
+ for (const f of written) {
4542
+ console.log(chalk.green(` ✓ ${f}`));
4543
+ }
4544
+ } else if (options.community && options.app) {
4545
+ console.log(chalk.cyan('\n📋 Create and initialize the app\n'));
4546
+ const apiClient = new DeSciXApiClient();
4547
+ await requireAuth(apiClient);
4548
+ await runAppInit(apiClient, { app: options.app, community: options.community });
4549
+ } else {
4550
+ console.log(chalk.yellow('\n No app yet, so no agent instruction files (they state its id). Next:'));
4551
+ console.log(chalk.white(' descix app init -a <name> -c <community>'));
4660
4552
  }
4661
4553
 
4662
4554
  // Step 4: Generate .vscode/mcp.json (skipped if DeSciX extension handles MCP)
@@ -0,0 +1,154 @@
1
+ /**
2
+ * `descix app init` — THE path to an app (CEO-D-2026-08-14): creates the app when it does not exist
3
+ * yet, then registers and scaffolds it locally. `descix quickstart` runs the same function, so the
4
+ * two cannot disagree about what an initialized app is.
5
+ *
6
+ * THE APP ID IS THE SERVER'S. With -c, the -a value is a NAME and create_app_for_community composes
7
+ * the id ({community}-{short}); this module registers whatever id the server returns and never
8
+ * composes one. `descix init` used to record the NAME as the app id, so the workspace and CLAUDE.md
9
+ * named `myapp` while the platform held `daita-myapp` (devx review 2026-09-19, D2). The agent
10
+ * instruction files are therefore written HERE, after the id exists, and nowhere earlier.
11
+ */
12
+ import chalk from 'chalk';
13
+ import fs from 'fs/promises';
14
+ import path from 'path';
15
+ import { WorkspaceConfig, resolveWorkspacePath } from '../workspace-config.js';
16
+ import { refreshCommunityIdentity, printIdentityReceipt } from './communityIdentity.js';
17
+ import { generateAgentFiles } from '../agent-files.js';
18
+
19
+ /**
20
+ * @param {Object} apiClient an authenticated DeSciXApiClient
21
+ * @param {{app: string, community?: string, short?: string, overwrite?: boolean, kb?: string, path?: string}} options
22
+ * @returns {Promise<{appId: string, communityId: string, appPath: string, kbId: string}>}
23
+ */
24
+ export async function runAppInit(apiClient, options) {
25
+ let appId = options.app;
26
+ const kbId = options.kb || 'General';
27
+
28
+ // Refuse an unusable -p BEFORE anything is written — server-side included. The same resolver
29
+ // the workspace loader applies on every read decides it, so a value accepted here is one the
30
+ // next read accepts too. Refusing only at registration came AFTER a `-c` create, leaving a
31
+ // platform app with no local registration (measured 2026-09-18, daita-docs).
32
+ const workspaceConfig = await WorkspaceConfig.tryLoad();
33
+ if (options.path) {
34
+ resolveWorkspacePath(workspaceConfig?.workspaceRoot || process.cwd(), options.path, appId);
35
+ }
36
+
37
+ // Resolve community_id from the Products registry to learn whether the app exists yet.
38
+ let communityId;
39
+ try {
40
+ const productCtx = await apiClient.invoke('get_product_context', { app_id: appId });
41
+ communityId = (productCtx.message || productCtx).community_id;
42
+ } catch (e) {
43
+ // Not in Products — either we create it below (-c given) or we fail loud.
44
+ }
45
+
46
+ if (!communityId) {
47
+ if (!options.community) {
48
+ throw new Error(
49
+ `App '${appId}' does not exist yet. Pass -c <community> to create it: ` +
50
+ `descix app init -a ${appId} -c <community> [-s <short>]`
51
+ );
52
+ }
53
+ // CREATE leg — the canonical server path. It composes the unique app_id
54
+ // ({community}-{short}) and is authoritative; we never compose it client-side.
55
+ const response = await apiClient.invoke('create_app_for_community', {
56
+ community_id: options.community,
57
+ app_name: appId,
58
+ short_name: options.short || undefined,
59
+ create_skeleton: false,
60
+ overwrite: options.overwrite,
61
+ });
62
+ const created = response.message || response;
63
+ appId = created.app_id || appId;
64
+ communityId = created.community_id || options.community;
65
+ console.log(chalk.green(`\n✅ App created: ${appId}`));
66
+ if (appId !== options.app) {
67
+ console.log(chalk.gray(` The platform composed the id from the community and the name you gave.`));
68
+ console.log(chalk.gray(` Use -a ${appId} in every later command.`));
69
+ }
70
+ } else if (options.community && options.community !== communityId) {
71
+ throw new Error(
72
+ `App '${appId}' already exists in community '${communityId}', not '${options.community}'. ` +
73
+ `Omit -c to initialize the existing app.`
74
+ );
75
+ }
76
+
77
+ // 1. Workspace.json — register app if not already mapped
78
+ const alreadyMapped = workspaceConfig?.getAppByAppId(appId);
79
+ let appPath = alreadyMapped?.absolutePath;
80
+
81
+ if (alreadyMapped && options.path) {
82
+ throw new Error(
83
+ `App '${appId}' is already mapped to '${alreadyMapped.localPath}'. ` +
84
+ `Use 'descix app set-localpath -a ${appId} -p <new-path>' to update.`
85
+ );
86
+ }
87
+
88
+ const wsRoot = workspaceConfig?.workspaceRoot || process.cwd();
89
+ if (!alreadyMapped) {
90
+ const localPath = options.path || '.';
91
+ const cfg = workspaceConfig || new WorkspaceConfig({}, wsRoot);
92
+ cfg.registerApp(communityId, appId, { localPath, kbId });
93
+ await cfg.save(wsRoot);
94
+ appPath = path.resolve(wsRoot, localPath);
95
+ console.log(chalk.gray(` workspace.json updated: ${appId} → ${localPath}`));
96
+ }
97
+
98
+ // 2. Create app folder structure (site, microservice, assets)
99
+ const assetsDir = path.join(appPath, 'assets');
100
+ await fs.mkdir(path.join(appPath, 'site'), { recursive: true });
101
+ await fs.mkdir(path.join(appPath, 'microservice'), { recursive: true });
102
+ await fs.mkdir(assetsDir, { recursive: true });
103
+ const siPath = path.join(assetsDir, 'system_instructions.md');
104
+ const descPath = path.join(assetsDir, 'app_description.md');
105
+ try {
106
+ await fs.access(siPath);
107
+ } catch {
108
+ await fs.writeFile(siPath, `# System Instructions for ${appId}\n\nYou are an AI assistant for the ${appId} application.\n`);
109
+ }
110
+ try {
111
+ await fs.access(descPath);
112
+ } catch {
113
+ await fs.writeFile(descPath, `# ${appId}\n\nApplication description goes here.\n`);
114
+ }
115
+ console.log(chalk.gray(` Created: site/, microservice/, assets/`));
116
+
117
+ // 3. Create KnowledgeBase Firestore doc (Git Mode — no Drive required)
118
+ const kbResponse = await apiClient.invoke('init_git_mode_kb', { app_id: appId, kb_name: kbId });
119
+ const kbResult = kbResponse.message || kbResponse;
120
+
121
+ console.log(chalk.green(`\n✓ ${appId} initialized`));
122
+ console.log(chalk.gray(` Community: ${communityId}`));
123
+
124
+ // A community's OWN app (app_id == community_id) mirrors its token symbol and icon from the
125
+ // env-invariant descix-chain registry into this environment (CEO 2026-09-19). The app is
126
+ // already initialized; a refusal here (not an admin of the community, or the community not in
127
+ // the registry) is reported with the command that retries it, not treated as an init failure.
128
+ if (appId === communityId) {
129
+ try {
130
+ printIdentityReceipt(communityId, await refreshCommunityIdentity(apiClient, communityId));
131
+ } catch (err) {
132
+ console.log(chalk.yellow(`\n ⚠ Community identity not mirrored: ${err.message}`));
133
+ console.log(chalk.gray(` Retry with: descix community refresh-identity -c ${communityId}`));
134
+ }
135
+ }
136
+ console.log(chalk.gray(` KB: ${kbId} — ${kbResult.created ? 'created' : 'already exists'}\n`));
137
+ console.log(chalk.gray(` (every app is guaranteed a default KB at creation; an empty one`));
138
+ console.log(chalk.gray(` says so rather than answering from general knowledge)\n`));
139
+
140
+ // 4. Agent instruction files, now that the workspace names an id the platform issued. Files the
141
+ // developer has customised (no BOOTSTRAP marker) are left alone by generateAgentFiles.
142
+ const written = await generateAgentFiles(wsRoot);
143
+ for (const f of written) console.log(chalk.green(` ✓ ${f}`));
144
+
145
+ console.log(chalk.cyan('\nNext steps:'));
146
+ // The manifest lives in THIS app's registered directory — never a guessed `apps/<id>/`,
147
+ // which named a path that does not exist for any app registered elsewhere.
148
+ const manifestPath = path.join(appPath, '.descix', 'manifests', `${kbId}.json`);
149
+ console.log(chalk.gray(` Create a corpus manifest at ${path.relative(process.cwd(), manifestPath) || manifestPath}`));
150
+ console.log(chalk.gray(` then run:`));
151
+ console.log(chalk.white(` descix kb corpus sync -a ${appId}\n`));
152
+
153
+ return { appId, communityId, appPath, kbId };
154
+ }
@@ -11,7 +11,6 @@ import { fileURLToPath } from 'url';
11
11
  import { dirname, join } from 'path';
12
12
  // clone.js is imported dynamically inside the invite flow to avoid circular deps
13
13
  import { WorkspaceConfig } from '../workspace-config.js';
14
- import { generateAgentFiles } from '../agent-files.js';
15
14
  // The canonical KB-sync surface is owned by retired-kb-sync.js. Consume the constant: a literal
16
15
  // spelled here is a second derivation of the same fact, and the removed verb this replaced
17
16
  // reached a developer who had done everything right.
@@ -151,11 +150,10 @@ export async function runInit(apiClient, options = {}) {
151
150
  }
152
151
  }
153
152
 
154
- const appId = appName.toLowerCase().replace(/[^a-z0-9_-]/g, '_');
155
153
  console.log(chalk.cyan('\n─── Summary ───\n'));
156
154
  console.log(chalk.white(` Project: ${projectPath}`));
157
155
  console.log(chalk.white(` Community: ${communityId}`));
158
- console.log(chalk.white(` App: ${appName} (${appId})`));
156
+ console.log(chalk.white(` App name: ${appName}`));
159
157
 
160
158
  const proceed = options.yes ? true : await rl.askYesNo(chalk.white('\nProceed?'), true);
161
159
  if (!proceed) {
@@ -170,7 +168,11 @@ export async function runInit(apiClient, options = {}) {
170
168
  config.env.products = [];
171
169
  delete config.env.platform;
172
170
  }
173
- config.registerApp(communityId, appId, { localPath: '.', kbId: 'General' });
171
+ // NO APP IS REGISTERED HERE. The app id is the platform's: `app init` creates the app and
172
+ // registers the id the server returns (with -c it is composed from the community and the
173
+ // name). Recording the NAME here as the id left the workspace and CLAUDE.md naming an app the
174
+ // platform does not have (devx review 2026-09-19, D2). The agent instruction files state that
175
+ // id, so `app init` writes them too, once it exists.
174
176
  await config.save(projectPath);
175
177
  // A NEW workspace records the environment this run used (`descix --env dev init …`), through
176
178
  // the same owner `config init` uses — otherwise the workspace carried no environment and the
@@ -180,24 +182,16 @@ export async function runInit(apiClient, options = {}) {
180
182
  await config.setEnvironment(options.env);
181
183
  }
182
184
 
183
- console.log(chalk.green('Created:'));
185
+ console.log(chalk.green(`${existingConfig ? 'Updated' : 'Created'}:`));
184
186
  console.log(chalk.green(' ✓ .descix/workspace.json'));
185
187
 
186
- // Generate agent instruction files with correct context
187
- try {
188
- const agentFilesWritten = await generateAgentFiles(projectPath);
189
- for (const f of agentFilesWritten) {
190
- console.log(chalk.green(` ✓ ${f}`));
191
- }
192
- } catch {
193
- // Agent file generation is best-effort
194
- }
195
-
196
188
  console.log(chalk.cyan('\n─── Next Steps ───\n'));
197
- console.log(chalk.white(` 1. descix app init -a ${appId} -c ${communityId} # register app on platform`));
198
- console.log(chalk.gray(` 2. Create a corpus manifest at .descix/manifests/General.json`));
199
- console.log(chalk.white(` 3. ${CANONICAL_KB_SYNC} -a ${appId} # sync KB to Pinecone`));
200
- console.log(chalk.white(` 4. descix chat -c ${communityId} -a ${appId} -q "test" # verify RAG\n`));
189
+ console.log(chalk.white(` 1. descix login # if you are not signed in`));
190
+ console.log(chalk.white(` 2. descix app init -a ${appName} -c ${communityId}`));
191
+ console.log(chalk.gray(` Creates the app and registers the id the platform issues for it (with -c the`));
192
+ console.log(chalk.gray(` id is ${communityId}-<name>), then writes CLAUDE.md and the other agent files.`));
193
+ console.log(chalk.gray(` 3. Create the corpus manifest app init names, then:`));
194
+ console.log(chalk.white(` ${CANONICAL_KB_SYNC} -a <the id app init printed>\n`));
201
195
  console.log(chalk.green('✅ Workspace initialized.\n'));
202
196
  rl.close();
203
197
  return { created: ['.descix/workspace.json'], skipped: [], warnings: [] };
@@ -208,38 +202,4 @@ export async function runInit(apiClient, options = {}) {
208
202
  }
209
203
  }
210
204
 
211
- /**
212
- * Non-interactive init: writes .descix/workspace.json only.
213
- * @param {Object} options - { path?, communityId, appName? }
214
- * @returns {Promise<Object>} { created, skipped, warnings }
215
- */
216
- export async function initWorkspace(options) {
217
- const projectPath = options.path ? path.resolve(options.path) : process.cwd();
218
- const communityId = options.communityId;
219
- const appName = options.appName || path.basename(projectPath).toLowerCase().replace(/[^a-z0-9]/g, '_');
220
- const appId = appName.toLowerCase().replace(/[^a-z0-9_-]/g, '_');
221
- if (!communityId) {
222
- throw new Error('communityId is required');
223
- }
224
- const config = new WorkspaceConfig({ version: '2.0', type: 'workspace', communities: {} }, projectPath);
225
- config.registerApp(communityId, appId, { localPath: '.', kbId: 'General' });
226
- await config.save(projectPath);
227
-
228
- // Generate agent instruction files with workspace context
229
- const created = ['.descix/workspace.json'];
230
- try {
231
- const agentFilesWritten = await generateAgentFiles(projectPath);
232
- created.push(...agentFilesWritten);
233
- } catch {
234
- // Best-effort
235
- }
236
-
237
- return {
238
- created,
239
- skipped: [],
240
- warnings: [],
241
- nextSteps: [`descix app init -a ${appId} -c ${communityId}`, `${CANONICAL_KB_SYNC} -a ${appId}`]
242
- };
243
- }
244
-
245
- export default { runInit, initWorkspace };
205
+ export default { runInit };
@@ -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.17",
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?"
@@ -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)?"
@@ -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)?"
@@ -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)?"