@descix/cli 1.0.0 → 1.0.3

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 (103) hide show
  1. package/LICENSE.md +671 -0
  2. package/README.md +43 -4
  3. package/agent-assets/guides/README.md +2 -2
  4. package/agent-assets/guides/dynamic-site-pattern.md +29 -14
  5. package/agent-assets/guides/knowledge-only-pattern.md +5 -5
  6. package/agent-assets/guides/microservice-pattern.md +48 -4
  7. package/agent-assets/guides/static-site-pattern.md +8 -0
  8. package/agent-assets/instructions/app-asset-validation.md +5 -5
  9. package/agent-assets/instructions/onboarding-flow.md +4 -4
  10. package/agent-assets/instructions/standard-folder-structure.md +20 -11
  11. package/agent-assets/reference/app-creation.md +42 -20
  12. package/agent-assets/reference/architecture.md +24 -22
  13. package/agent-assets/reference/local-dev.md +230 -67
  14. package/agent-assets/reference/mcp-integration.md +9 -9
  15. package/agent-assets/reference/platform-api-consumer.md +244 -0
  16. package/agent-assets/reference/workspace-config.md +7 -7
  17. package/agent-assets/rules/descix_mcp.template.mdc +8 -8
  18. package/bin/descix.js +2559 -1435
  19. package/bin/kb-deny-lint.mjs +91 -0
  20. package/bin/mcp-server.js +175 -91
  21. package/lib/agent-files.js +37 -25
  22. package/lib/api-client.js +223 -56
  23. package/lib/auth-guard.js +13 -3
  24. package/lib/chat-session.js +187 -0
  25. package/lib/cli-version.js +59 -0
  26. package/lib/commands/airdrop.js +251 -0
  27. package/lib/commands/auth.js +254 -72
  28. package/lib/commands/briefer/errors.js +88 -0
  29. package/lib/commands/briefer/index.js +319 -0
  30. package/lib/commands/briefer/sources/canonical-sources.js +129 -0
  31. package/lib/commands/briefer/sources/entitlements.js +209 -0
  32. package/lib/commands/briefer/sources/environments.js +205 -0
  33. package/lib/commands/briefer/sources/identifiers.js +214 -0
  34. package/lib/commands/briefer/sources/microservice-deploy.js +267 -0
  35. package/lib/commands/briefer/sources/routing.js +275 -0
  36. package/lib/commands/briefer/sources/what-is-not.js +223 -0
  37. package/lib/commands/briefer/stitcher.js +134 -0
  38. package/lib/commands/briefer/util/source-reader.js +502 -0
  39. package/lib/commands/config.js +210 -90
  40. package/lib/commands/corpus.js +978 -0
  41. package/lib/commands/credits.js +122 -0
  42. package/lib/commands/health.js +627 -0
  43. package/lib/commands/kb-list-render.js +32 -0
  44. package/lib/commands/kb.js +190 -413
  45. package/lib/commands/mcp.js +5 -5
  46. package/lib/commands/microservice-restart.js +359 -0
  47. package/lib/commands/model-config.js +313 -0
  48. package/lib/commands/retired-kb-sync.js +134 -0
  49. package/lib/commands/serve.js +26 -1
  50. package/lib/commands/status.js +23 -51
  51. package/lib/commands/update.js +36 -107
  52. package/lib/core/Chunker.js +491 -17
  53. package/lib/core/CorpusDenyLint.js +326 -0
  54. package/lib/core/CorpusWalker.js +357 -0
  55. package/lib/core/Hydrator.js +75 -29
  56. package/lib/core/ManifestLoader.js +533 -0
  57. package/lib/core/SiteWalker.js +218 -0
  58. package/lib/core/Syncer.js +163 -11
  59. package/lib/diagnostic-log.js +41 -0
  60. package/lib/environment-report.js +100 -0
  61. package/lib/global-config.js +4 -1
  62. package/lib/oauth-client.js +164 -0
  63. package/lib/origin.js +143 -0
  64. package/lib/service-api-client.js +95 -0
  65. package/lib/wallet-environment.js +49 -0
  66. package/lib/wallet-file.js +16 -2
  67. package/lib/wizard/setup.js +10 -9
  68. package/lib/workspace-config.js +380 -235
  69. package/lib/workspace-identity.js +92 -0
  70. package/lib/workspace-utils.js +41 -61
  71. package/package.json +29 -9
  72. package/templates/agent-claude.md +157 -9
  73. package/templates/agent-cline.md +68 -8
  74. package/templates/agent-copilot.md +68 -8
  75. package/templates/agent-cursor.md +68 -8
  76. package/templates/alignment-schema.json +20 -0
  77. package/templates/cloud-brain-hook.sh +20 -0
  78. package/templates/drive/README.md +1 -1
  79. package/templates/drive_templates/README.md +2 -2
  80. package/templates/scaffolds/README.md +6 -10
  81. package/templates/scaffolds/microservice/SERVICE_README_sdk.md +30 -0
  82. package/templates/scaffolds/microservice/app.js +51 -10
  83. package/templates/scaffolds/microservice/app.yaml +2 -2
  84. package/templates/scaffolds/microservice/defaults-config-dev.json +4 -0
  85. package/templates/scaffolds/microservice/dev-overrides.example.json +5 -0
  86. package/templates/scaffolds/microservice/manifest.json +0 -1
  87. package/templates/scaffolds/microservice/package.json +3 -3
  88. package/templates/scaffolds/microservice/scripts/register.js +56 -41
  89. package/templates/scaffolds/microservice/services/mcpClient.js +55 -65
  90. package/templates/scaffolds/microservice/services/utils.js +20 -238
  91. package/templates/scaffolds/microservice/templates/SERVICE_README_TEMPLATE.md +24 -0
  92. package/SERVICE_README_sdk.md +0 -399
  93. package/descix-cli-1.0.0.tgz +0 -0
  94. package/lib/commands/app-wizard.js +0 -627
  95. package/lib/commands/folder.js +0 -291
  96. package/lib/core/PathContext.js +0 -335
  97. package/templates/scaffolds/microservice/dev-overrides.json.example +0 -5
  98. package/templates/scaffolds/site/DeSciXAppSDK.js +0 -62
  99. package/templates/scaffolds/site/README.md +0 -51
  100. package/templates/scaffolds/site/app.js +0 -22
  101. package/templates/scaffolds/site/index.html +0 -42
  102. package/templates/scaffolds/site/styles.css +0 -123
  103. package/test-hydration.js +0 -150
