deepspace 0.27.0 → 0.28.0

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 (53) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +19 -8
  3. package/dist/{chunk-SF6GNPYL.js → chunk-652TIGI4.js} +2 -2
  4. package/dist/{chunk-SF6GNPYL.js.map → chunk-652TIGI4.js.map} +1 -1
  5. package/dist/cli.js +1819 -1068
  6. package/dist/cli.js.map +1 -1
  7. package/dist/documentation-client-core.js +1 -1
  8. package/dist/documentation-default-renderer.cjs +1 -1
  9. package/dist/documentation-react.js +1 -1
  10. package/dist/documentation-runtime.js +1 -1
  11. package/dist/documentation-server-core.js +1 -1
  12. package/dist/documentation.d.ts +0 -1
  13. package/dist/documentation.js +41 -21
  14. package/dist/documentation.js.map +1 -1
  15. package/dist/feature-installer.js +27 -61
  16. package/dist/feature-installer.js.map +1 -1
  17. package/dist/index.d.ts +6 -55
  18. package/dist/index.js +4 -20
  19. package/dist/index.js.map +1 -1
  20. package/dist/schema.js.map +1 -1
  21. package/dist/server.d.ts +8 -39
  22. package/dist/server.js +16 -64
  23. package/dist/server.js.map +1 -1
  24. package/dist/testing.js +2 -2
  25. package/dist/testing.js.map +1 -1
  26. package/dist/worker.d.ts +7 -80
  27. package/dist/worker.js +17 -69
  28. package/dist/worker.js.map +1 -1
  29. package/features/admin-page/feature.json +0 -1
  30. package/features/ai-chat/feature.json +0 -1
  31. package/features/canvas/feature.json +0 -1
  32. package/features/cron/feature.json +0 -1
  33. package/features/documents/feature.json +0 -1
  34. package/features/file-attachments/feature.json +0 -1
  35. package/features/file-manager/feature.json +0 -1
  36. package/features/integration-test/feature.json +0 -1
  37. package/features/items/feature.json +0 -1
  38. package/features/kanban/feature.json +0 -1
  39. package/features/landing/feature.json +0 -1
  40. package/features/leaderboard/feature.json +0 -1
  41. package/features/messaging/feature.json +0 -1
  42. package/features/search-bar/feature.json +0 -1
  43. package/features/tasks/feature.json +0 -1
  44. package/features/testing/feature.json +0 -1
  45. package/features/topbar/feature.json +1 -4
  46. package/features/tree/feature.json +1 -4
  47. package/package.json +1 -1
  48. package/dist/chunk-Q5YJGF5Z.js +0 -769
  49. package/dist/chunk-Q5YJGF5Z.js.map +0 -1
  50. package/dist/repo-api-7GDPVSFV.js +0 -14
  51. package/dist/repo-api-7GDPVSFV.js.map +0 -1
  52. package/features/presence-test/feature.json +0 -22
  53. package/features/presence-test/src/PresenceTestPage.tsx +0 -120
@@ -18,6 +18,30 @@ import { tmpdir } from "os";
18
18
  import { dirname, isAbsolute, join as join2, resolve } from "path";
19
19
  import { fileURLToPath } from "url";
20
20
 
21
+ // src/cli/lib/command-suggestions.ts
22
+ function editDistance(a, b) {
23
+ const left = a.toLowerCase();
24
+ const right = b.toLowerCase();
25
+ const dp = Array.from({ length: left.length + 1 }, (_, i) => [
26
+ i,
27
+ ...new Array(right.length).fill(0)
28
+ ]);
29
+ for (let j = 1; j <= right.length; j++) dp[0][j] = j;
30
+ for (let i = 1; i <= left.length; i++) {
31
+ for (let j = 1; j <= right.length; j++) {
32
+ dp[i][j] = Math.min(
33
+ dp[i - 1][j] + 1,
34
+ dp[i][j - 1] + 1,
35
+ dp[i - 1][j - 1] + (left[i - 1] === right[j - 1] ? 0 : 1)
36
+ );
37
+ if (i > 1 && j > 1 && left[i - 1] === right[j - 2] && left[i - 2] === right[j - 1]) {
38
+ dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + 1);
39
+ }
40
+ }
41
+ }
42
+ return dp[left.length][right.length];
43
+ }
44
+
21
45
  // src/cli/lib/package-manager.ts
22
46
  import { existsSync, readFileSync } from "fs";
23
47
  import { join } from "path";
@@ -81,19 +105,6 @@ function featureCatalog(packageRoot = featurePackageRoot()) {
81
105
  description: config.description ?? null
82
106
  }));
83
107
  }
