deepspace 0.19.1 → 0.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/cli.js +85 -21
- package/dist/cli.js.map +1 -1
- package/dist/feature-installer.js +14 -5
- package/dist/feature-installer.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +37 -11
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/worker.d.ts +1 -1
- package/features/admin-page/feature.json +3 -4
- package/features/cron/feature.json +8 -5
- package/features/tasks/src/TasksPage.tsx +1 -1
- package/features/tasks/src/tasks-schema.ts +1 -1
- package/package.json +1 -1
- package/features/cron/src/cron.ts +0 -25
|
@@ -316,7 +316,9 @@ function integrateCode(config, targetDir, emit) {
|
|
|
316
316
|
if (insertion.import && !content.includes(insertion.import)) {
|
|
317
317
|
const importIndex = content.search(/^import\s/m);
|
|
318
318
|
content = `${content.slice(0, importIndex < 0 ? 0 : importIndex)}${insertion.import}
|
|
319
|
-
${content.slice(
|
|
319
|
+
${content.slice(
|
|
320
|
+
importIndex < 0 ? 0 : importIndex
|
|
321
|
+
)}`;
|
|
320
322
|
}
|
|
321
323
|
const currentMarkerIndex = content.indexOf(insertion.marker);
|
|
322
324
|
const insertAt = insertion.placement === "before" ? currentMarkerIndex : currentMarkerIndex + insertion.marker.length;
|
|
@@ -470,15 +472,22 @@ ${css}`;
|
|
|
470
472
|
return unresolved;
|
|
471
473
|
}
|
|
472
474
|
function unresolvedRoute(route, config, reason, emit) {
|
|
475
|
+
const roles = routeRolesSuffix(route);
|
|
473
476
|
emit("");
|
|
474
477
|
emit(" Add manually to src/nav.ts:");
|
|
475
|
-
emit(` { path: '${route.path}', label: '${config.name}' },`);
|
|
478
|
+
emit(` { path: '${route.path}', label: '${config.name}'${roles} },`);
|
|
476
479
|
return {
|
|
477
480
|
area: "nav",
|
|
478
481
|
reason,
|
|
479
|
-
steps: [
|
|
482
|
+
steps: [
|
|
483
|
+
`Add { path: '${route.path}', label: '${config.name}'${roles} } to the exported nav array.`
|
|
484
|
+
]
|
|
480
485
|
};
|
|
481
486
|
}
|
|
487
|
+
function routeRolesSuffix(route) {
|
|
488
|
+
const roles = route.roles?.length ? route.roles : route.protected === false ? [] : ["member"];
|
|
489
|
+
return roles.length ? `, roles: [${roles.map((role) => `'${role}' as Role`).join(", ")}]` : "";
|
|
490
|
+
}
|
|
482
491
|
function integrateRoute(config, targetDir, emit) {
|
|
483
492
|
if (!config.route) return [];
|
|
484
493
|
const navPath = join2(targetDir, "src", "nav.ts");
|
|
@@ -502,7 +511,7 @@ function integrateRoute(config, targetDir, emit) {
|
|
|
502
511
|
)
|
|
503
512
|
];
|
|
504
513
|
}
|
|
505
|
-
const roles = config.route
|
|
514
|
+
const roles = routeRolesSuffix(config.route);
|
|
506
515
|
const entry = ` { path: '${routePath}', label: '${config.name}'${roles} },`;
|
|
507
516
|
content = content.replace(NAV_MARKER, `${NAV_MARKER}
|
|
508
517
|
${entry}`);
|
|
@@ -698,7 +707,7 @@ function installFeature(options) {
|
|
|
698
707
|
);
|
|
699
708
|
if (config.instructions?.length) {
|
|
700
709
|
emit("");
|
|
701
|
-
emit("---
|
|
710
|
+
emit("--- Next steps ---");
|
|
702
711
|
emit("");
|
|
703
712
|
config.instructions.forEach((instruction, index) => {
|
|
704
713
|
emit(`${index + 1}. ${instruction}`);
|
|
@@ -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?: { path?: string; protected?: boolean }\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${\n content.slice(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 emit('')\n emit(' Add manually to src/nav.ts:')\n emit(` { path: '${route.path}', label: '${config.name}' },`)\n return {\n area: 'nav',\n reason,\n steps: [`Add { path: '${route.path}', label: '${config.name}' } to the exported nav array.`],\n }\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 = config.route.protected === false ? '' : \", roles: ['member' as Role]\"\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('--- Manual wiring needed ---')\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/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"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ interface RolePermissions {
|
|
|
76
76
|
create: boolean;
|
|
77
77
|
update: PermissionLevel;
|
|
78
78
|
delete: PermissionLevel;
|
|
79
|
-
/** If set, only these columns can be updated by this role. */
|
|
79
|
+
/** If set, only these caller-supplied columns can be created or updated by this role. */
|
|
80
80
|
writableFields?: string[];
|
|
81
81
|
}
|
|
82
82
|
interface CollectionSchema {
|
package/dist/index.js
CHANGED
|
@@ -3440,22 +3440,33 @@ function usePresenceRoom(scopeId) {
|
|
|
3440
3440
|
let ws = null;
|
|
3441
3441
|
let reconnectTimer = null;
|
|
3442
3442
|
let alive = true;
|
|
3443
|
+
let browserOnline = typeof navigator === "undefined" || navigator.onLine;
|
|
3444
|
+
let connecting = false;
|
|
3443
3445
|
const connect = async () => {
|
|
3444
|
-
if (!alive) return;
|
|
3445
|
-
|
|
3446
|
-
|
|
3446
|
+
if (!alive || !browserOnline || connecting) return;
|
|
3447
|
+
if (ws?.readyState === WebSocket.CONNECTING || ws?.readyState === WebSocket.OPEN) return;
|
|
3448
|
+
connecting = true;
|
|
3449
|
+
let token;
|
|
3450
|
+
try {
|
|
3451
|
+
token = await tokenProvider();
|
|
3452
|
+
} finally {
|
|
3453
|
+
connecting = false;
|
|
3454
|
+
}
|
|
3455
|
+
if (!alive || !browserOnline) return;
|
|
3447
3456
|
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
3448
3457
|
const baseUrl = `${protocol}//${window.location.host}`;
|
|
3449
3458
|
const url = new URL(`/ws/presence/${encodeURIComponent(scopeId)}`, baseUrl);
|
|
3450
3459
|
if (token) url.searchParams.set("token", token);
|
|
3451
3460
|
wsLog("connecting", `presence:${scopeId}`);
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3461
|
+
const socket = new WebSocket(url.toString());
|
|
3462
|
+
ws = socket;
|
|
3463
|
+
wsRef.current = socket;
|
|
3464
|
+
socket.onopen = () => {
|
|
3465
|
+
if (ws !== socket) return socket.close();
|
|
3455
3466
|
wsLog("connected", `presence:${scopeId}`);
|
|
3456
3467
|
setConnected(true);
|
|
3457
3468
|
};
|
|
3458
|
-
|
|
3469
|
+
socket.onmessage = (event) => {
|
|
3459
3470
|
dispatch(event.data, {
|
|
3460
3471
|
[MSG.PRESENCE_SYNC]: (p) => {
|
|
3461
3472
|
setPeers(p.peers);
|
|
@@ -3476,19 +3487,34 @@ function usePresenceRoom(scopeId) {
|
|
|
3476
3487
|
}
|
|
3477
3488
|
});
|
|
3478
3489
|
};
|
|
3479
|
-
|
|
3490
|
+
socket.onclose = () => {
|
|
3491
|
+
if (ws !== socket) return;
|
|
3480
3492
|
wsLog("disconnected", `presence:${scopeId}`);
|
|
3493
|
+
ws = null;
|
|
3481
3494
|
wsRef.current = null;
|
|
3482
3495
|
setConnected(false);
|
|
3483
|
-
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
3496
|
+
if (alive && browserOnline) reconnectTimer = setTimeout(connect, 1e3);
|
|
3484
3497
|
};
|
|
3485
|
-
|
|
3498
|
+
socket.onerror = () => socket.close();
|
|
3486
3499
|
};
|
|
3487
|
-
|
|
3500
|
+
const handleOffline = () => {
|
|
3501
|
+
browserOnline = false;
|
|
3502
|
+
setConnected(false);
|
|
3503
|
+
ws?.close();
|
|
3504
|
+
};
|
|
3505
|
+
const handleOnline = () => {
|
|
3506
|
+
browserOnline = true;
|
|
3507
|
+
void connect();
|
|
3508
|
+
};
|
|
3509
|
+
window.addEventListener("offline", handleOffline);
|
|
3510
|
+
window.addEventListener("online", handleOnline);
|
|
3511
|
+
void connect();
|
|
3488
3512
|
return () => {
|
|
3489
3513
|
wsLog("closing", `presence:${scopeId}`);
|
|
3490
3514
|
alive = false;
|
|
3491
3515
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
3516
|
+
window.removeEventListener("offline", handleOffline);
|
|
3517
|
+
window.removeEventListener("online", handleOnline);
|
|
3492
3518
|
if (ws) {
|
|
3493
3519
|
ws.onclose = null;
|
|
3494
3520
|
ws.onmessage = null;
|