@@ -24,7 +24,7 @@ import crypto from 'crypto';
24
24
  import { DeSciXApiClient } from '../api-client.js';
25
25
  import { requireAuth } from '../auth-guard.js';
26
26
  import { WorkspaceConfig } from '../workspace-config.js';
27
- import { runKbChunk, runKbSync } from './kb.js';
27
+ import { refuseRetiredKbSync } from './retired-kb-sync.js';
28
28
 
29
29
  /**
30
30
  * Helper to load workspace context with options override
@@ -36,26 +36,13 @@ async function loadWorkspaceContext(options = {}) {
36
36
  const workspaceConfig = await WorkspaceConfig.load();
37
37
  const ctx = workspaceConfig.requireContext(options);
38
38
 
39
- // Prefer getAppByAppId (env.platform/products, Unified Registry)
40
- let appConfig = workspaceConfig.getAppByAppId(ctx.appId);
41
- if (!appConfig && ctx.communityId) {
42
- appConfig = workspaceConfig.getApp(ctx.communityId, ctx.appId);
43
- if (appConfig) {
44
- appConfig = {
45
- localPath: appConfig.localPath,
46
- absolutePath: appConfig.absolutePath || (workspaceConfig.workspaceRoot && appConfig.localPath
47
- ? path.join(workspaceConfig.workspaceRoot, appConfig.localPath)
48
- : null),
49
- communityId: ctx.communityId,
50
- kbId: appConfig.kbId || 'General'
51
- };
52
- }
53
- }
39
+ // Unified Registry: getAppByAppId only — v1 community-keyed fallback removed
40
+ const appConfig = workspaceConfig.getAppByAppId(ctx.appId);
54
41
 
55
42
  if (!appConfig) {
56
43
  throw new Error(
57
44
  `App "${ctx.appId}" not found in workspace.json.\n` +
58
- 'Run "npx descix init" or ensure env.platform/env.products maps app_id to localPath.'
45
+ 'Use `descix app init` to register, or `descix app set-localpath -a <id> -p <path>` to repoint.'
59
46
  );
60
47
  }
61
48
 
@@ -183,11 +170,17 @@ export async function updateAuto(options = {}) {
183
170
  case 'app':
184
171
  return await updateApp(options);
185
172
  case 'kb':
186
- return await updateKB(options);
173
+ // kb sync has exactly ONE surface. Auto-detect lands here whenever the user is
174
+ // standing in the app's kb/ directory, so this path is REACHED in normal use —
175
+ // it is the single most likely way someone still tries to sync a KB via `update`.
176
+ // Refuses through the one owner so this branch and the explicit `update kb`
177
+ // branch cannot drift apart.
178
+ spinner.stop();
179
+ return refuseRetiredKbSync('descix update kb', chalk.red);
187
180
  case 'site':
188
181
  return await updateSite(options);
189
182
  case 'microservice':
190
- console.log(chalk.yellow(' Microservice deployment not supported via update. Use \'descix deploy\'.\n'));
183
+ console.log(chalk.yellow(' Microservice deployment not supported via update. Use \'descix microservice deploy\'.\n'));
191
184
  return { success: false, reason: 'use_deploy' };
192
185
  default:
193
186
  console.log(chalk.yellow(` Unknown sync type: ${syncType}. Use 'descix update app/kb/site' explicitly.\n`));
@@ -278,12 +271,17 @@ export async function updateApp(options = {}) {
278
271
  let baseFolderId = ctx.workspaceConfig.driveConfig?.base_folder_id;
279
272
 
280
273
  if (!baseFolderId) {
281
- const userInfo = await apiClient.invoke('get_my_profile', {});
282
- baseFolderId = userInfo.message?.base_folder_id;
274
+ // `get_my_profile` was a call to a verb NOTHING SERVES: it is absent from Cloud's command
275
+ // registry and had zero references anywhere in DeSciX_Cloud, DeSciX_Core or DeSciX_Powch
276
+ // outside this one call site (measured 2026-08-29). `get_folder_info` is the served,
277
+ // AUTHENTICATED verb that owns this fact — registry.js maps it to appCommands.js, and for
278
+ // entity_type 'user' it returns the caller's own base_folder_id as `folder_id`.
279
+ const folderInfo = await apiClient.invoke('get_folder_info', { entity_type: 'user' });
280
+ baseFolderId = folderInfo.message?.folder_id;
283
281
  }
284
282
 
285
283
  if (!baseFolderId) {
286
- throw new Error('No base Drive folder configured. Run descix login --setup first.');
284
+ throw new Error('No base Drive folder configured: set driveConfig.base_folder_id in .descix/workspace.json.');
287
285
  }
288
286
 
289
287
  // Navigate to assets folder: {base}/{community}/{app}/assets
@@ -359,61 +357,8 @@ export async function updateApp(options = {}) {
359
357
  }
360
358
  }
361
359
 
362
- /**
363
- * Update knowledge base (Git Mode: local chunk → kb_sync_chunks → Pinecone)
364
- *
365
- * Drive Mode (Drive → GCS → Pinecone) is server-side only for PWA users.
366
- * CLI mandates Git Mode: local files are chunked locally and upserted directly.
367
- *
368
- * Convention: KB files are in {appPath}/kb/{kbId}/
369
- */
370
- export async function updateKB(options = {}) {
371
- const apiClient = new DeSciXApiClient();
372
- await requireAuth(apiClient);
373
-
374
- const spinner = ora('Loading context...').start();
375
-
376
- try {
377
- const ctx = await loadWorkspaceContext(options);
378
- const kbId = ctx.kbId;
379
-
380
- spinner.succeed(`KB: ${ctx.appId}/${kbId}`);
381
-
382
- // Resolve community_id from Products when missing (Unified Registry - app_id only)
383
- if (!ctx.communityId) {
384
- try {
385
- const productCtx = await apiClient.invoke('get_product_context', { app_id: ctx.appId });
386
- ctx.communityId = productCtx?.community_id || productCtx?.message?.community_id;
387
- if (!ctx.communityId) {
388
- throw new Error(`Product "${ctx.appId}" not found in Products registry. Run bootstrap.`);
389
- }
390
- } catch (err) {
391
- if (err.message?.includes('not found')) throw err;
392
- throw new Error(`Could not resolve community for app "${ctx.appId}". Run bootstrap.`);
393
- }
394
- }
395
-
396
- console.log(chalk.cyan('\n📤 Updating Knowledge Base\n'));
397
- console.log(chalk.gray(` Community: ${ctx.communityId}`));
398
- console.log(chalk.gray(` App: ${ctx.appId}`));
399
- console.log(chalk.gray(` KB: ${kbId}`));
400
- console.log(chalk.gray(` Source: ${path.join(ctx.appPath, 'kb', kbId)}\n`));
401
-
402
- // Git Mode: chunk local files → kb_sync_chunks → Pinecone
403
- // (Drive → GCS → Pinecone is server-side only for PWA users)
404
- const kbOptions = { ...options, app: ctx.appId, community: ctx.communityId, kb: kbId, quiet: true };
405
- await runKbChunk(kbOptions);
406
- await runKbSync(apiClient, kbOptions);
407
-
408
- console.log(chalk.green('\n✓ Knowledge base updated successfully\n'));
409
- return { success: true };
410
-
411
- } catch (error) {
412
- spinner.fail('Update failed');
413
- console.error(chalk.red(`\n❌ ${error.message}\n`));
414
- throw error;
415
- }
416
- }
360
+ // updateKB is DELETED. `update kb` refuses and names `descix kb corpus sync`; `update all`
361
+ // and `update auto` no longer touch the KB. No exported symbol survives without a caller.
417
362
 