84
- function editDistance(a, b) {
85
- const row = Array.from({ length: b.length + 1 }, (_, index) => index);
86
- for (let i = 1; i <= a.length; i++) {
87
- let previous = row[0];
88
- row[0] = i;
89
- for (let j = 1; j <= b.length; j++) {
90
- const current = row[j];
91
- row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
92
- previous = current;
93
- }
94
- }
95
- return row[b.length];
96
- }
97
108
  function suggestFeature(featureId, packageRoot = featurePackageRoot()) {
98
109
  let closest = null;
99
110
  let closestDistance = Number.POSITIVE_INFINITY;
@@ -147,7 +158,7 @@ function installFiles(packageRoot, config, targetDir, emit) {
147
158
  if (!existed) missing.push(resolvedDest);
148
159
  continue;
149
160
  }
150
- if (existed && !file.overwrite) {
161
+ if (existed) {
151
162
  emit(` Exists (skipped): ${resolvedDest}`);
152
163
  skipped++;
153
164
  continue;
@@ -156,8 +167,8 @@ function installFiles(packageRoot, config, targetDir, emit) {
156
167
  const shiftLevels = resolvedDest.split("/").length - file.dest.split("/").length;
157
168
  if (wasRedirected) copyFileWithImportShift(srcPath, destPath, shiftLevels);
158
169
  else copyFile(srcPath, destPath);
159
- emit(` ${existed ? "Overwrote" : "Copied"}: ${resolvedDest}`);
160
- if (!existed) created.push(resolvedDest);
170
+ emit(` Copied: ${resolvedDest}`);
171
+ created.push(resolvedDest);
161
172
  copied++;
162
173
  }
163
174
  return { copied, skipped, files: { created, preexisting, missing } };
@@ -427,50 +438,6 @@ function rateLimitBindingBlock(scope, binding) {
427
438
  `simple = { limit = ${binding.limit}, period = ${binding.period} }`
428
439
  ].join("\n");
429
440
  }
430
- function integrateCss(packageRoot, config, targetDir, emit) {
431
- if (!config.css?.length) return [];
432
- const stylesPath = join2(targetDir, "src", "styles.css");
433
- if (!existsSync2(stylesPath)) {
434
- emit(" Warning: Cannot integrate CSS \u2014 src/styles.css not found");
435
- return [
436
- {
437
- area: "css",
438
- reason: "src/styles.css was not found.",
439
- steps: config.css.map(
440
- (cssFile) => `Append node_modules/deepspace/features/${config.id}/${cssFile} to src/styles.css.`
441
- )
442
- }
443
- ];
444
- }
445
- let styles = readFileSync2(stylesPath, "utf-8");
446
- let integrated = 0;
447
- const unresolved = [];
448
- for (const cssFile of config.css) {
449
- const srcPath = join2(packageRoot, "features", config.id, cssFile);
450
- if (!existsSync2(srcPath)) {
451
- emit(` Warning: CSS source not found: ${cssFile}`, "stderr");
452
- unresolved.push({
453
- area: "css",
454
- reason: `Feature CSS source '${cssFile}' was not found in the installed package.`,
455
- steps: ["Reinstall the current deepspace package, then retry this feature installation."]
456
- });
457
- continue;
458
- }
459
- const css = readFileSync2(srcPath, "utf-8");
460
- const fingerprint = css.match(/\.([\w-]+)\s*\{|@keyframes\s+([\w-]+)/);
461
- const marker = fingerprint?.[1] ?? fingerprint?.[2];
462
- if (marker && styles.includes(marker)) {
463
- emit(` CSS already present: ${cssFile} (found .${marker})`);
464
- continue;
465
- }
466
- styles += `
467
- ${css}`;
468
- integrated++;
469
- emit(` CSS integrated: ${cssFile} -> styles.css`);
470
- }
471
- if (integrated > 0) writeFileSync(stylesPath, styles);
472
- return unresolved;
473
- }
474
441
  function unresolvedRoute(route, config, reason, emit) {
475
442
  const roles = routeRolesSuffix(route);
476
443
  emit("");
@@ -695,7 +662,6 @@ function installFeature(options) {
695
662
  ...integrateActions(config, targetDir, emit),
696
663
  ...integrateWrangler(config, targetDir, emit),
697
664
  ...integrateCode(config, targetDir, emit),
698
- ...integrateCss(packageRoot, config, targetDir, emit),
699
665
  ...integrateRoute(config, targetDir, emit)
700
666
  ];
701
667
  const dependencyResult = integrateDependencies(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/commands/feature-installer.ts","../src/cli/lib/package-manager.ts"],"sourcesContent":["/**\n * The feature catalog and installer.\n *\n * This is a separate build entry because `add` loads the copy shipped by the\n * target app's installed `deepspace` package. That keeps feature files,\n * manifest interpretation, and mutations on the app-pinned SDK version while\n * leaving the public command/output contract in add.ts.\n */\n\nimport {\n closeSync,\n copyFileSync,\n existsSync,\n fstatSync,\n mkdirSync,\n mkdtempSync,\n openSync,\n readFileSync,\n readSync,\n readdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { spawnSync } from 'node:child_process'\nimport { tmpdir } from 'node:os'\nimport { dirname, isAbsolute, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { detectPackageManager } from '../lib/package-manager'\n\nconst NAV_MARKER = '// ── Features add nav items below this line ──'\n\ninterface FeatureFile {\n src: string\n dest: string\n overwrite?: boolean\n}\n\ninterface FeatureSchema {\n exportName: string\n importPath: string\n spreadOperator?: boolean\n}\n\ninterface FeatureAction {\n exportName: string\n registerAs: string\n importPath: string\n}\n\ninterface FeatureCodeInsertion {\n file: string\n marker: string\n insert: string\n placement?: 'before' | 'after'\n import?: string\n}\n\ninterface FeatureWranglerIntegration {\n runWorkerFirst?: boolean\n rateLimits?: Array<{\n name: string\n namespaceId: string\n limit: number\n period: 10 | 60\n }>\n}\n\nexport interface FeatureConfig {\n id: string\n name: string\n category?: string\n description?: string\n details?: string\n internal?: boolean\n files: FeatureFile[]\n ignore?: string[]\n route?: {\n path?: string\n protected?: boolean\n roles?: Array<'viewer' | 'member' | 'admin'>\n }\n schema?: FeatureSchema\n actions?: FeatureAction[]\n code?: FeatureCodeInsertion[]\n wrangler?: FeatureWranglerIntegration\n css?: string[]\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n instructions?: string[]\n patterns?: string[]\n agentNotes?: string[]\n example?: string\n [key: string]: unknown\n}\n\nexport interface FeatureCatalogEntry {\n id: string\n name: string\n category: string | null\n description: string | null\n}\n\ntype DependencySection = 'dependencies' | 'devDependencies'\n\ninterface DependencyAddition {\n name: string\n section: DependencySection\n version: unknown\n}\n\ntype IntegrationArea = 'schema' | 'actions' | 'code' | 'css' | 'nav' | 'wrangler'\n\ninterface UnresolvedIntegration {\n area: IntegrationArea\n reason: string\n steps: string[]\n}\n\ninterface InstallData extends Record<string, unknown> {\n feature: string\n dir: string\n installed: boolean\n observedChanges: {\n files: { created: string[]; preexisting: string[]; missing: string[] }\n dependencies: {\n added: DependencyAddition[]\n missingDeclarations: string[]\n installRequested: boolean\n diagnosticTail?: string\n }\n }\n unresolvedIntegrations: UnresolvedIntegration[]\n manifestGuidance: {\n instructions: string[]\n patterns: string[]\n agentNotes: string[]\n }\n}\n\ninterface InstallerAction {\n cwd: string\n argv: string[]\n}\n\nexport type FeatureInstallOutcome =\n | { ok: true; data: InstallData; action?: InstallerAction }\n | {\n ok: false\n code: 'unknown_feature'\n error: string\n data: {\n requestedFeature: string\n suggestedFeature: string | null\n availableFeatures: FeatureCatalogEntry[]\n }\n }\n | {\n ok: false\n code: 'dependency_install_failed' | 'manual_integration_required'\n error: string\n data: InstallData\n }\n\nexport type FeatureInstallerOutput = (line: string, stream?: 'stdout' | 'stderr') => void\n\nexport interface FeatureInstallOptions {\n feature: string\n targetDir: string\n installDependencies: boolean\n emit?: FeatureInstallerOutput\n}\n\n/** Find the package containing this source file or emitted build entry. */\nexport function featurePackageRoot(moduleUrl: string = import.meta.url): string {\n let dir = dirname(fileURLToPath(moduleUrl))\n for (;;) {\n const packagePath = join(dir, 'package.json')\n if (existsSync(packagePath)) {\n try {\n const pkg = JSON.parse(readFileSync(packagePath, 'utf-8')) as { name?: unknown }\n if (pkg.name === 'deepspace') return dir\n } catch {\n // Keep walking: a nearer unrelated package.json is not this package.\n }\n }\n const parent = dirname(dir)\n if (parent === dir) throw new Error('Could not locate the deepspace package root')\n dir = parent\n }\n}\n\nexport function hasFeatureCatalog(packageRoot: string = featurePackageRoot()): boolean {\n return existsSync(join(packageRoot, 'features'))\n}\n\nexport function readFeatureConfig(\n id: string,\n packageRoot: string = featurePackageRoot(),\n): FeatureConfig | null {\n const configPath = join(packageRoot, 'features', id, 'feature.json')\n if (!existsSync(configPath)) return null\n try {\n const config = JSON.parse(readFileSync(configPath, 'utf-8')) as Partial<FeatureConfig>\n if (\n typeof config.id !== 'string' ||\n typeof config.name !== 'string' ||\n !Array.isArray(config.files)\n ) {\n return null\n }\n return config as FeatureConfig\n } catch {\n return null\n }\n}\n\nexport function listFeatureConfigs(packageRoot: string = featurePackageRoot()): FeatureConfig[] {\n const featuresDir = join(packageRoot, 'features')\n if (!existsSync(featuresDir)) return []\n return readdirSync(featuresDir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => readFeatureConfig(entry.name, packageRoot))\n .filter((config): config is FeatureConfig => config !== null && !config.internal)\n .sort((a, b) => a.id.localeCompare(b.id))\n}\n\nexport function featureCatalog(packageRoot: string = featurePackageRoot()): FeatureCatalogEntry[] {\n return listFeatureConfigs(packageRoot).map((config) => ({\n id: config.id,\n name: config.name,\n category: config.category ?? null,\n description: config.description ?? null,\n }))\n}\n\nfunction editDistance(a: string, b: string): number {\n const row = Array.from({ length: b.length + 1 }, (_, index) => index)\n for (let i = 1; i <= a.length; i++) {\n let previous = row[0]\n row[0] = i\n for (let j = 1; j <= b.length; j++) {\n const current = row[j]\n row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1))\n previous = current\n }\n }\n return row[b.length]\n}\n\nexport function suggestFeature(\n featureId: string,\n packageRoot: string = featurePackageRoot(),\n): string | null {\n let closest: string | null = null\n let closestDistance = Number.POSITIVE_INFINITY\n for (const feature of listFeatureConfigs(packageRoot)) {\n const distance = editDistance(featureId, feature.id)\n if (distance < closestDistance) {\n closest = feature.id\n closestDistance = distance\n }\n }\n const threshold = Math.max(2, Math.floor(featureId.length / 3))\n return closest !== null && closestDistance <= threshold ? closest : null\n}\n\nfunction resolveTargetDir(raw: string): string {\n return isAbsolute(raw) ? raw : resolve(raw)\n}\n\nexport function resolveFeatureDestPath(fileDest: string, route: FeatureConfig['route']): string {\n const pages = 'src/pages/'\n const appPages = 'src/pages/(app)/'\n if (!fileDest.startsWith(pages) || fileDest.startsWith(appPages)) return fileDest\n const rest = fileDest.slice(pages.length)\n return route?.protected === false ? `${appPages}${rest}` : `${appPages}(protected)/${rest}`\n}\n\nfunction copyFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true })\n copyFileSync(src, dest)\n}\n\nfunction copyFileWithImportShift(src: string, dest: string, levels: number): void {\n mkdirSync(dirname(dest), { recursive: true })\n const prefix = '../'.repeat(levels)\n const shifted = readFileSync(src, 'utf-8').replace(\n /(from\\s+|import\\s+|import\\()(['\"])(\\.\\.\\/)/g,\n `$1$2${prefix}$3`,\n )\n writeFileSync(dest, shifted)\n}\n\nfunction installFiles(\n packageRoot: string,\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): {\n copied: number\n skipped: number\n files: { created: string[]; preexisting: string[]; missing: string[] }\n} {\n let copied = 0\n let skipped = 0\n const created: string[] = []\n const preexisting: string[] = []\n const missing: string[] = []\n\n for (const file of config.files) {\n const srcPath = join(packageRoot, 'features', config.id, file.src)\n const resolvedDest = resolveFeatureDestPath(file.dest, config.route)\n const destPath = join(targetDir, resolvedDest)\n const existed = existsSync(destPath)\n if (existed) preexisting.push(resolvedDest)\n\n if (!existsSync(srcPath)) {\n emit(` Warning: source not found: ${file.src}`, 'stderr')\n if (!existed) missing.push(resolvedDest)\n continue\n }\n\n if (existed && !file.overwrite) {\n emit(` Exists (skipped): ${resolvedDest}`)\n skipped++\n continue\n }\n\n const wasRedirected = resolvedDest !== file.dest\n const shiftLevels = resolvedDest.split('/').length - file.dest.split('/').length\n if (wasRedirected) copyFileWithImportShift(srcPath, destPath, shiftLevels)\n else copyFile(srcPath, destPath)\n emit(` ${existed ? 'Overwrote' : 'Copied'}: ${resolvedDest}`)\n if (!existed) created.push(resolvedDest)\n copied++\n }\n\n return { copied, skipped, files: { created, preexisting, missing } }\n}\n\nfunction unresolvedSchema(\n schema: FeatureSchema,\n reason: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration {\n const entry = schema.spreadOperator ? `...${schema.exportName}` : schema.exportName\n emit('')\n emit(' Add manually to src/schemas.ts:')\n emit(` import { ${schema.exportName} } from '${schema.importPath}'`)\n emit(` // then add ${entry} to the schemas array`)\n return {\n area: 'schema',\n reason,\n steps: [\n `Add import { ${schema.exportName} } from '${schema.importPath}' to src/schemas.ts.`,\n `Add ${entry} to the exported schemas array.`,\n ],\n }\n}\n\nfunction integrateSchema(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n if (!config.schema) return []\n const schemasPath = join(targetDir, 'src', 'schemas.ts')\n if (!existsSync(schemasPath)) {\n return [unresolvedSchema(config.schema, 'src/schemas.ts was not found.', emit)]\n }\n\n let content = readFileSync(schemasPath, 'utf-8')\n const { exportName, importPath, spreadOperator } = config.schema\n const importPattern = new RegExp(`^import\\\\s+\\\\{[^}]*\\\\b${exportName}\\\\b`, 'm')\n if (importPattern.test(content)) {\n emit(` Schema already present: ${exportName}`)\n return []\n }\n if (\n !content.includes('export const schemas') ||\n !/export const schemas:\\s*CollectionSchema\\[\\]\\s*=\\s*\\[/.test(content)\n ) {\n const reason = 'src/schemas.ts has an unexpected structure.'\n emit(` Could not auto-integrate schema (${reason})`)\n return [unresolvedSchema(config.schema, reason, emit)]\n }\n\n const importLine = `import { ${exportName} } from '${importPath}'`\n const withImport = content.replace(\n /export const schemas/,\n `${importLine}\\n\\nexport const schemas`,\n )\n const schemaEntry = spreadOperator ? `...${exportName}` : exportName\n const withEntry = withImport.replace(\n /export const schemas:\\s*CollectionSchema\\[\\]\\s*=\\s*\\[/,\n `export const schemas: CollectionSchema[] = [\\n ${schemaEntry},`,\n )\n if (withImport === content || withEntry === withImport) {\n const reason = 'src/schemas.ts could not be updated safely.'\n emit(` Could not auto-integrate schema (${reason})`)\n return [unresolvedSchema(config.schema, reason, emit)]\n }\n content = withEntry\n writeFileSync(schemasPath, content)\n emit(` Schema integrated: ${exportName} -> schemas.ts`)\n return []\n}\n\nfunction unresolvedActions(\n actions: FeatureAction[],\n reason: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration {\n emit('')\n emit(' Add manually to src/actions/index.ts:')\n for (const action of actions) {\n emit(` import { ${action.exportName} } from '${action.importPath}'`)\n emit(` // then add '${action.registerAs}': ${action.exportName} to the actions object`)\n }\n return {\n area: 'actions',\n reason,\n steps: actions.flatMap((action) => [\n `Add import { ${action.exportName} } from '${action.importPath}' to src/actions/index.ts.`,\n `Register '${action.registerAs}': ${action.exportName} in the exported actions object.`,\n ]),\n }\n}\n\nfunction integrateActions(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n if (!config.actions?.length) return []\n const actionsPath = join(targetDir, 'src', 'actions', 'index.ts')\n if (!existsSync(actionsPath)) {\n return [unresolvedActions(config.actions, 'src/actions/index.ts was not found.', emit)]\n }\n\n let content = readFileSync(actionsPath, 'utf-8')\n const registryPattern =\n /export const actions:\\s*Record<string,\\s*ActionHandler(?:<[^>]*>)?>\\s*=\\s*\\{/\n if (!registryPattern.test(content)) {\n const reason = 'src/actions/index.ts has an unexpected structure.'\n emit(` Could not auto-integrate actions (${reason})`)\n return [unresolvedActions(config.actions, reason, emit)]\n }\n\n let integrated = 0\n const unresolved: UnresolvedIntegration[] = []\n for (const action of config.actions) {\n const importPattern = new RegExp(`^import\\\\s+\\\\{[^}]*\\\\b${action.exportName}\\\\b`, 'm')\n if (importPattern.test(content)) {\n emit(` Action already present: ${action.registerAs}`)\n continue\n }\n const importLine = `import { ${action.exportName} } from '${action.importPath}'`\n const withImport = content.replace(\n /export const actions:/,\n `${importLine}\\n\\nexport const actions:`,\n )\n const registryEntry = ` '${action.registerAs}': ${action.exportName},`\n const withEntry = withImport.replace(registryPattern, (match) => `${match}\\n${registryEntry}`)\n if (withImport === content || withEntry === withImport) {\n emit(` Could not integrate action: ${action.registerAs}`)\n unresolved.push(\n unresolvedActions(\n [action],\n `Action '${action.registerAs}' could not be registered safely.`,\n emit,\n ),\n )\n continue\n }\n content = withEntry\n integrated++\n emit(` Action integrated: ${action.registerAs} (${action.exportName})`)\n }\n if (integrated > 0) writeFileSync(actionsPath, content)\n return unresolved\n}\n\nfunction integrateCode(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n const unresolved: UnresolvedIntegration[] = []\n for (const insertion of config.code ?? []) {\n const targetPath = join(targetDir, insertion.file)\n if (!existsSync(targetPath)) {\n unresolved.push({\n area: 'code',\n reason: `${insertion.file} was not found.`,\n steps: [`Add ${insertion.insert.trim()} to ${insertion.file}.`],\n })\n continue\n }\n\n const original = readFileSync(targetPath, 'utf-8')\n if (original.includes(insertion.insert.trim())) {\n emit(` Integration already present: ${insertion.file}`)\n continue\n }\n const markerIndex = original.indexOf(insertion.marker)\n if (markerIndex < 0) {\n unresolved.push({\n area: 'code',\n reason: `${insertion.file} does not contain the expected insertion point.`,\n steps: [\n ...(insertion.import ? [`Add ${insertion.import} to ${insertion.file}.`] : []),\n `Add ${insertion.insert.trim()} to ${insertion.file}.`,\n ],\n })\n continue\n }\n\n let content = original\n if (insertion.import && !content.includes(insertion.import)) {\n const importIndex = content.search(/^import\\s/m)\n content = `${content.slice(0, importIndex < 0 ? 0 : importIndex)}${insertion.import}\\n${content.slice(\n importIndex < 0 ? 0 : importIndex,\n )}`\n }\n const currentMarkerIndex = content.indexOf(insertion.marker)\n const insertAt =\n insertion.placement === 'before'\n ? currentMarkerIndex\n : currentMarkerIndex + insertion.marker.length\n const prefix = insertion.placement === 'before' ? '' : '\\n'\n const suffix = insertion.placement === 'before' ? '\\n' : ''\n content = `${content.slice(0, insertAt)}${prefix}${insertion.insert}${suffix}${content.slice(insertAt)}`\n writeFileSync(targetPath, content)\n emit(` Integrated: ${insertion.file}`)\n }\n return unresolved\n}\n\nfunction integrateIgnore(config: FeatureConfig, targetDir: string): void {\n if (!config.ignore?.length) return\n const targetPath = join(targetDir, '.gitignore')\n const current = existsSync(targetPath) ? readFileSync(targetPath, 'utf-8') : ''\n const present = new Set(current.split(/\\r?\\n/).map((line) => line.trim()))\n const missing = config.ignore.filter((pattern) => !present.has(pattern))\n if (missing.length === 0) return\n const separator = current === '' || current.endsWith('\\n') ? '' : '\\n'\n writeFileSync(targetPath, `${current}${separator}${missing.join('\\n')}\\n`)\n}\n\nfunction integrateWrangler(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n const runWorkerFirst = config.wrangler?.runWorkerFirst === true\n const rateLimits = config.wrangler?.rateLimits ?? []\n if (!runWorkerFirst && rateLimits.length === 0) return []\n const targetPath = join(targetDir, 'wrangler.toml')\n const steps = [\n ...(runWorkerFirst ? ['Set assets.run_worker_first = true in wrangler.toml.'] : []),\n ...rateLimits.map((binding) => `Add the ${binding.name} rate-limit binding to wrangler.toml.`),\n ]\n if (!existsSync(targetPath)) {\n return [{ area: 'wrangler', reason: 'wrangler.toml was not found.', steps }]\n }\n\n let source = readFileSync(targetPath, 'utf-8')\n if (runWorkerFirst && !/^\\[assets\\]\\s*$/m.test(source)) {\n return [{ area: 'wrangler', reason: 'wrangler.toml has no [assets] section.', steps }]\n }\n\n let changed = false\n if (runWorkerFirst) {\n const updated = setRunWorkerFirst(source)\n changed ||= updated !== source\n source = updated\n }\n\n const scopes = ['', ...wranglerEnvironmentNames(source)]\n for (const scope of scopes) {\n for (const binding of rateLimits) {\n if (hasRateLimitBinding(source, scope, binding.name)) continue\n source = `${source.trimEnd()}\\n\\n${rateLimitBindingBlock(scope, binding)}\\n`\n changed = true\n }\n }\n\n if (changed) {\n writeFileSync(targetPath, source)\n emit(' Integrated: wrangler.toml')\n } else emit(' Integration already present: wrangler.toml')\n return []\n}\n\nfunction setRunWorkerFirst(source: string): string {\n const headers = [...source.matchAll(/^\\[(?:env\\.[^\\]]+\\.)?assets\\]\\s*$/gm)]\n for (const header of headers.reverse()) {\n const start = header.index\n const bodyStart = start + header[0].length\n const nextHeader = source.slice(bodyStart).search(/^\\[\\[?[^\\]]+\\]\\]?\\s*$/m)\n const end = nextHeader < 0 ? source.length : bodyStart + nextHeader\n const section = source.slice(start, end)\n if (/^\\s*run_worker_first\\s*=\\s*true(?:\\s*#.*)?$/m.test(section)) continue\n // Quoted strings are consumed atomically so a `]` inside a route string\n // cannot truncate the array match.\n const setting =\n /^(\\s*)run_worker_first\\s*=\\s*(?:false|\\[(?:[^\\]\"']|\"(?:[^\"\\\\]|\\\\[\\s\\S])*\"|'[^']*')*\\])(\\s*(?:#.*)?)$/m\n const updated = setting.test(section)\n ? section.replace(setting, '$1run_worker_first = true$2')\n : section.replace(/^\\[(?:env\\.[^\\]]+\\.)?assets\\]\\s*$/m, '$&\\nrun_worker_first = true')\n source = source.slice(0, start) + updated + source.slice(end)\n }\n return source\n}\n\nfunction wranglerEnvironmentNames(source: string): string[] {\n return [\n ...new Set(\n [...source.matchAll(/^\\[\\[?env\\.([^.\\]]+)(?:\\.|\\]\\]?\\s*$)/gm)].map((match) => match[1]),\n ),\n ]\n}\n\nfunction hasRateLimitBinding(source: string, scope: string, name: string): boolean {\n const header = scope ? `[[env.${scope}.ratelimits]]` : '[[ratelimits]]'\n // Tolerate hand-reformatted spacing and either TOML string quoting so a\n // reinstall never appends a duplicate block Wrangler would reject.\n const escaped = name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const namePattern = new RegExp(\n `^\\\\s*name\\\\s*=\\\\s*(?:\"${escaped}\"|'${escaped}')\\\\s*(?:#.*)?$`,\n 'm',\n )\n let offset = 0\n while ((offset = source.indexOf(header, offset)) >= 0) {\n const end = source.slice(offset + header.length).search(/^\\[/m)\n const blockEnd = end < 0 ? source.length : offset + header.length + end\n if (namePattern.test(source.slice(offset, blockEnd))) return true\n offset += header.length\n }\n return false\n}\n\nfunction rateLimitBindingBlock(\n scope: string,\n binding: NonNullable<FeatureWranglerIntegration['rateLimits']>[number],\n): string {\n const header = scope ? `[[env.${scope}.ratelimits]]` : '[[ratelimits]]'\n return [\n header,\n `name = ${JSON.stringify(binding.name)}`,\n `namespace_id = ${JSON.stringify(binding.namespaceId)}`,\n `simple = { limit = ${binding.limit}, period = ${binding.period} }`,\n ].join('\\n')\n}\n\nfunction integrateCss(\n packageRoot: string,\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n if (!config.css?.length) return []\n const stylesPath = join(targetDir, 'src', 'styles.css')\n if (!existsSync(stylesPath)) {\n emit(' Warning: Cannot integrate CSS — src/styles.css not found')\n return [\n {\n area: 'css',\n reason: 'src/styles.css was not found.',\n steps: config.css.map(\n (cssFile) =>\n `Append node_modules/deepspace/features/${config.id}/${cssFile} to src/styles.css.`,\n ),\n },\n ]\n }\n\n let styles = readFileSync(stylesPath, 'utf-8')\n let integrated = 0\n const unresolved: UnresolvedIntegration[] = []\n for (const cssFile of config.css) {\n const srcPath = join(packageRoot, 'features', config.id, cssFile)\n if (!existsSync(srcPath)) {\n emit(` Warning: CSS source not found: ${cssFile}`, 'stderr')\n unresolved.push({\n area: 'css',\n reason: `Feature CSS source '${cssFile}' was not found in the installed package.`,\n steps: ['Reinstall the current deepspace package, then retry this feature installation.'],\n })\n continue\n }\n const css = readFileSync(srcPath, 'utf-8')\n const fingerprint = css.match(/\\.([\\w-]+)\\s*\\{|@keyframes\\s+([\\w-]+)/)\n const marker = fingerprint?.[1] ?? fingerprint?.[2]\n if (marker && styles.includes(marker)) {\n emit(` CSS already present: ${cssFile} (found .${marker})`)\n continue\n }\n styles += `\\n${css}`\n integrated++\n emit(` CSS integrated: ${cssFile} -> styles.css`)\n }\n if (integrated > 0) writeFileSync(stylesPath, styles)\n return unresolved\n}\n\nfunction unresolvedRoute(\n route: NonNullable<FeatureConfig['route']>,\n config: FeatureConfig,\n reason: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration {\n const roles = routeRolesSuffix(route)\n emit('')\n emit(' Add manually to src/nav.ts:')\n emit(` { path: '${route.path}', label: '${config.name}'${roles} },`)\n return {\n area: 'nav',\n reason,\n steps: [\n `Add { path: '${route.path}', label: '${config.name}'${roles} } to the exported nav array.`,\n ],\n }\n}\n\nfunction routeRolesSuffix(route: NonNullable<FeatureConfig['route']>): string {\n const roles = route.roles?.length ? route.roles : route.protected === false ? [] : ['member']\n return roles.length ? `, roles: [${roles.map((role) => `'${role}' as Role`).join(', ')}]` : ''\n}\n\nfunction integrateRoute(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n if (!config.route) return []\n const navPath = join(targetDir, 'src', 'nav.ts')\n if (!existsSync(navPath)) {\n return [unresolvedRoute(config.route, config, 'src/nav.ts was not found.', emit)]\n }\n let content = readFileSync(navPath, 'utf-8')\n const routePath = config.route.path\n if (content.includes(`'${routePath}'`)) {\n emit(` Nav already present: ${routePath}`)\n return []\n }\n if (!content.includes(NAV_MARKER)) {\n emit(' Could not auto-wire nav (marker not found in nav.ts)')\n return [\n unresolvedRoute(\n config.route,\n config,\n 'The feature insertion marker was not found in src/nav.ts.',\n emit,\n ),\n ]\n }\n const roles = routeRolesSuffix(config.route)\n const entry = ` { path: '${routePath}', label: '${config.name}'${roles} },`\n content = content.replace(NAV_MARKER, `${NAV_MARKER}\\n${entry}`)\n writeFileSync(navPath, content)\n emit(` Nav wired: ${routePath} (${config.name})`)\n emit(' Route: automatic (file-based routing via src/pages/)')\n return []\n}\n\nconst INSTALL_DIAGNOSTIC_BYTES = 16 * 1024\n\ninterface PackageInstallRun {\n error?: Error\n status: number | null\n diagnosticTail?: string\n}\n\nfunction readDiagnosticTail(outputFd: number): string | undefined {\n const size = fstatSync(outputFd).size\n if (size === 0) return undefined\n const length = Math.min(size, INSTALL_DIAGNOSTIC_BYTES)\n const buffer = Buffer.alloc(length)\n readSync(outputFd, buffer, 0, length, size - length)\n const tail = buffer.toString('utf-8').trim()\n if (!tail) return undefined\n return size > length ? `[last ${length} bytes]\\n${tail}` : tail\n}\n\nfunction runPackageInstall(\n packageManager: string,\n targetDir: string,\n outputVisible: boolean,\n): PackageInstallRun {\n const options = {\n cwd: targetDir,\n shell: process.platform === 'win32',\n }\n if (outputVisible) {\n const child = spawnSync(packageManager, ['install'], { ...options, stdio: 'inherit' })\n return { error: child.error, status: child.status }\n }\n\n // Keep stdout reserved for the command's one-line JSON envelope. Both child\n // streams share a temporary file, then only a fixed-size tail enters memory.\n const captureDir = mkdtempSync(join(tmpdir(), 'deepspace-add-install-'))\n let outputFd: number | undefined\n try {\n outputFd = openSync(join(captureDir, 'output.log'), 'w+')\n const child = spawnSync(packageManager, ['install'], {\n ...options,\n stdio: ['ignore', outputFd, outputFd],\n })\n return {\n error: child.error,\n status: child.status,\n diagnosticTail: readDiagnosticTail(outputFd),\n }\n } finally {\n if (outputFd !== undefined) closeSync(outputFd)\n rmSync(captureDir, { recursive: true, force: true })\n }\n}\n\nfunction integrateDependencies(\n config: FeatureConfig,\n targetDir: string,\n runInstall: boolean,\n outputVisible: boolean,\n emit: FeatureInstallerOutput,\n): {\n added: DependencyAddition[]\n installRan: boolean\n installError?: string\n diagnosticTail?: string\n packageManager: string\n} {\n const packageManager = detectPackageManager(targetDir)\n const declarations: Array<{\n section: DependencySection\n values: Record<string, string> | undefined\n }> = [\n { section: 'dependencies', values: config.dependencies },\n { section: 'devDependencies', values: config.devDependencies },\n ]\n if (declarations.every(({ values }) => !values || Object.keys(values).length === 0)) {\n return { added: [], installRan: false, packageManager }\n }\n\n const packagePath = join(targetDir, 'package.json')\n if (!existsSync(packagePath)) {\n emit(' Could not patch package.json (file not found)')\n return { added: [], installRan: false, packageManager }\n }\n\n let pkg: Record<string, unknown> & {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n }\n try {\n pkg = JSON.parse(readFileSync(packagePath, 'utf-8')) as typeof pkg\n } catch (error) {\n emit(\n ` Could not patch package.json (parse error: ${error instanceof Error ? error.message : String(error)})`,\n )\n return { added: [], installRan: false, packageManager }\n }\n\n const added: DependencyAddition[] = []\n const skipped: string[] = []\n for (const { section, values } of declarations) {\n if (!values) continue\n pkg[section] ??= {}\n for (const [name, version] of Object.entries(values)) {\n if (pkg.dependencies?.[name] || pkg.devDependencies?.[name]) {\n if (!added.some((dependency) => dependency.name === name)) skipped.push(name)\n continue\n }\n pkg[section]![name] = version\n added.push({ name, section, version })\n }\n }\n\n if (added.length === 0) {\n emit(' Dependencies already present')\n } else {\n writeFileSync(packagePath, `${JSON.stringify(pkg, null, 2)}\\n`, 'utf-8')\n emit(` Added to package.json: ${added.map(({ name }) => name).join(', ')}`)\n if (skipped.length) emit(` Already present (kept your version): ${skipped.join(', ')}`)\n }\n\n if (!runInstall) return { added, installRan: false, packageManager }\n emit('')\n emit(` Installing dependencies with ${packageManager}...`)\n const child = runPackageInstall(packageManager, targetDir, outputVisible)\n if (child.error) {\n const error = child.error as NodeJS.ErrnoException\n const reason = error.code === 'ENOENT' ? `${packageManager} not found on PATH` : error.message\n return {\n added,\n installRan: false,\n installError: `Could not launch ${packageManager} (${reason}).`,\n diagnosticTail: child.diagnosticTail,\n packageManager,\n }\n }\n if (child.status !== 0) {\n const diagnostic = child.diagnosticTail ? `\\nDiagnostic tail:\\n${child.diagnosticTail}` : ''\n return {\n added,\n installRan: false,\n installError: `${packageManager} install did not complete (exit ${child.status ?? 'unknown'}).${diagnostic}`,\n diagnosticTail: child.diagnosticTail,\n packageManager,\n }\n }\n return { added, installRan: true, packageManager }\n}\n\nfunction dependencySnapshot(targetDir: string): {\n dependencies: Record<string, unknown>\n devDependencies: Record<string, unknown>\n} {\n try {\n const pkg = JSON.parse(readFileSync(join(targetDir, 'package.json'), 'utf-8')) as {\n dependencies?: Record<string, unknown>\n devDependencies?: Record<string, unknown>\n }\n return {\n dependencies: pkg.dependencies ?? {},\n devDependencies: pkg.devDependencies ?? {},\n }\n } catch {\n return { dependencies: {}, devDependencies: {} }\n }\n}\n\nfunction installedNavFeatures(packageRoot: string, targetDir: string): string[] {\n return listFeatureConfigs(packageRoot)\n .filter((feature) => feature.category === 'nav' && feature.files.length > 0)\n .filter((feature) => {\n const signature = resolveFeatureDestPath(feature.files[0].dest, feature.route)\n return existsSync(join(targetDir, signature))\n })\n .map((feature) => feature.id)\n}\n\nfunction warnNavConflicts(\n packageRoot: string,\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): void {\n if (config.category !== 'nav') return\n const present = installedNavFeatures(packageRoot, targetDir)\n if (present.length <= 1) return\n emit('')\n emit(`⚠ Multiple navigation features present (${present.join(', ')}).`)\n emit(' sidebar, topbar, and tree are mutually exclusive — keep one and remove the')\n emit(' others to avoid competing navigation in your layout.')\n}\n\nexport function installFeature(options: FeatureInstallOptions): FeatureInstallOutcome {\n const packageRoot = featurePackageRoot()\n const targetDir = resolveTargetDir(options.targetDir)\n const config = readFeatureConfig(options.feature, packageRoot)\n if (!config) {\n const suggestion = suggestFeature(options.feature, packageRoot)\n return {\n ok: false,\n code: 'unknown_feature',\n error: [\n `Unknown feature: ${options.feature}`,\n ...(suggestion ? [`Did you mean \"${suggestion}\"?`] : []),\n ].join('\\n'),\n data: {\n requestedFeature: options.feature,\n suggestedFeature: suggestion,\n availableFeatures: featureCatalog(packageRoot),\n },\n }\n }\n\n const emit: FeatureInstallerOutput = options.emit ?? (() => undefined)\n emit('')\n emit(`Installing: ${config.name}`)\n emit(` ${config.description ?? ''}`)\n emit(` Target: ${targetDir}`)\n\n const installedFiles = installFiles(packageRoot, config, targetDir, emit)\n integrateIgnore(config, targetDir)\n emit('')\n emit(\n `Copied ${installedFiles.copied} file(s)${\n installedFiles.skipped > 0 ? `, skipped ${installedFiles.skipped} existing` : ''\n }`,\n )\n\n const unresolvedIntegrations = [\n ...integrateSchema(config, targetDir, emit),\n ...integrateActions(config, targetDir, emit),\n ...integrateWrangler(config, targetDir, emit),\n ...integrateCode(config, targetDir, emit),\n ...integrateCss(packageRoot, config, targetDir, emit),\n ...integrateRoute(config, targetDir, emit),\n ]\n const dependencyResult = integrateDependencies(\n config,\n targetDir,\n options.installDependencies,\n options.emit !== undefined,\n emit,\n )\n\n if (config.instructions?.length) {\n emit('')\n emit('--- Next steps ---')\n emit('')\n config.instructions.forEach((instruction, index) => {\n emit(`${index + 1}. ${instruction}`)\n emit('')\n })\n }\n if (config.patterns?.length) {\n emit('--- Key patterns ---')\n emit('')\n config.patterns.forEach((pattern) => emit(`- ${pattern}`))\n emit('')\n }\n warnNavConflicts(packageRoot, config, targetDir, emit)\n\n const dependenciesAfter = dependencySnapshot(targetDir)\n const declaredDependencies = [\n ...Object.keys(config.dependencies ?? {}),\n ...Object.keys(config.devDependencies ?? {}),\n ]\n const missingDeclarations = declaredDependencies.filter(\n (name) =>\n !(name in dependenciesAfter.dependencies) && !(name in dependenciesAfter.devDependencies),\n )\n const installed =\n installedFiles.files.missing.length === 0 &&\n missingDeclarations.length === 0 &&\n unresolvedIntegrations.length === 0 &&\n dependencyResult.installError === undefined\n const dependencyInstallRequired =\n installed &&\n dependencyResult.added.length > 0 &&\n !options.installDependencies &&\n !dependencyResult.installRan\n\n const data: InstallData = {\n feature: config.id,\n dir: targetDir,\n installed,\n observedChanges: {\n files: installedFiles.files,\n dependencies: {\n added: dependencyResult.added,\n missingDeclarations,\n installRequested: options.installDependencies,\n ...(dependencyResult.diagnosticTail\n ? { diagnosticTail: dependencyResult.diagnosticTail }\n : {}),\n },\n },\n unresolvedIntegrations,\n manifestGuidance: {\n instructions: config.instructions ?? [],\n patterns: config.patterns ?? [],\n agentNotes: config.agentNotes ?? [],\n },\n }\n if (dependencyResult.installError) {\n return {\n ok: false,\n code: 'dependency_install_failed',\n error: dependencyResult.installError,\n data,\n }\n }\n if (unresolvedIntegrations.length > 0) {\n const count = unresolvedIntegrations.length\n return {\n ok: false,\n code: 'manual_integration_required',\n error: `${count} app integration${count === 1 ? '' : 's'} require manual completion. Follow the unresolved integration steps, then run your checks.`,\n data,\n }\n }\n\n return {\n ok: true,\n data,\n ...(dependencyInstallRequired\n ? {\n action: {\n cwd: targetDir,\n argv: [dependencyResult.packageManager, 'install'],\n },\n }\n : {}),\n }\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun'\n\n/** Resolve the repository's package manager from its explicit packageManager\n * field first, then its lockfile. npm is the conservative fallback. */\nexport function detectPackageManager(appDir: string): PackageManager {\n try {\n const pkg = JSON.parse(readFileSync(join(appDir, 'package.json'), 'utf-8')) as {\n packageManager?: unknown\n }\n const name = typeof pkg.packageManager === 'string' ? pkg.packageManager.split('@')[0] : ''\n if (name === 'npm' || name === 'pnpm' || name === 'yarn' || name === 'bun') return name\n } catch {\n // Missing/malformed package.json falls through to lockfile detection.\n }\n if (existsSync(join(appDir, 'pnpm-lock.yaml'))) return 'pnpm'\n if (existsSync(join(appDir, 'yarn.lock'))) return 'yarn'\n if (existsSync(join(appDir, 'bun.lock')) || existsSync(join(appDir, 'bun.lockb'))) return 'bun'\n return 'npm'\n}\n\nexport function installCommand(appDir: string): string {\n return `${detectPackageManager(appDir)} install`\n}\n"],"mappings":"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","names":["existsSync","readFileSync","join","join","existsSync","readFileSync"]}
1
+ {"version":3,"sources":["../src/cli/commands/feature-installer.ts","../src/cli/lib/command-suggestions.ts","../src/cli/lib/package-manager.ts"],"sourcesContent":["/**\n * The feature catalog and installer.\n *\n * This is a separate build entry because `add` loads the copy shipped by the\n * target app's installed `deepspace` package. That keeps feature files,\n * manifest interpretation, and mutations on the app-pinned SDK version while\n * leaving the public command/output contract in add.ts.\n */\n\nimport {\n closeSync,\n copyFileSync,\n existsSync,\n fstatSync,\n mkdirSync,\n mkdtempSync,\n openSync,\n readFileSync,\n readSync,\n readdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { spawnSync } from 'node:child_process'\nimport { tmpdir } from 'node:os'\nimport { dirname, isAbsolute, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { editDistance } from '../lib/command-suggestions'\nimport { detectPackageManager } from '../lib/package-manager'\n\nconst NAV_MARKER = '// ── Features add nav items below this line ──'\n\ninterface FeatureFile {\n src: string\n dest: string\n}\n\ninterface FeatureSchema {\n exportName: string\n importPath: string\n spreadOperator?: boolean\n}\n\ninterface FeatureAction {\n exportName: string\n registerAs: string\n importPath: string\n}\n\ninterface FeatureCodeInsertion {\n file: string\n marker: string\n insert: string\n placement?: 'before' | 'after'\n import?: string\n}\n\ninterface FeatureWranglerIntegration {\n runWorkerFirst?: boolean\n rateLimits?: Array<{\n name: string\n namespaceId: string\n limit: number\n period: 10 | 60\n }>\n}\n\nexport interface FeatureConfig {\n id: string\n name: string\n category?: string\n description?: string\n details?: string\n internal?: boolean\n files: FeatureFile[]\n ignore?: string[]\n route?: {\n path?: string\n protected?: boolean\n roles?: Array<'viewer' | 'member' | 'admin'>\n }\n schema?: FeatureSchema\n actions?: FeatureAction[]\n code?: FeatureCodeInsertion[]\n wrangler?: FeatureWranglerIntegration\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n instructions?: string[]\n patterns?: string[]\n agentNotes?: string[]\n example?: string\n [key: string]: unknown\n}\n\nexport interface FeatureCatalogEntry {\n id: string\n name: string\n category: string | null\n description: string | null\n}\n\ntype DependencySection = 'dependencies' | 'devDependencies'\n\ninterface DependencyAddition {\n name: string\n section: DependencySection\n version: unknown\n}\n\ntype IntegrationArea = 'schema' | 'actions' | 'code' | 'nav' | 'wrangler'\n\ninterface UnresolvedIntegration {\n area: IntegrationArea\n reason: string\n steps: string[]\n}\n\ninterface InstallData extends Record<string, unknown> {\n feature: string\n dir: string\n installed: boolean\n observedChanges: {\n files: { created: string[]; preexisting: string[]; missing: string[] }\n dependencies: {\n added: DependencyAddition[]\n missingDeclarations: string[]\n installRequested: boolean\n diagnosticTail?: string\n }\n }\n unresolvedIntegrations: UnresolvedIntegration[]\n manifestGuidance: {\n instructions: string[]\n patterns: string[]\n agentNotes: string[]\n }\n}\n\ninterface InstallerAction {\n cwd: string\n argv: string[]\n}\n\nexport type FeatureInstallOutcome =\n | { ok: true; data: InstallData; action?: InstallerAction }\n | {\n ok: false\n code: 'unknown_feature'\n error: string\n data: {\n requestedFeature: string\n suggestedFeature: string | null\n availableFeatures: FeatureCatalogEntry[]\n }\n }\n | {\n ok: false\n code: 'dependency_install_failed' | 'manual_integration_required'\n error: string\n data: InstallData\n }\n\nexport type FeatureInstallerOutput = (line: string, stream?: 'stdout' | 'stderr') => void\n\nexport interface FeatureInstallOptions {\n feature: string\n targetDir: string\n installDependencies: boolean\n emit?: FeatureInstallerOutput\n}\n\n/** Find the package containing this source file or emitted build entry. */\nexport function featurePackageRoot(moduleUrl: string = import.meta.url): string {\n let dir = dirname(fileURLToPath(moduleUrl))\n for (;;) {\n const packagePath = join(dir, 'package.json')\n if (existsSync(packagePath)) {\n try {\n const pkg = JSON.parse(readFileSync(packagePath, 'utf-8')) as { name?: unknown }\n if (pkg.name === 'deepspace') return dir\n } catch {\n // Keep walking: a nearer unrelated package.json is not this package.\n }\n }\n const parent = dirname(dir)\n if (parent === dir) throw new Error('Could not locate the deepspace package root')\n dir = parent\n }\n}\n\nexport function hasFeatureCatalog(packageRoot: string = featurePackageRoot()): boolean {\n return existsSync(join(packageRoot, 'features'))\n}\n\nexport function readFeatureConfig(\n id: string,\n packageRoot: string = featurePackageRoot(),\n): FeatureConfig | null {\n const configPath = join(packageRoot, 'features', id, 'feature.json')\n if (!existsSync(configPath)) return null\n try {\n const config = JSON.parse(readFileSync(configPath, 'utf-8')) as Partial<FeatureConfig>\n if (\n typeof config.id !== 'string' ||\n typeof config.name !== 'string' ||\n !Array.isArray(config.files)\n ) {\n return null\n }\n return config as FeatureConfig\n } catch {\n return null\n }\n}\n\nexport function listFeatureConfigs(packageRoot: string = featurePackageRoot()): FeatureConfig[] {\n const featuresDir = join(packageRoot, 'features')\n if (!existsSync(featuresDir)) return []\n return readdirSync(featuresDir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => readFeatureConfig(entry.name, packageRoot))\n .filter((config): config is FeatureConfig => config !== null && !config.internal)\n .sort((a, b) => a.id.localeCompare(b.id))\n}\n\nexport function featureCatalog(packageRoot: string = featurePackageRoot()): FeatureCatalogEntry[] {\n return listFeatureConfigs(packageRoot).map((config) => ({\n id: config.id,\n name: config.name,\n category: config.category ?? null,\n description: config.description ?? null,\n }))\n}\n\nexport function suggestFeature(\n featureId: string,\n packageRoot: string = featurePackageRoot(),\n): string | null {\n let closest: string | null = null\n let closestDistance = Number.POSITIVE_INFINITY\n for (const feature of listFeatureConfigs(packageRoot)) {\n const distance = editDistance(featureId, feature.id)\n if (distance < closestDistance) {\n closest = feature.id\n closestDistance = distance\n }\n }\n const threshold = Math.max(2, Math.floor(featureId.length / 3))\n return closest !== null && closestDistance <= threshold ? closest : null\n}\n\nfunction resolveTargetDir(raw: string): string {\n return isAbsolute(raw) ? raw : resolve(raw)\n}\n\nexport function resolveFeatureDestPath(fileDest: string, route: FeatureConfig['route']): string {\n const pages = 'src/pages/'\n const appPages = 'src/pages/(app)/'\n if (!fileDest.startsWith(pages) || fileDest.startsWith(appPages)) return fileDest\n const rest = fileDest.slice(pages.length)\n return route?.protected === false ? `${appPages}${rest}` : `${appPages}(protected)/${rest}`\n}\n\nfunction copyFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true })\n copyFileSync(src, dest)\n}\n\nfunction copyFileWithImportShift(src: string, dest: string, levels: number): void {\n mkdirSync(dirname(dest), { recursive: true })\n const prefix = '../'.repeat(levels)\n const shifted = readFileSync(src, 'utf-8').replace(\n /(from\\s+|import\\s+|import\\()(['\"])(\\.\\.\\/)/g,\n `$1$2${prefix}$3`,\n )\n writeFileSync(dest, shifted)\n}\n\nfunction installFiles(\n packageRoot: string,\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): {\n copied: number\n skipped: number\n files: { created: string[]; preexisting: string[]; missing: string[] }\n} {\n let copied = 0\n let skipped = 0\n const created: string[] = []\n const preexisting: string[] = []\n const missing: string[] = []\n\n for (const file of config.files) {\n const srcPath = join(packageRoot, 'features', config.id, file.src)\n const resolvedDest = resolveFeatureDestPath(file.dest, config.route)\n const destPath = join(targetDir, resolvedDest)\n const existed = existsSync(destPath)\n if (existed) preexisting.push(resolvedDest)\n\n if (!existsSync(srcPath)) {\n emit(` Warning: source not found: ${file.src}`, 'stderr')\n if (!existed) missing.push(resolvedDest)\n continue\n }\n\n if (existed) {\n emit(` Exists (skipped): ${resolvedDest}`)\n skipped++\n continue\n }\n\n const wasRedirected = resolvedDest !== file.dest\n const shiftLevels = resolvedDest.split('/').length - file.dest.split('/').length\n if (wasRedirected) copyFileWithImportShift(srcPath, destPath, shiftLevels)\n else copyFile(srcPath, destPath)\n emit(` Copied: ${resolvedDest}`)\n created.push(resolvedDest)\n copied++\n }\n\n return { copied, skipped, files: { created, preexisting, missing } }\n}\n\nfunction unresolvedSchema(\n schema: FeatureSchema,\n reason: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration {\n const entry = schema.spreadOperator ? `...${schema.exportName}` : schema.exportName\n emit('')\n emit(' Add manually to src/schemas.ts:')\n emit(` import { ${schema.exportName} } from '${schema.importPath}'`)\n emit(` // then add ${entry} to the schemas array`)\n return {\n area: 'schema',\n reason,\n steps: [\n `Add import { ${schema.exportName} } from '${schema.importPath}' to src/schemas.ts.`,\n `Add ${entry} to the exported schemas array.`,\n ],\n }\n}\n\nfunction integrateSchema(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n if (!config.schema) return []\n const schemasPath = join(targetDir, 'src', 'schemas.ts')\n if (!existsSync(schemasPath)) {\n return [unresolvedSchema(config.schema, 'src/schemas.ts was not found.', emit)]\n }\n\n let content = readFileSync(schemasPath, 'utf-8')\n const { exportName, importPath, spreadOperator } = config.schema\n const importPattern = new RegExp(`^import\\\\s+\\\\{[^}]*\\\\b${exportName}\\\\b`, 'm')\n if (importPattern.test(content)) {\n emit(` Schema already present: ${exportName}`)\n return []\n }\n if (\n !content.includes('export const schemas') ||\n !/export const schemas:\\s*CollectionSchema\\[\\]\\s*=\\s*\\[/.test(content)\n ) {\n const reason = 'src/schemas.ts has an unexpected structure.'\n emit(` Could not auto-integrate schema (${reason})`)\n return [unresolvedSchema(config.schema, reason, emit)]\n }\n\n const importLine = `import { ${exportName} } from '${importPath}'`\n const withImport = content.replace(\n /export const schemas/,\n `${importLine}\\n\\nexport const schemas`,\n )\n const schemaEntry = spreadOperator ? `...${exportName}` : exportName\n const withEntry = withImport.replace(\n /export const schemas:\\s*CollectionSchema\\[\\]\\s*=\\s*\\[/,\n `export const schemas: CollectionSchema[] = [\\n ${schemaEntry},`,\n )\n if (withImport === content || withEntry === withImport) {\n const reason = 'src/schemas.ts could not be updated safely.'\n emit(` Could not auto-integrate schema (${reason})`)\n return [unresolvedSchema(config.schema, reason, emit)]\n }\n content = withEntry\n writeFileSync(schemasPath, content)\n emit(` Schema integrated: ${exportName} -> schemas.ts`)\n return []\n}\n\nfunction unresolvedActions(\n actions: FeatureAction[],\n reason: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration {\n emit('')\n emit(' Add manually to src/actions/index.ts:')\n for (const action of actions) {\n emit(` import { ${action.exportName} } from '${action.importPath}'`)\n emit(` // then add '${action.registerAs}': ${action.exportName} to the actions object`)\n }\n return {\n area: 'actions',\n reason,\n steps: actions.flatMap((action) => [\n `Add import { ${action.exportName} } from '${action.importPath}' to src/actions/index.ts.`,\n `Register '${action.registerAs}': ${action.exportName} in the exported actions object.`,\n ]),\n }\n}\n\nfunction integrateActions(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n if (!config.actions?.length) return []\n const actionsPath = join(targetDir, 'src', 'actions', 'index.ts')\n if (!existsSync(actionsPath)) {\n return [unresolvedActions(config.actions, 'src/actions/index.ts was not found.', emit)]\n }\n\n let content = readFileSync(actionsPath, 'utf-8')\n const registryPattern =\n /export const actions:\\s*Record<string,\\s*ActionHandler(?:<[^>]*>)?>\\s*=\\s*\\{/\n if (!registryPattern.test(content)) {\n const reason = 'src/actions/index.ts has an unexpected structure.'\n emit(` Could not auto-integrate actions (${reason})`)\n return [unresolvedActions(config.actions, reason, emit)]\n }\n\n let integrated = 0\n const unresolved: UnresolvedIntegration[] = []\n for (const action of config.actions) {\n const importPattern = new RegExp(`^import\\\\s+\\\\{[^}]*\\\\b${action.exportName}\\\\b`, 'm')\n if (importPattern.test(content)) {\n emit(` Action already present: ${action.registerAs}`)\n continue\n }\n const importLine = `import { ${action.exportName} } from '${action.importPath}'`\n const withImport = content.replace(\n /export const actions:/,\n `${importLine}\\n\\nexport const actions:`,\n )\n const registryEntry = ` '${action.registerAs}': ${action.exportName},`\n const withEntry = withImport.replace(registryPattern, (match) => `${match}\\n${registryEntry}`)\n if (withImport === content || withEntry === withImport) {\n emit(` Could not integrate action: ${action.registerAs}`)\n unresolved.push(\n unresolvedActions(\n [action],\n `Action '${action.registerAs}' could not be registered safely.`,\n emit,\n ),\n )\n continue\n }\n content = withEntry\n integrated++\n emit(` Action integrated: ${action.registerAs} (${action.exportName})`)\n }\n if (integrated > 0) writeFileSync(actionsPath, content)\n return unresolved\n}\n\nfunction integrateCode(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n const unresolved: UnresolvedIntegration[] = []\n for (const insertion of config.code ?? []) {\n const targetPath = join(targetDir, insertion.file)\n if (!existsSync(targetPath)) {\n unresolved.push({\n area: 'code',\n reason: `${insertion.file} was not found.`,\n steps: [`Add ${insertion.insert.trim()} to ${insertion.file}.`],\n })\n continue\n }\n\n const original = readFileSync(targetPath, 'utf-8')\n if (original.includes(insertion.insert.trim())) {\n emit(` Integration already present: ${insertion.file}`)\n continue\n }\n const markerIndex = original.indexOf(insertion.marker)\n if (markerIndex < 0) {\n unresolved.push({\n area: 'code',\n reason: `${insertion.file} does not contain the expected insertion point.`,\n steps: [\n ...(insertion.import ? [`Add ${insertion.import} to ${insertion.file}.`] : []),\n `Add ${insertion.insert.trim()} to ${insertion.file}.`,\n ],\n })\n continue\n }\n\n let content = original\n if (insertion.import && !content.includes(insertion.import)) {\n const importIndex = content.search(/^import\\s/m)\n content = `${content.slice(0, importIndex < 0 ? 0 : importIndex)}${insertion.import}\\n${content.slice(\n importIndex < 0 ? 0 : importIndex,\n )}`\n }\n const currentMarkerIndex = content.indexOf(insertion.marker)\n const insertAt =\n insertion.placement === 'before'\n ? currentMarkerIndex\n : currentMarkerIndex + insertion.marker.length\n const prefix = insertion.placement === 'before' ? '' : '\\n'\n const suffix = insertion.placement === 'before' ? '\\n' : ''\n content = `${content.slice(0, insertAt)}${prefix}${insertion.insert}${suffix}${content.slice(insertAt)}`\n writeFileSync(targetPath, content)\n emit(` Integrated: ${insertion.file}`)\n }\n return unresolved\n}\n\nfunction integrateIgnore(config: FeatureConfig, targetDir: string): void {\n if (!config.ignore?.length) return\n const targetPath = join(targetDir, '.gitignore')\n const current = existsSync(targetPath) ? readFileSync(targetPath, 'utf-8') : ''\n const present = new Set(current.split(/\\r?\\n/).map((line) => line.trim()))\n const missing = config.ignore.filter((pattern) => !present.has(pattern))\n if (missing.length === 0) return\n const separator = current === '' || current.endsWith('\\n') ? '' : '\\n'\n writeFileSync(targetPath, `${current}${separator}${missing.join('\\n')}\\n`)\n}\n\nfunction integrateWrangler(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n const runWorkerFirst = config.wrangler?.runWorkerFirst === true\n const rateLimits = config.wrangler?.rateLimits ?? []\n if (!runWorkerFirst && rateLimits.length === 0) return []\n const targetPath = join(targetDir, 'wrangler.toml')\n const steps = [\n ...(runWorkerFirst ? ['Set assets.run_worker_first = true in wrangler.toml.'] : []),\n ...rateLimits.map((binding) => `Add the ${binding.name} rate-limit binding to wrangler.toml.`),\n ]\n if (!existsSync(targetPath)) {\n return [{ area: 'wrangler', reason: 'wrangler.toml was not found.', steps }]\n }\n\n let source = readFileSync(targetPath, 'utf-8')\n if (runWorkerFirst && !/^\\[assets\\]\\s*$/m.test(source)) {\n return [{ area: 'wrangler', reason: 'wrangler.toml has no [assets] section.', steps }]\n }\n\n let changed = false\n if (runWorkerFirst) {\n const updated = setRunWorkerFirst(source)\n changed ||= updated !== source\n source = updated\n }\n\n const scopes = ['', ...wranglerEnvironmentNames(source)]\n for (const scope of scopes) {\n for (const binding of rateLimits) {\n if (hasRateLimitBinding(source, scope, binding.name)) continue\n source = `${source.trimEnd()}\\n\\n${rateLimitBindingBlock(scope, binding)}\\n`\n changed = true\n }\n }\n\n if (changed) {\n writeFileSync(targetPath, source)\n emit(' Integrated: wrangler.toml')\n } else emit(' Integration already present: wrangler.toml')\n return []\n}\n\nfunction setRunWorkerFirst(source: string): string {\n const headers = [...source.matchAll(/^\\[(?:env\\.[^\\]]+\\.)?assets\\]\\s*$/gm)]\n for (const header of headers.reverse()) {\n const start = header.index\n const bodyStart = start + header[0].length\n const nextHeader = source.slice(bodyStart).search(/^\\[\\[?[^\\]]+\\]\\]?\\s*$/m)\n const end = nextHeader < 0 ? source.length : bodyStart + nextHeader\n const section = source.slice(start, end)\n if (/^\\s*run_worker_first\\s*=\\s*true(?:\\s*#.*)?$/m.test(section)) continue\n // Quoted strings are consumed atomically so a `]` inside a route string\n // cannot truncate the array match.\n const setting =\n /^(\\s*)run_worker_first\\s*=\\s*(?:false|\\[(?:[^\\]\"']|\"(?:[^\"\\\\]|\\\\[\\s\\S])*\"|'[^']*')*\\])(\\s*(?:#.*)?)$/m\n const updated = setting.test(section)\n ? section.replace(setting, '$1run_worker_first = true$2')\n : section.replace(/^\\[(?:env\\.[^\\]]+\\.)?assets\\]\\s*$/m, '$&\\nrun_worker_first = true')\n source = source.slice(0, start) + updated + source.slice(end)\n }\n return source\n}\n\nfunction wranglerEnvironmentNames(source: string): string[] {\n return [\n ...new Set(\n [...source.matchAll(/^\\[\\[?env\\.([^.\\]]+)(?:\\.|\\]\\]?\\s*$)/gm)].map((match) => match[1]),\n ),\n ]\n}\n\nfunction hasRateLimitBinding(source: string, scope: string, name: string): boolean {\n const header = scope ? `[[env.${scope}.ratelimits]]` : '[[ratelimits]]'\n // Tolerate hand-reformatted spacing and either TOML string quoting so a\n // reinstall never appends a duplicate block Wrangler would reject.\n const escaped = name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const namePattern = new RegExp(\n `^\\\\s*name\\\\s*=\\\\s*(?:\"${escaped}\"|'${escaped}')\\\\s*(?:#.*)?$`,\n 'm',\n )\n let offset = 0\n while ((offset = source.indexOf(header, offset)) >= 0) {\n const end = source.slice(offset + header.length).search(/^\\[/m)\n const blockEnd = end < 0 ? source.length : offset + header.length + end\n if (namePattern.test(source.slice(offset, blockEnd))) return true\n offset += header.length\n }\n return false\n}\n\nfunction rateLimitBindingBlock(\n scope: string,\n binding: NonNullable<FeatureWranglerIntegration['rateLimits']>[number],\n): string {\n const header = scope ? `[[env.${scope}.ratelimits]]` : '[[ratelimits]]'\n return [\n header,\n `name = ${JSON.stringify(binding.name)}`,\n `namespace_id = ${JSON.stringify(binding.namespaceId)}`,\n `simple = { limit = ${binding.limit}, period = ${binding.period} }`,\n ].join('\\n')\n}\n\nfunction unresolvedRoute(\n route: NonNullable<FeatureConfig['route']>,\n config: FeatureConfig,\n reason: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration {\n const roles = routeRolesSuffix(route)\n emit('')\n emit(' Add manually to src/nav.ts:')\n emit(` { path: '${route.path}', label: '${config.name}'${roles} },`)\n return {\n area: 'nav',\n reason,\n steps: [\n `Add { path: '${route.path}', label: '${config.name}'${roles} } to the exported nav array.`,\n ],\n }\n}\n\nfunction routeRolesSuffix(route: NonNullable<FeatureConfig['route']>): string {\n const roles = route.roles?.length ? route.roles : route.protected === false ? [] : ['member']\n return roles.length ? `, roles: [${roles.map((role) => `'${role}' as Role`).join(', ')}]` : ''\n}\n\nfunction integrateRoute(\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): UnresolvedIntegration[] {\n if (!config.route) return []\n const navPath = join(targetDir, 'src', 'nav.ts')\n if (!existsSync(navPath)) {\n return [unresolvedRoute(config.route, config, 'src/nav.ts was not found.', emit)]\n }\n let content = readFileSync(navPath, 'utf-8')\n const routePath = config.route.path\n if (content.includes(`'${routePath}'`)) {\n emit(` Nav already present: ${routePath}`)\n return []\n }\n if (!content.includes(NAV_MARKER)) {\n emit(' Could not auto-wire nav (marker not found in nav.ts)')\n return [\n unresolvedRoute(\n config.route,\n config,\n 'The feature insertion marker was not found in src/nav.ts.',\n emit,\n ),\n ]\n }\n const roles = routeRolesSuffix(config.route)\n const entry = ` { path: '${routePath}', label: '${config.name}'${roles} },`\n content = content.replace(NAV_MARKER, `${NAV_MARKER}\\n${entry}`)\n writeFileSync(navPath, content)\n emit(` Nav wired: ${routePath} (${config.name})`)\n emit(' Route: automatic (file-based routing via src/pages/)')\n return []\n}\n\nconst INSTALL_DIAGNOSTIC_BYTES = 16 * 1024\n\ninterface PackageInstallRun {\n error?: Error\n status: number | null\n diagnosticTail?: string\n}\n\nfunction readDiagnosticTail(outputFd: number): string | undefined {\n const size = fstatSync(outputFd).size\n if (size === 0) return undefined\n const length = Math.min(size, INSTALL_DIAGNOSTIC_BYTES)\n const buffer = Buffer.alloc(length)\n readSync(outputFd, buffer, 0, length, size - length)\n const tail = buffer.toString('utf-8').trim()\n if (!tail) return undefined\n return size > length ? `[last ${length} bytes]\\n${tail}` : tail\n}\n\nfunction runPackageInstall(\n packageManager: string,\n targetDir: string,\n outputVisible: boolean,\n): PackageInstallRun {\n const options = {\n cwd: targetDir,\n shell: process.platform === 'win32',\n }\n if (outputVisible) {\n const child = spawnSync(packageManager, ['install'], { ...options, stdio: 'inherit' })\n return { error: child.error, status: child.status }\n }\n\n // Keep stdout reserved for the command's one-line JSON envelope. Both child\n // streams share a temporary file, then only a fixed-size tail enters memory.\n const captureDir = mkdtempSync(join(tmpdir(), 'deepspace-add-install-'))\n let outputFd: number | undefined\n try {\n outputFd = openSync(join(captureDir, 'output.log'), 'w+')\n const child = spawnSync(packageManager, ['install'], {\n ...options,\n stdio: ['ignore', outputFd, outputFd],\n })\n return {\n error: child.error,\n status: child.status,\n diagnosticTail: readDiagnosticTail(outputFd),\n }\n } finally {\n if (outputFd !== undefined) closeSync(outputFd)\n rmSync(captureDir, { recursive: true, force: true })\n }\n}\n\nfunction integrateDependencies(\n config: FeatureConfig,\n targetDir: string,\n runInstall: boolean,\n outputVisible: boolean,\n emit: FeatureInstallerOutput,\n): {\n added: DependencyAddition[]\n installRan: boolean\n installError?: string\n diagnosticTail?: string\n packageManager: string\n} {\n const packageManager = detectPackageManager(targetDir)\n const declarations: Array<{\n section: DependencySection\n values: Record<string, string> | undefined\n }> = [\n { section: 'dependencies', values: config.dependencies },\n { section: 'devDependencies', values: config.devDependencies },\n ]\n if (declarations.every(({ values }) => !values || Object.keys(values).length === 0)) {\n return { added: [], installRan: false, packageManager }\n }\n\n const packagePath = join(targetDir, 'package.json')\n if (!existsSync(packagePath)) {\n emit(' Could not patch package.json (file not found)')\n return { added: [], installRan: false, packageManager }\n }\n\n let pkg: Record<string, unknown> & {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n }\n try {\n pkg = JSON.parse(readFileSync(packagePath, 'utf-8')) as typeof pkg\n } catch (error) {\n emit(\n ` Could not patch package.json (parse error: ${error instanceof Error ? error.message : String(error)})`,\n )\n return { added: [], installRan: false, packageManager }\n }\n\n const added: DependencyAddition[] = []\n const skipped: string[] = []\n for (const { section, values } of declarations) {\n if (!values) continue\n pkg[section] ??= {}\n for (const [name, version] of Object.entries(values)) {\n if (pkg.dependencies?.[name] || pkg.devDependencies?.[name]) {\n if (!added.some((dependency) => dependency.name === name)) skipped.push(name)\n continue\n }\n pkg[section]![name] = version\n added.push({ name, section, version })\n }\n }\n\n if (added.length === 0) {\n emit(' Dependencies already present')\n } else {\n writeFileSync(packagePath, `${JSON.stringify(pkg, null, 2)}\\n`, 'utf-8')\n emit(` Added to package.json: ${added.map(({ name }) => name).join(', ')}`)\n if (skipped.length) emit(` Already present (kept your version): ${skipped.join(', ')}`)\n }\n\n if (!runInstall) return { added, installRan: false, packageManager }\n emit('')\n emit(` Installing dependencies with ${packageManager}...`)\n const child = runPackageInstall(packageManager, targetDir, outputVisible)\n if (child.error) {\n const error = child.error as NodeJS.ErrnoException\n const reason = error.code === 'ENOENT' ? `${packageManager} not found on PATH` : error.message\n return {\n added,\n installRan: false,\n installError: `Could not launch ${packageManager} (${reason}).`,\n diagnosticTail: child.diagnosticTail,\n packageManager,\n }\n }\n if (child.status !== 0) {\n const diagnostic = child.diagnosticTail ? `\\nDiagnostic tail:\\n${child.diagnosticTail}` : ''\n return {\n added,\n installRan: false,\n installError: `${packageManager} install did not complete (exit ${child.status ?? 'unknown'}).${diagnostic}`,\n diagnosticTail: child.diagnosticTail,\n packageManager,\n }\n }\n return { added, installRan: true, packageManager }\n}\n\nfunction dependencySnapshot(targetDir: string): {\n dependencies: Record<string, unknown>\n devDependencies: Record<string, unknown>\n} {\n try {\n const pkg = JSON.parse(readFileSync(join(targetDir, 'package.json'), 'utf-8')) as {\n dependencies?: Record<string, unknown>\n devDependencies?: Record<string, unknown>\n }\n return {\n dependencies: pkg.dependencies ?? {},\n devDependencies: pkg.devDependencies ?? {},\n }\n } catch {\n return { dependencies: {}, devDependencies: {} }\n }\n}\n\nfunction installedNavFeatures(packageRoot: string, targetDir: string): string[] {\n return listFeatureConfigs(packageRoot)\n .filter((feature) => feature.category === 'nav' && feature.files.length > 0)\n .filter((feature) => {\n const signature = resolveFeatureDestPath(feature.files[0].dest, feature.route)\n return existsSync(join(targetDir, signature))\n })\n .map((feature) => feature.id)\n}\n\nfunction warnNavConflicts(\n packageRoot: string,\n config: FeatureConfig,\n targetDir: string,\n emit: FeatureInstallerOutput,\n): void {\n if (config.category !== 'nav') return\n const present = installedNavFeatures(packageRoot, targetDir)\n if (present.length <= 1) return\n emit('')\n emit(`⚠ Multiple navigation features present (${present.join(', ')}).`)\n emit(' sidebar, topbar, and tree are mutually exclusive — keep one and remove the')\n emit(' others to avoid competing navigation in your layout.')\n}\n\nexport function installFeature(options: FeatureInstallOptions): FeatureInstallOutcome {\n const packageRoot = featurePackageRoot()\n const targetDir = resolveTargetDir(options.targetDir)\n const config = readFeatureConfig(options.feature, packageRoot)\n if (!config) {\n const suggestion = suggestFeature(options.feature, packageRoot)\n return {\n ok: false,\n code: 'unknown_feature',\n error: [\n `Unknown feature: ${options.feature}`,\n ...(suggestion ? [`Did you mean \"${suggestion}\"?`] : []),\n ].join('\\n'),\n data: {\n requestedFeature: options.feature,\n suggestedFeature: suggestion,\n availableFeatures: featureCatalog(packageRoot),\n },\n }\n }\n\n const emit: FeatureInstallerOutput = options.emit ?? (() => undefined)\n emit('')\n emit(`Installing: ${config.name}`)\n emit(` ${config.description ?? ''}`)\n emit(` Target: ${targetDir}`)\n\n const installedFiles = installFiles(packageRoot, config, targetDir, emit)\n integrateIgnore(config, targetDir)\n emit('')\n emit(\n `Copied ${installedFiles.copied} file(s)${\n installedFiles.skipped > 0 ? `, skipped ${installedFiles.skipped} existing` : ''\n }`,\n )\n\n const unresolvedIntegrations = [\n ...integrateSchema(config, targetDir, emit),\n ...integrateActions(config, targetDir, emit),\n ...integrateWrangler(config, targetDir, emit),\n ...integrateCode(config, targetDir, emit),\n ...integrateRoute(config, targetDir, emit),\n ]\n const dependencyResult = integrateDependencies(\n config,\n targetDir,\n options.installDependencies,\n options.emit !== undefined,\n emit,\n )\n\n if (config.instructions?.length) {\n emit('')\n emit('--- Next steps ---')\n emit('')\n config.instructions.forEach((instruction, index) => {\n emit(`${index + 1}. ${instruction}`)\n emit('')\n })\n }\n if (config.patterns?.length) {\n emit('--- Key patterns ---')\n emit('')\n config.patterns.forEach((pattern) => emit(`- ${pattern}`))\n emit('')\n }\n warnNavConflicts(packageRoot, config, targetDir, emit)\n\n const dependenciesAfter = dependencySnapshot(targetDir)\n const declaredDependencies = [\n ...Object.keys(config.dependencies ?? {}),\n ...Object.keys(config.devDependencies ?? {}),\n ]\n const missingDeclarations = declaredDependencies.filter(\n (name) =>\n !(name in dependenciesAfter.dependencies) && !(name in dependenciesAfter.devDependencies),\n )\n const installed =\n installedFiles.files.missing.length === 0 &&\n missingDeclarations.length === 0 &&\n unresolvedIntegrations.length === 0 &&\n dependencyResult.installError === undefined\n const dependencyInstallRequired =\n installed &&\n dependencyResult.added.length > 0 &&\n !options.installDependencies &&\n !dependencyResult.installRan\n\n const data: InstallData = {\n feature: config.id,\n dir: targetDir,\n installed,\n observedChanges: {\n files: installedFiles.files,\n dependencies: {\n added: dependencyResult.added,\n missingDeclarations,\n installRequested: options.installDependencies,\n ...(dependencyResult.diagnosticTail\n ? { diagnosticTail: dependencyResult.diagnosticTail }\n : {}),\n },\n },\n unresolvedIntegrations,\n manifestGuidance: {\n instructions: config.instructions ?? [],\n patterns: config.patterns ?? [],\n agentNotes: config.agentNotes ?? [],\n },\n }\n if (dependencyResult.installError) {\n return {\n ok: false,\n code: 'dependency_install_failed',\n error: dependencyResult.installError,\n data,\n }\n }\n if (unresolvedIntegrations.length > 0) {\n const count = unresolvedIntegrations.length\n return {\n ok: false,\n code: 'manual_integration_required',\n error: `${count} app integration${count === 1 ? '' : 's'} require manual completion. Follow the unresolved integration steps, then run your checks.`,\n data,\n }\n }\n\n return {\n ok: true,\n data,\n ...(dependencyInstallRequired\n ? {\n action: {\n cwd: targetDir,\n argv: [dependencyResult.packageManager, 'install'],\n },\n }\n : {}),\n }\n}\n","export interface CommandTreeNode {\n subCommands?: Record<string, CommandTreeNode>\n}\n\nexport interface UnknownCommand {\n attemptedPath: string[]\n helpPath: string[]\n suggestion: string[]\n /**\n * May the suggestion be handed back as a runnable `action`, or must it stay\n * prose? Only a whole command path that arrived as ONE quoted token, to a\n * non-destructive leaf, is certain — nothing there is being guessed. Every\n * ranked or exact-leaf guess stays prose: running it verbatim can be a\n * different act (`undeploy` ranks `deploy`), and no distance threshold\n * separates those cases.\n */\n executable: boolean\n /** Everything the caller wrote AFTER the bad token — the positionals the\n * corrected command still needs. Without these the suggested action drops\n * them and refuses `missing_argument` when run. */\n remainder: string[]\n /** The whole command arrived as ONE quoted argv token, e.g. `\"auth whoami\"`. */\n quotedToken?: true\n}\n\n/**\n * A single argv token holding a whole command path — `deepspace \"auth whoami\"`.\n * Almost always over-quoting in a script or a shell that does not word-split,\n * and the nearest-name search answers it uselessly: the token IS the command,\n * so the suggestion comes back reading identical to what was typed.\n */\nfunction splitTokenPath(\n token: string,\n table: Record<string, CommandTreeNode>,\n): string[] | null {\n const parts = token.trim().split(/\\s+/)\n if (parts.length < 2) return null\n let node: Record<string, CommandTreeNode> | undefined = table\n for (const part of parts) {\n const next: CommandTreeNode | undefined = node?.[part]\n if (!next) return null\n node = next.subCommands\n }\n return parts\n}\n\n/**\n * Verbs that destroy something. A guess is a guess: `rm` ranks `app files rm`\n * first and `delete` ranks `secrets delete` first, so an agent that pastes the\n * offered action deletes data it never named. These stay in the prose (\"did you\n * mean …?\") and are withheld from `action`, which is the executable channel —\n * a destructive command has to be typed on purpose.\n */\nconst DESTRUCTIVE_VERBS = new Set(['rm', 'delete', 'remove', 'drop', 'clear', 'undeploy', 'kill', 'logout'])\n\n/**\n * Damerau-Levenshtein (optimal string alignment) for short command names.\n *\n * Plain Levenshtein charges a TRANSPOSITION two edits, which is how `puhs`\n * tied `push` with `pull` and — losing the tiebreak alphabetically —\n * suggested the wrong verb for the single most common kind of typo. Adjacent\n * swaps cost one.\n */\nexport function editDistance(a: string, b: string): number {\n const left = a.toLowerCase()\n const right = b.toLowerCase()\n const dp = Array.from({ length: left.length + 1 }, (_, i) => [\n i,\n ...new Array<number>(right.length).fill(0),\n ])\n for (let j = 1; j <= right.length; j++) dp[0][j] = j\n for (let i = 1; i <= left.length; i++) {\n for (let j = 1; j <= right.length; j++) {\n dp[i][j] = Math.min(\n dp[i - 1][j] + 1,\n dp[i][j - 1] + 1,\n dp[i - 1][j - 1] + (left[i - 1] === right[j - 1] ? 0 : 1),\n )\n if (\n i > 1 &&\n j > 1 &&\n left[i - 1] === right[j - 2] &&\n left[i - 2] === right[j - 1]\n ) {\n dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + 1)\n }\n }\n }\n return dp[left.length][right.length]\n}\n\nfunction commandPaths(table: Record<string, CommandTreeNode>, prefix: string[] = []): string[][] {\n const paths: string[][] = []\n for (const [name, command] of Object.entries(table)) {\n const path = [...prefix, name]\n paths.push(path)\n if (command.subCommands) paths.push(...commandPaths(command.subCommands, path))\n }\n return paths\n}\n\n/**\n * Pick a command from the whole remaining tree, comparing the unknown token to\n * every command name. This lets a misplaced leaf such as top-level `migrate`\n * resolve to `app migrate`, not merely to the nearest top-level group.\n */\nexport function closestCommandPath(\n input: string,\n table: Record<string, CommandTreeNode>,\n): string[] | null {\n const ranked = commandPaths(table)\n .map((path) => ({ path, distance: editDistance(input, path.at(-1) ?? '') }))\n .sort(\n (a, b) =>\n a.distance - b.distance ||\n a.path.length - b.path.length ||\n a.path.join(' ').localeCompare(b.path.join(' ')),\n )\n return ranked[0]?.path ?? null\n}\n\nfunction takeLeadingPositionals(rest: string[]): string[] {\n const stop = rest.findIndex((token) => token.startsWith('-'))\n return stop === -1 ? rest : rest.slice(0, stop)\n}\n\n/**\n * Find the first invalid command token. Once a leaf command is reached, its\n * remaining positional arguments belong to that command and are not checked.\n */\nexport function findUnknownCommand(\n argv: string[],\n rootCommands: Record<string, CommandTreeNode>,\n): UnknownCommand | null {\n let table: Record<string, CommandTreeNode> | undefined = rootCommands\n const accepted: string[] = []\n\n for (const [index, token] of argv.entries()) {\n if (!table || token.startsWith('-')) return null\n const command: CommandTreeNode | undefined = table[token]\n if (!command) {\n // Ranking, best evidence first. An UNAMBIGUOUS exact leaf name found\n // deeper in the tree beats everything: `app add alice@example.com`\n // means `app collaborators add`, and the alias table would otherwise\n // read `add` as `create` and point a collaborator invite at the\n // scaffolder. A leaf name carried by two groups (`cancel`, under both\n // `transfer` and `collaborators`) is NOT evidence — `closestCommandPath`\n // would settle that tie alphabetically — so it falls through to ranking\n // like any other guess.\n const exactAll = commandPaths(table).filter((path) => path.at(-1) === token)\n const exactHit = exactAll.length === 1 ? exactAll[0] : null\n // A whole command path quoted into one token (`\"auth whoami\"`), not a\n // lexical guess against a string with spaces.\n const split = splitTokenPath(token, table)\n // The same exact-leaf rule, widened to the WHOLE tree when this group\n // has no exact match of its own: `auth status` means the top-level\n // `status` (an exact name), not the fuzzy-nearest sibling — which was\n // `logout`, a destructive guess for a read verb.\n const rootExactAll =\n exactHit || split ? [] : commandPaths(rootCommands).filter((path) => path.at(-1) === token)\n // Prefer the SHALLOWEST exact match rather than requiring global\n // uniqueness: `status` exists three times in the real tree (top-level,\n // `workspace status`, `app transfer status`), and demanding one hit\n // sent `auth status` to the fuzzy sibling — `logout`, a destructive\n // guess for a read verb. Ambiguity only remains when two matches share\n // the minimum depth; then no exact guess is safe.\n const minDepth = Math.min(...rootExactAll.map((path) => path.length))\n const shallowest = rootExactAll.filter((path) => path.length === minDepth)\n const rootExact = shallowest.length === 1 ? shallowest[0] : null\n const relativeSuggestion = exactHit ?? split ?? (rootExact ? null : closestCommandPath(token, table))\n const suggestionPath = relativeSuggestion ? [...accepted, ...relativeSuggestion] : rootExact\n if (!suggestionPath) return null\n // Only the quoted-token case is certain enough to hand back as a\n // runnable `action` (see `executable` above); everything else is prose.\n const guessed = suggestionPath.at(-1) ?? ''\n return {\n attemptedPath: ['deepspace', ...accepted, token],\n helpPath: ['deepspace', ...accepted],\n suggestion: ['deepspace', ...suggestionPath],\n executable: split !== null && !DESTRUCTIVE_VERBS.has(guessed),\n // POSITIONALS ONLY. The remainder exists so the corrected verb keeps\n // the arguments it needs; carrying flags too meant `auth logn --email\n // a@b --password hunter2` echoed the password into `action.argv`, and\n // agents persist envelopes. Cut at the first `-` token.\n remainder: takeLeadingPositionals(argv.slice(index + 1)),\n ...(split ? { quotedToken: true as const } : {}),\n }\n }\n accepted.push(token)\n table = command.subCommands\n }\n\n return null\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun'\n\n/** Resolve the repository's package manager from its explicit packageManager\n * field first, then its lockfile. npm is the conservative fallback. */\nexport function detectPackageManager(appDir: string): PackageManager {\n try {\n const pkg = JSON.parse(readFileSync(join(appDir, 'package.json'), 'utf-8')) as {\n packageManager?: unknown\n }\n const name = typeof pkg.packageManager === 'string' ? pkg.packageManager.split('@')[0] : ''\n if (name === 'npm' || name === 'pnpm' || name === 'yarn' || name === 'bun') return name\n } catch {\n // Missing/malformed package.json falls through to lockfile detection.\n }\n if (existsSync(join(appDir, 'pnpm-lock.yaml'))) return 'pnpm'\n if (existsSync(join(appDir, 'yarn.lock'))) return 'yarn'\n if (existsSync(join(appDir, 'bun.lock')) || existsSync(join(appDir, 'bun.lockb'))) return 'bun'\n return 'npm'\n}\n\nexport function installCommand(appDir: string): string {\n return `${detectPackageManager(appDir)} install`\n}\n"],"mappings":"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","names":["existsSync","readFileSync","join","join","existsSync","readFileSync"]}
package/dist/index.d.ts CHANGED
@@ -576,11 +576,6 @@ declare const MSG: {
576
576
  readonly PRESENCE_JOIN: "presence.join";
577
577
  readonly PRESENCE_LEAVE: "presence.leave";
578
578
  readonly PRESENCE_UPDATE: "presence.update";
579
- readonly GW_SCOPE_CONNECT: "gateway.scope_connect";
580
- readonly GW_SCOPE_DISCONNECT: "gateway.scope_disconnect";
581
- readonly GW_SCOPE_ERROR: "gateway.scope_error";
582
- readonly GW_TOKEN_REFRESH: "gateway.token_refresh";
583
- readonly GW_USER_UPDATE: "gateway.user_update";
584
579
  };
585
580
  /**
586
581
  * Type of any message type constant — the union of every string literal
@@ -628,7 +623,7 @@ declare const RECORD_NOT_FOUND = "Record not found";
628
623
  * runtime. This module pairs every constant with its payload type, so
629
624
  * that:
630
625
  *
631
- * 1. Building a message with `clientBuild.gameInput(...)` is payload-
626
+ * 1. Building a message with `clientBuild.canvasAdd(...)` is payload-
632
627
  * checked at the call site — the compiler refuses to ship a wrong
633
628
  * shape.
634
629
  *
@@ -677,7 +672,7 @@ declare const RECORD_NOT_FOUND = "Record not found";
677
672
  *
678
673
  * Where payload shapes are stable + narrow (ids, flags), we type them
679
674
  * precisely. Where they're opaque or escape the protocol layer (record
680
- * data blobs, Yjs binary frames, game-engine state), we use `unknown` and
675
+ * data blobs, Yjs binary frames, canvas shapes), we use `unknown` and
681
676
  * defer narrowing to the caller. This is intentional: over-typing opaque
682
677
  * payloads would require the protocol layer to import application types
683
678
  * and defeat the "thin wire contract" goal.
@@ -685,7 +680,7 @@ declare const RECORD_NOT_FOUND = "Record not found";
685
680
 
686
681
  /**
687
682
  * The outer shape of every wire message. `T` is the string discriminator
688
- * (e.g. `"game.input"`) — keeping it as a generic literal type lets the
683
+ * (e.g. `"canvas.add"`) — keeping it as a generic literal type lets the
689
684
  * discriminated-union narrowing in `dispatch()` pick the right payload.
690
685
  *
691
686
  * Callers extending the protocol should pass a string-literal type for
@@ -763,15 +758,7 @@ type ClientMessage = BaseMessage<typeof MSG.SUBSCRIBE, {
763
758
  jobId: string;
764
759
  }> | BaseMessage<typeof MSG.JOB_RETRY, {
765
760
  jobId: string;
766
- }> | BaseMessage<typeof MSG.PRESENCE_UPDATE, Record<string, unknown>> | BaseMessage<typeof MSG.GW_SCOPE_CONNECT, {
767
- scopeType: string;
768
- scopeId: string;
769
- }> | BaseMessage<typeof MSG.GW_SCOPE_DISCONNECT, {
770
- scopeType: string;
771
- scopeId: string;
772
- }> | BaseMessage<typeof MSG.GW_TOKEN_REFRESH, {
773
- token: string;
774
- }>;
761
+ }> | BaseMessage<typeof MSG.PRESENCE_UPDATE, Record<string, unknown>>;
775
762
  /**
776
763
  * Every message the server can send. Room and handler `send` / `broadcast`
777
764
  * signatures are tightened to this union so outbound payloads are
@@ -865,11 +852,7 @@ type ServerMessage = BaseMessage<typeof MSG.QUERY_RESULT, {
865
852
  }> | BaseMessage<typeof MSG.PRESENCE_UPDATE, {
866
853
  userId: string;
867
854
  state: Record<string, unknown>;
868
- }> | BaseMessage<typeof MSG.GW_SCOPE_ERROR, {
869
- scopeType: string;
870
- scopeId: string;
871
- error: string;
872
- }> | BaseMessage<typeof MSG.GW_USER_UPDATE, unknown>;
855
+ }>;
873
856
  /**
874
857
  * Any wire message, regardless of direction. Use this only when the code
875
858
  * path genuinely doesn't care — otherwise pick `ClientMessage` or
@@ -1036,26 +1019,6 @@ declare const clientBuild: {
1036
1019
  readonly type: "presence.update";
1037
1020
  readonly payload: Record<string, unknown>;
1038
1021
  };
1039
- gwScopeConnect: (scopeType: string, scopeId: string) => {
1040
- readonly type: "gateway.scope_connect";
1041
- readonly payload: {
1042
- readonly scopeType: string;
1043
- readonly scopeId: string;
1044
- };
1045
- };
1046
- gwScopeDisconnect: (scopeType: string, scopeId: string) => {
1047
- readonly type: "gateway.scope_disconnect";
1048
- readonly payload: {
1049
- readonly scopeType: string;
1050
- readonly scopeId: string;
1051
- };
1052
- };
1053
- gwTokenRefresh: (token: string) => {
1054
- readonly type: "gateway.token_refresh";
1055
- readonly payload: {
1056
- readonly token: string;
1057
- };
1058
- };
1059
1022
  };
1060
1023
  /** Factories for every server → client message. Used by room DOs and
1061
1024
  * handler modules so server broadcasts are payload-checked too. Opaque
@@ -1299,18 +1262,6 @@ declare const serverBuild: {
1299
1262
  readonly state: Record<string, unknown>;
1300
1263
  };
1301
1264
  };
1302
- gwScopeError: (scopeType: string, scopeId: string, error: string) => {
1303
- readonly type: "gateway.scope_error";
1304
- readonly payload: {
1305
- readonly scopeType: string;
1306
- readonly scopeId: string;
1307
- readonly error: string;
1308
- };
1309
- };
1310
- gwUserUpdate: (user: unknown) => {
1311
- readonly type: "gateway.user_update";
1312
- readonly payload: unknown;
1313
- };
1314
1265
  };
1315
1266
  /**
1316
1267
  * Handler map keyed by a message's string `type`. Every key maps to the
@@ -1340,7 +1291,7 @@ declare function dispatch<M extends BaseMessage<string, unknown> = ProtocolMessa
1340
1291
  /**
1341
1292
  * Serialise a typed-built message for `ws.send`. A tiny wrapper around
1342
1293
  * `JSON.stringify` kept around so call sites read as
1343
- * `ws.send(encode(clientBuild.gameInput(...)))` rather than paying
1294
+ * `ws.send(encode(clientBuild.canvasAdd(...)))` rather than paying
1344
1295
  * attention to stringify arguments.
1345
1296
  */
1346
1297
  declare function encode<M extends BaseMessage<string, unknown>>(message: M): string;
package/dist/index.js CHANGED
@@ -561,7 +561,7 @@ var MSG = {
561
561
  USER_UPDATE: "user.update",
562
562
  // ---- Auth signal -----------------------------------------------------
563
563
  // Server → client one-shot on connect from rooms that enforce role-based
564
- // writes (Canvas, Game, Cron). Tells the client whether this connection
564
+ // writes (Canvas, Cron). Tells the client whether this connection
565
565
  // can write so its hook can disable local write APIs and the UI can
566
566
  // render controls accordingly. Without this, a viewer's click would
567
567
  // round-trip to the server and silently come back as ERROR.
@@ -605,13 +605,7 @@ var MSG = {
605
605
  PRESENCE_SYNC: "presence.sync",
606
606
  PRESENCE_JOIN: "presence.join",
607
607
  PRESENCE_LEAVE: "presence.leave",
608
- PRESENCE_UPDATE: "presence.update",
609
- // ---- Gateway multiplexing --------------------------------------------
610
- GW_SCOPE_CONNECT: "gateway.scope_connect",
611
- GW_SCOPE_DISCONNECT: "gateway.scope_disconnect",
612
- GW_SCOPE_ERROR: "gateway.scope_error",
613
- GW_TOKEN_REFRESH: "gateway.token_refresh",
614
- GW_USER_UPDATE: "gateway.user_update"
608
+ PRESENCE_UPDATE: "presence.update"
615
609
  };
616
610
  var MSG_YJS_SYNC = 22;
617
611
  var MSG_YJS_AWARENESS = 23;
@@ -665,11 +659,7 @@ var clientBuild = {
665
659
  jobCancel: (jobId) => ({ type: MSG.JOB_CANCEL, payload: { jobId } }),
666
660
  jobRetry: (jobId) => ({ type: MSG.JOB_RETRY, payload: { jobId } }),
667
661
  // Presence
668
- presenceUpdate: (state) => ({ type: MSG.PRESENCE_UPDATE, payload: state }),
669
- // Gateway
670
- gwScopeConnect: (scopeType, scopeId) => ({ type: MSG.GW_SCOPE_CONNECT, payload: { scopeType, scopeId } }),
671
- gwScopeDisconnect: (scopeType, scopeId) => ({ type: MSG.GW_SCOPE_DISCONNECT, payload: { scopeType, scopeId } }),
672
- gwTokenRefresh: (token) => ({ type: MSG.GW_TOKEN_REFRESH, payload: { token } })
662
+ presenceUpdate: (state) => ({ type: MSG.PRESENCE_UPDATE, payload: state })
673
663
  };
674
664
  var serverBuild = {
675
665
  // Records / CRUD
@@ -733,13 +723,7 @@ var serverBuild = {
733
723
  presenceSync: (peers) => ({ type: MSG.PRESENCE_SYNC, payload: { peers } }),
734
724
  presenceJoin: (peer) => ({ type: MSG.PRESENCE_JOIN, payload: { peer } }),
735
725
  presenceLeave: (userId) => ({ type: MSG.PRESENCE_LEAVE, payload: { userId } }),
736
- presenceUpdate: (userId, state) => ({ type: MSG.PRESENCE_UPDATE, payload: { userId, state } }),
737
- // Gateway
738
- gwScopeError: (scopeType, scopeId, error) => ({
739
- type: MSG.GW_SCOPE_ERROR,
740
- payload: { scopeType, scopeId, error }
741
- }),
742
- gwUserUpdate: (user) => ({ type: MSG.GW_USER_UPDATE, payload: user })
726
+ presenceUpdate: (userId, state) => ({ type: MSG.PRESENCE_UPDATE, payload: { userId, state } })
743
727
  };
744
728
  function dispatch(raw, handlers) {
745
729
  let msg;