418
363
  /**
419
364
  * Update site (deploy to GCS)
@@ -431,25 +376,12 @@ export async function updateSite(options = {}) {
431
376
  // Convention: site folder path
432
377
  const siteDir = path.join(ctx.appPath, 'site');
433
378
 
434
- // Handle local port registration
379
+ // Handle local port registration — setSitePort mutates the live env entry and saves
435
380
  if (options.port) {
436
381
  spinner.text = `Registering local port: ${options.port}`;
437
382
  try {
438
- const appConfig = ctx.workspaceConfig.getApp(ctx.communityId, ctx.appId);
439
-
440
- if (appConfig) {
441
- if (!appConfig.site) appConfig.site = {};
442
- appConfig.site.port = options.port;
443
- // Also set devCommand if not present (default guess)
444
- if (!appConfig.site.devCommand) {
445
- appConfig.site.devCommand = 'npm run dev';
446
- }
447
-
448
- await ctx.workspaceConfig.save();
449
- console.log(chalk.green(`\n✅ Local port ${options.port} registered in workspace.json`));
450
- } else {
451
- console.log(chalk.yellow(`\n⚠️ App not found in workspace.json. Run 'descix init' first.`));
452
- }
383
+ await ctx.workspaceConfig.setSitePort(ctx.appId, options.port);
384
+ console.log(chalk.green(`\n✅ Local port ${options.port} registered in workspace.json`));
453
385
  } catch (err) {
454
386
  console.log(chalk.yellow(`\n⚠️ Could not register port: ${err.message}`));
455
387
  }
@@ -512,7 +444,7 @@ export async function updateSite(options = {}) {
512
444
  preview: options.preview || false
513
445
  });
514
446
 
515
- const { signed_urls, existing_manifest, token_id, site_url } = tokenResponse.message;
447
+ const { signed_urls, upload_headers, existing_manifest, token_id, site_url } = tokenResponse.message;
516
448
 
517
449
  // Determine delta
518
450
  let filesToUpload = fileList;
@@ -543,10 +475,15 @@ export async function updateSite(options = {}) {
543
475
  if (!signedUrl) continue;
544
476
 
545
477
  const content = await fs.readFile(path.join(siteDir, file.path));
546
-
478
+
479
+ // Canonical contract (WS-DEPLOY-HARDENING item 4): the server binds Cache-Control into
480
+ // the v4 signed URL signature (generateSiteUploadUrls/siteAssetCacheControl). Ferry the
481
+ // exact header bag the server minted — never re-derive the policy client-side, and never
482
+ // send a header the signature doesn't expect (GCS returns 403 signature-mismatch).
483
+ const headers = (upload_headers && upload_headers[file.path]) || { 'Content-Type': file.content_type };
547
484
  const response = await fetch(signedUrl, {
548
485
  method: 'PUT',
549
- headers: { 'Content-Type': file.content_type },
486
+ headers,
550
487
  body: content
551
488
  });
552
489
 
@@ -613,16 +550,9 @@ export async function updateAll(options = {}) {
613
550
  // assets folder doesn't exist, skip
614
551
  }
615
552
 
616
- // Check for KB folder and update if exists
617
- const kbDir = path.join(ctx.appPath, 'kb');
618
- try {
619
- await fs.access(kbDir);
620
- console.log(chalk.white('\n─── Knowledge Base ───\n'));
621
- results.kb = await updateKB(options);
622
- } catch {
623
- // kb folder doesn't exist, skip
624
- }
625
-
553
+ // Knowledge bases are NOT part of `update all`. The one KB sync surface is
554
+ // `descix kb corpus sync` (git-manifest); this composite keeps doing app and site.
555
+
626
556
  // Check for site folder and update if exists
627
557
  const siteDir = path.join(ctx.appPath, 'site');
628
558
  try {
@@ -647,7 +577,6 @@ export async function updateAll(options = {}) {
647
577
  export default {
648
578
  updateAuto,
649
579
  updateApp,
650
- updateKB,
651
580
  updateSite,
652
581
  updateAll
653
582
  };