diff --git a/CLAUDE.md b/CLAUDE.md index fca80de..eb2a165 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,7 +11,7 @@ The extension display name is **ERD Studio** (package name `erd-studio`). ERD domain files live at `{project_root}/.erd-studio/{layer}/{domain}.json`. Each file is a unified domain containing the logical stage data. The custom editor activates for files matching: - `**/.erd-studio/*/*.json` -The base directory is configurable via the `dbtSemantic.semanticDir` setting (default: `.erd-studio`). +The base directory is configurable via the `erdStudio.semanticDir` setting (default: `.erd-studio`). ``` .erd-studio/ @@ -24,16 +24,12 @@ The base directory is configurable via the `dbtSemantic.semanticDir` setting (de └── reporting.json ``` -### Legacy Internal Identifiers +### Internal Identifiers -The following internal identifiers still use the legacy `dbtSemantic` prefix and must **not** be renamed (doing so would break existing user settings, keybindings, and stored state): +All internal identifiers use the `erdStudio` prefix (`erd-studio` for the activity bar container id), with the command palette category `"ERD Studio"`. The extension was originally published with a `dbtSemantic` prefix; two compatibility shims keep pre-rename users working and must **not** be removed: -- **Command IDs**: `dbtSemantic.createDomain`, `dbtSemantic.openDomain`, `dbtSemantic.deleteDomain`, `dbtSemantic.refreshManifest`, `dbtSemantic.renameDomain`, `dbtSemantic.addLayer`, `dbtSemantic.editLayer`, `dbtSemantic.removeLayer`, `dbtSemantic.initializeLayerConfig`, `dbtSemantic.setupSemanticDirectory`, `dbtSemantic.installCodingHarness` -- **View IDs**: `dbt-semantic` (activity bar container), `dbtSemantic.domainTree` -- **Custom editor viewType**: `dbtSemantic.domainEditor` -- **Setting keys**: `dbtSemantic.projectPath`, `dbtSemantic.semanticDir` -- **Color IDs**: `dbtSemantic.layer.bronze`, `dbtSemantic.layer.silver`, `dbtSemantic.layer.gold`, `dbtSemantic.layer.platinum`, `dbtSemantic.layer.custom` -- **Command category**: `"category": "dbt"` in package.json command contributions +- **Legacy command aliases**: every `erdStudio.*` command is also registered in code as `dbtSemantic.*` (see `LEGACY_ALIASED_COMMANDS` at the end of `activate()` in `src/extension.ts`) so old keybindings keep working. These are code-only registrations — never contribute them in package.json. +- **Legacy setting fallback**: settings are read via `getErdStudioSetting()` (`src/services/configService.ts`), which prefers explicit `erdStudio.*` values and falls back to explicit `dbtSemantic.*` values. The deprecated `dbtSemantic.projectPath` / `dbtSemantic.semanticDir` entries in package.json carry `markdownDeprecationMessage` and must stay contributed. Never read settings with `getConfiguration('erdStudio').get(...)` directly — always use the helper. ## Build & Test Commands @@ -140,7 +136,7 @@ Discrepancy statuses for models/columns/relationships: `matched`, `extra`, `miss ## Harness Versioning -AI coding harness files (installed via `dbtSemantic.installCodingHarness`) embed a version marker to track staleness: +AI coding harness files (installed via `erdStudio.installCodingHarness`) embed a version marker to track staleness: ``` diff --git a/package.json b/package.json index b022a85..b2a5810 100644 --- a/package.json +++ b/package.json @@ -32,112 +32,112 @@ "contributes": { "commands": [ { - "command": "dbtSemantic.createDomain", + "command": "erdStudio.createDomain", "title": "Create Semantic Domain", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.setupSemanticDirectory", + "command": "erdStudio.setupSemanticDirectory", "title": "Set Up Semantic Domains Directory", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.openDomain", + "command": "erdStudio.openDomain", "title": "Open Semantic Domain", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.deleteDomain", + "command": "erdStudio.deleteDomain", "title": "Delete Semantic Domain", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.refreshManifest", + "command": "erdStudio.refreshManifest", "title": "Refresh Manifest", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.renameDomain", + "command": "erdStudio.renameDomain", "title": "Rename Semantic Domain", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.addLayer", + "command": "erdStudio.addLayer", "title": "Layer +", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.editLayer", + "command": "erdStudio.editLayer", "title": "Edit Layer", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.removeLayer", + "command": "erdStudio.removeLayer", "title": "Remove Layer", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.initializeLayerConfig", + "command": "erdStudio.initializeLayerConfig", "title": "Initialize Layer Configuration", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.installCodingHarness", + "command": "erdStudio.installCodingHarness", "title": "Install AI Coding Harness", - "category": "dbt", + "category": "ERD Studio", "icon": "$(hubot)" }, { - "command": "dbtSemantic.syncDomainTags", + "command": "erdStudio.syncDomainTags", "title": "Regenerate dbt selectors.yml", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.stripLegacyDomainTags", + "command": "erdStudio.stripLegacyDomainTags", "title": "Strip Legacy Domain Tags from Model YAMLs", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.migrateToV5", + "command": "erdStudio.migrateToV5", "title": "Migrate Domains to Central Model Store", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.deleteLogicalModel", + "command": "erdStudio.deleteLogicalModel", "title": "Delete Model", - "category": "dbt" + "category": "ERD Studio" }, { - "command": "dbtSemantic.revealLogicalModel", + "command": "erdStudio.revealLogicalModel", "title": "Reveal in Explorer", - "category": "dbt" + "category": "ERD Studio" } ], "viewsContainers": { "activitybar": [ { - "id": "dbt-semantic", + "id": "erd-studio", "title": "ERD Studio", "icon": "media/icon-sidebar.svg" } ] }, "views": { - "dbt-semantic": [ + "erd-studio": [ { - "id": "dbtSemantic.domainTree", + "id": "erdStudio.domainTree", "name": "ERD Studio" }, { - "id": "dbtSemantic.modelLibrary", + "id": "erdStudio.modelLibrary", "name": "Model Library", - "when": "dbtSemantic.hasLogicalModelsDir" + "when": "erdStudio.hasLogicalModelsDir" } ] }, "colors": [ { - "id": "dbtSemantic.layer.bronze", + "id": "erdStudio.layer.bronze", "description": "Color for bronze layer folders", "defaults": { "dark": "#cd7f32", @@ -146,7 +146,7 @@ } }, { - "id": "dbtSemantic.layer.silver", + "id": "erdStudio.layer.silver", "description": "Color for silver layer folders", "defaults": { "dark": "#a0a0a0", @@ -155,7 +155,7 @@ } }, { - "id": "dbtSemantic.layer.gold", + "id": "erdStudio.layer.gold", "description": "Color for gold layer folders", "defaults": { "dark": "#d4a800", @@ -164,7 +164,7 @@ } }, { - "id": "dbtSemantic.layer.platinum", + "id": "erdStudio.layer.platinum", "description": "Color for platinum layer folders", "defaults": { "dark": "#e5e4e2", @@ -173,7 +173,7 @@ } }, { - "id": "dbtSemantic.layer.custom", + "id": "erdStudio.layer.custom", "description": "Color for custom layer folders", "defaults": { "dark": "#6a9fb5", @@ -184,17 +184,17 @@ ], "viewsWelcome": [ { - "view": "dbtSemantic.domainTree", - "contents": "No ERD domains found.\n\nERD Studio lets you design your data warehouse visually across two stages:\n\n**Logical** — columns, data types, FK keys, and design rationale\n**Physical** — read-only view of what's built in dbt\n\n[Set Up ERD Studio](command:dbtSemantic.setupSemanticDirectory)\n\nCreates the .erd-studio directory structure and your first domain.\n\n[Install AI Coding Harness](command:dbtSemantic.installCodingHarness)\n\nAdd ERD Studio schema reference to Claude, Copilot, Gemini, or Codex." + "view": "erdStudio.domainTree", + "contents": "No ERD domains found.\n\nERD Studio lets you design your data warehouse visually across two stages:\n\n**Logical** — columns, data types, FK keys, and design rationale\n**Physical** — read-only view of what's built in dbt\n\n[Set Up ERD Studio](command:erdStudio.setupSemanticDirectory)\n\nCreates the .erd-studio directory structure and your first domain.\n\n[Install AI Coding Harness](command:erdStudio.installCodingHarness)\n\nAdd ERD Studio schema reference to Claude, Copilot, Gemini, or Codex." }, { - "view": "dbtSemantic.modelLibrary", + "view": "erdStudio.modelLibrary", "contents": "No logical models found.\n\nModels are stored as YAML files in .erd-studio/logical-models/.\n\nAdd models to a domain using the ERD editor to create them here." } ], "customEditors": [ { - "viewType": "dbtSemantic.domainEditor", + "viewType": "erdStudio.domainEditor", "displayName": "Semantic Domain Editor", "selector": [ { @@ -210,45 +210,45 @@ "menus": { "view/item/context": [ { - "command": "dbtSemantic.renameDomain", - "when": "view == dbtSemantic.domainTree && viewItem == domain", + "command": "erdStudio.renameDomain", + "when": "view == erdStudio.domainTree && viewItem == domain", "group": "7_modification@1" }, { - "command": "dbtSemantic.deleteDomain", - "when": "view == dbtSemantic.domainTree && viewItem == domain", + "command": "erdStudio.deleteDomain", + "when": "view == erdStudio.domainTree && viewItem == domain", "group": "7_modification@2" }, { - "command": "dbtSemantic.editLayer", - "when": "view == dbtSemantic.domainTree && viewItem == layer", + "command": "erdStudio.editLayer", + "when": "view == erdStudio.domainTree && viewItem == layer", "group": "7_modification@1" }, { - "command": "dbtSemantic.removeLayer", - "when": "view == dbtSemantic.domainTree && viewItem == layer", + "command": "erdStudio.removeLayer", + "when": "view == erdStudio.domainTree && viewItem == layer", "group": "7_modification@2" }, { - "command": "dbtSemantic.revealLogicalModel", - "when": "view == dbtSemantic.modelLibrary && viewItem == logicalModel", + "command": "erdStudio.revealLogicalModel", + "when": "view == erdStudio.modelLibrary && viewItem == logicalModel", "group": "navigation@1" }, { - "command": "dbtSemantic.deleteLogicalModel", - "when": "view == dbtSemantic.modelLibrary && viewItem == logicalModel", + "command": "erdStudio.deleteLogicalModel", + "when": "view == erdStudio.modelLibrary && viewItem == logicalModel", "group": "7_modification@1" } ], "view/title": [ { - "command": "dbtSemantic.installCodingHarness", - "when": "view == dbtSemantic.domainTree && dbtSemantic.hasSemanticDir", + "command": "erdStudio.installCodingHarness", + "when": "view == erdStudio.domainTree && erdStudio.hasSemanticDir", "group": "navigation@0" }, { - "command": "dbtSemantic.addLayer", - "when": "view == dbtSemantic.domainTree && dbtSemantic.hasSemanticDir", + "command": "erdStudio.addLayer", + "when": "view == erdStudio.domainTree && erdStudio.hasSemanticDir", "group": "navigation@1" } ] @@ -256,15 +256,25 @@ "configuration": { "title": "ERD Studio", "properties": { - "dbtSemantic.projectPath": { + "erdStudio.projectPath": { "type": "string", "default": "", "description": "Path to dbt project root (auto-detected from workspace)" }, - "dbtSemantic.semanticDir": { + "erdStudio.semanticDir": { "type": "string", "default": ".erd-studio", "description": "Relative path to ERD domain files within the project" + }, + "dbtSemantic.projectPath": { + "type": "string", + "markdownDeprecationMessage": "Deprecated: use `#erdStudio.projectPath#` instead. Legacy values are still honoured.", + "description": "Path to dbt project root (auto-detected from workspace)" + }, + "dbtSemantic.semanticDir": { + "type": "string", + "markdownDeprecationMessage": "Deprecated: use `#erdStudio.semanticDir#` instead. Legacy values are still honoured.", + "description": "Relative path to ERD domain files within the project" } } } diff --git a/src/extension.ts b/src/extension.ts index 6637a34..d6bd8c8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,6 +18,7 @@ import { LegacyTagCleanupService } from './services/legacyTagCleanupService'; import { LogicalModelService } from './services/logicalModelService'; import { MigrationService, migrateLegacySemanticDir } from './services/migrationService'; import { YmlParserService } from './services/ymlParserService'; +import { getErdStudioSetting } from './services/configService'; import { ModelLibraryTreeProvider, type ModelLibraryNode } from './providers/ModelLibraryTreeProvider'; import { DOMAIN_EDITOR_VIEW_TYPE, hasOpenDomainCanvas, saveAllAndReload } from './services/recoveryService'; @@ -183,8 +184,7 @@ export async function activate(context: vscode.ExtensionContext): Promise console.log(`ERD Studio: Found dbt project at ${workspaceRoot}`); - const config = vscode.workspace.getConfiguration('dbtSemantic'); - const semanticDir = config.get('semanticDir', '.erd-studio'); + const semanticDir = getErdStudioSetting('semanticDir', '.erd-studio'); // v0.6.44 moved the default data directory from erd-studio/ to .erd-studio/. // Rename legacy folders in place before any service reads from disk so @@ -229,7 +229,7 @@ export async function activate(context: vscode.ExtensionContext): Promise if (choice === 'Show file') { void vscode.window.showTextDocument(vscode.Uri.file(info.filePath)); } else if (choice === 'Resync now') { - void vscode.commands.executeCommand('dbtSemantic.syncDomainTags'); + void vscode.commands.executeCommand('erdStudio.syncDomainTags'); } }); @@ -238,7 +238,7 @@ export async function activate(context: vscode.ExtensionContext): Promise vscode.StatusBarAlignment.Right, 0, ); - selectorsOutOfSyncStatus.command = 'dbtSemantic.syncDomainTags'; + selectorsOutOfSyncStatus.command = 'erdStudio.syncDomainTags'; selectorsOutOfSyncStatus.backgroundColor = new vscode.ThemeColor( 'statusBarItem.warningBackground', ); @@ -300,8 +300,8 @@ export async function activate(context: vscode.ExtensionContext): Promise // Set context key so view/title menus only show when semantic dir exists const fullSemanticDirPath = path.join(workspaceRoot, semanticDir); - void vscode.commands.executeCommand('setContext', 'dbtSemantic.hasSemanticDir', fs.existsSync(fullSemanticDirPath)); - void vscode.commands.executeCommand('setContext', 'dbtSemantic.hasLogicalModelsDir', logicalModelService.dirExists()); + void vscode.commands.executeCommand('setContext', 'erdStudio.hasSemanticDir', fs.existsSync(fullSemanticDirPath)); + void vscode.commands.executeCommand('setContext', 'erdStudio.hasLogicalModelsDir', logicalModelService.dirExists()); // ------------------------------------------------------------------------- // File watchers @@ -370,7 +370,7 @@ export async function activate(context: vscode.ExtensionContext): Promise 'Regenerate Now', ).then(choice => { if (choice === 'Regenerate Now') { - void vscode.commands.executeCommand('dbtSemantic.syncDomainTags'); + void vscode.commands.executeCommand('erdStudio.syncDomainTags'); } }); }); @@ -382,7 +382,7 @@ export async function activate(context: vscode.ExtensionContext): Promise treeProvider.refresh(); modelLibraryProvider.refresh(); // Re-evaluate context key so the Model Library view appears if logical-models/ was just created - void vscode.commands.executeCommand('setContext', 'dbtSemantic.hasLogicalModelsDir', logicalModelService.dirExists()); + void vscode.commands.executeCommand('setContext', 'erdStudio.hasLogicalModelsDir', logicalModelService.dirExists()); }, ); @@ -419,7 +419,7 @@ export async function activate(context: vscode.ExtensionContext): Promise dbtYmlChangedSubscription, projectChangedSubscription, (() => { - const treeView = vscode.window.createTreeView('dbtSemantic.domainTree', { + const treeView = vscode.window.createTreeView('erdStudio.domainTree', { treeDataProvider: treeProvider, dragAndDropController: treeProvider, canSelectMany: false, @@ -431,12 +431,12 @@ export async function activate(context: vscode.ExtensionContext): Promise vscode.window.registerFileDecorationProvider(layerDecorationProvider), modelLibraryProvider, (() => { - return vscode.window.createTreeView('dbtSemantic.modelLibrary', { + return vscode.window.createTreeView('erdStudio.modelLibrary', { treeDataProvider: modelLibraryProvider, canSelectMany: false, }); })(), - vscode.commands.registerCommand('dbtSemantic.deleteLogicalModel', async (node: ModelLibraryNode | undefined) => { + vscode.commands.registerCommand('erdStudio.deleteLogicalModel', async (node: ModelLibraryNode | undefined) => { if (!node || node.type !== 'model') { void vscode.window.showErrorMessage('Delete Model: No model selected. Right-click a model in the Model Library.'); return; @@ -451,14 +451,14 @@ export async function activate(context: vscode.ExtensionContext): Promise modelLibraryProvider.refresh(); } }), - vscode.commands.registerCommand('dbtSemantic.revealLogicalModel', (node: ModelLibraryNode | undefined) => { + vscode.commands.registerCommand('erdStudio.revealLogicalModel', (node: ModelLibraryNode | undefined) => { if (!node || node.type !== 'model') { void vscode.window.showErrorMessage('Reveal in Explorer: No model selected. Right-click a model in the Model Library.'); return; } void vscode.commands.executeCommand('revealInExplorer', vscode.Uri.file(node.filePath)); }), - vscode.commands.registerCommand('dbtSemantic.openDomain', async (filePath: string, stage?: Stage) => { + vscode.commands.registerCommand('erdStudio.openDomain', async (filePath: string, stage?: Stage) => { const fileUri = vscode.Uri.file(filePath); await vscode.commands.executeCommand( 'vscode.openWith', @@ -470,7 +470,7 @@ export async function activate(context: vscode.ExtensionContext): Promise } }), vscode.commands.registerCommand( - 'dbtSemantic.createDomain', + 'erdStudio.createDomain', async (layerArg?: Layer) => { // Step 1: Determine layer let layer: Layer | undefined = layerArg; @@ -582,7 +582,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }, ), vscode.commands.registerCommand( - 'dbtSemantic.deleteDomain', + 'erdStudio.deleteDomain', async (element?: TreeElement) => { if (!element || element.type !== 'domain') { void vscode.window.showErrorMessage('Delete Domain: No domain selected. Right-click a domain in the tree view.'); @@ -622,7 +622,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }, ), vscode.commands.registerCommand( - 'dbtSemantic.renameDomain', + 'erdStudio.renameDomain', async (element?: TreeElement) => { if (!element || element.type !== 'domain') { void vscode.window.showErrorMessage('Rename Domain: No domain selected. Right-click a domain in the tree view.'); @@ -683,7 +683,7 @@ export async function activate(context: vscode.ExtensionContext): Promise await vscode.commands.executeCommand('vscode.openWith', newFileUri, DOMAIN_EDITOR_VIEW_TYPE); }, ), - vscode.commands.registerCommand('dbtSemantic.refreshManifest', async () => { + vscode.commands.registerCommand('erdStudio.refreshManifest', async () => { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, @@ -702,7 +702,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }), // Regenerate the root selectors.yml from current domain files. // Run a domain refresh in dbt with: dbt build --selector domain_{layer}_{domain} - vscode.commands.registerCommand('dbtSemantic.syncDomainTags', async () => { + vscode.commands.registerCommand('erdStudio.syncDomainTags', async () => { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, @@ -729,7 +729,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }), // One-shot cleanup: strip legacy `domain:*` tags from every model YAML // left behind by the old SchemaTagService. Safe to run repeatedly. - vscode.commands.registerCommand('dbtSemantic.stripLegacyDomainTags', async () => { + vscode.commands.registerCommand('erdStudio.stripLegacyDomainTags', async () => { const confirm = await vscode.window.showWarningMessage( 'This will scan every .yml file in your workspace and remove any `domain:*` tag from `config.tags` or top-level `tags` on each dbt model. ' + 'Review and commit the changes as a single PR. Continue?', @@ -782,7 +782,7 @@ export async function activate(context: vscode.ExtensionContext): Promise ); }), // Migrate v4 domains to v5 central model store - vscode.commands.registerCommand('dbtSemantic.migrateToV5', async () => { + vscode.commands.registerCommand('erdStudio.migrateToV5', async () => { if (!migrationService.needsMigration()) { void vscode.window.showInformationMessage('All domain files are already using the v5 central model store format.'); return; @@ -812,7 +812,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }), // F408: Set up semantic directory for new projects vscode.commands.registerCommand( - 'dbtSemantic.setupSemanticDirectory', + 'erdStudio.setupSemanticDirectory', async () => { const fullSemanticDir = path.join(workspaceRoot, semanticDir); const defaultLayers = layerService.getAllLayers(); @@ -844,18 +844,18 @@ export async function activate(context: vscode.ExtensionContext): Promise } // Update context key so view/title menus appear - void vscode.commands.executeCommand('setContext', 'dbtSemantic.hasSemanticDir', true); + void vscode.commands.executeCommand('setContext', 'erdStudio.hasSemanticDir', true); treeProvider.refresh(); await new Promise(resolve => setTimeout(resolve, 100)); void vscode.window.showInformationMessage('ERD Studio directory created! Now create your first domain.'); - await vscode.commands.executeCommand('dbtSemantic.createDomain'); + await vscode.commands.executeCommand('erdStudio.createDomain'); }, ), // ------------------------------------------------------------------------- // Layer Management Commands (unchanged) // ------------------------------------------------------------------------- vscode.commands.registerCommand( - 'dbtSemantic.addLayer', + 'erdStudio.addLayer', async () => { // Step 1: Layer ID const id = await vscode.window.showInputBox({ @@ -924,7 +924,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }, ), vscode.commands.registerCommand( - 'dbtSemantic.editLayer', + 'erdStudio.editLayer', async (element?: TreeElement) => { let layerId: string | undefined; if (element && element.type === 'layer') { @@ -1004,7 +1004,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }, ), vscode.commands.registerCommand( - 'dbtSemantic.removeLayer', + 'erdStudio.removeLayer', async (element?: TreeElement) => { let layerId: string | undefined; if (element && element.type === 'layer') { @@ -1061,7 +1061,7 @@ export async function activate(context: vscode.ExtensionContext): Promise }, ), vscode.commands.registerCommand( - 'dbtSemantic.initializeLayerConfig', + 'erdStudio.initializeLayerConfig', async () => { const detected = layerService.detectLayersFromFilesystem(); if (detected.length === 0) { @@ -1095,7 +1095,7 @@ export async function activate(context: vscode.ExtensionContext): Promise // AI Coding Harness Installation // ------------------------------------------------------------------------- vscode.commands.registerCommand( - 'dbtSemantic.installCodingHarness', + 'erdStudio.installCodingHarness', async () => { const harnessService = new HarnessService(); const existing = harnessService.detectExisting(workspaceRoot); @@ -1169,7 +1169,7 @@ export async function activate(context: vscode.ExtensionContext): Promise ); } else if (installedCount === 0) { // No harnesses installed — prompt user to choose - void vscode.commands.executeCommand('dbtSemantic.installCodingHarness'); + void vscode.commands.executeCommand('erdStudio.installCodingHarness'); } } @@ -1194,6 +1194,39 @@ export async function activate(context: vscode.ExtensionContext): Promise }); } } + + // --------------------------------------------------------------------------- + // Legacy command aliases + // --------------------------------------------------------------------------- + // The extension was originally published with dbtSemantic.* command IDs. + // Keep them callable (registered in code only, so they stay out of the + // command palette) so existing user keybindings keep working after the + // erdStudio.* rename. + const LEGACY_ALIASED_COMMANDS = [ + 'createDomain', + 'setupSemanticDirectory', + 'openDomain', + 'deleteDomain', + 'refreshManifest', + 'renameDomain', + 'addLayer', + 'editLayer', + 'removeLayer', + 'initializeLayerConfig', + 'installCodingHarness', + 'syncDomainTags', + 'stripLegacyDomainTags', + 'migrateToV5', + 'deleteLogicalModel', + 'revealLogicalModel', + ]; + for (const name of LEGACY_ALIASED_COMMANDS) { + context.subscriptions.push( + vscode.commands.registerCommand(`dbtSemantic.${name}`, (...args: unknown[]) => + vscode.commands.executeCommand(`erdStudio.${name}`, ...args), + ), + ); + } } export function deactivate(): void { diff --git a/src/providers/DomainTreeProvider.ts b/src/providers/DomainTreeProvider.ts index b40744f..0df3626 100644 --- a/src/providers/DomainTreeProvider.ts +++ b/src/providers/DomainTreeProvider.ts @@ -205,7 +205,7 @@ export class DomainTreeProvider item.iconPath = new vscode.ThemeIcon('folder'); // Assign a resource URI so FileDecorationProvider can apply colors - item.resourceUri = vscode.Uri.parse(`dbt-semantic-layer:/${element.layer}`); + item.resourceUri = vscode.Uri.parse(`erd-studio-layer:/${element.layer}`); return item; } @@ -226,7 +226,7 @@ export class DomainTreeProvider item.iconPath = new vscode.ThemeIcon('json'); item.tooltip = `${this.layerService.getLabel(element.summary.layer)} / ${element.summary.domain}`; item.command = { - command: 'dbtSemantic.openDomain', + command: 'erdStudio.openDomain', title: 'Open Domain', arguments: [element.summary.filePath], }; @@ -242,7 +242,7 @@ export class DomainTreeProvider item.contextValue = 'newDomain'; item.iconPath = new vscode.ThemeIcon('add'); item.command = { - command: 'dbtSemantic.createDomain', + command: 'erdStudio.createDomain', title: 'Create Domain', arguments: [element.layer], }; diff --git a/src/providers/LayerDecorationProvider.ts b/src/providers/LayerDecorationProvider.ts index ca41554..b63888e 100644 --- a/src/providers/LayerDecorationProvider.ts +++ b/src/providers/LayerDecorationProvider.ts @@ -6,7 +6,7 @@ import type { LayerService } from '../services/layerService'; * URI scheme for layer tree items. * Used to identify layer nodes in the FileDecorationProvider. */ -export const LAYER_URI_SCHEME = 'dbt-semantic-layer'; +export const LAYER_URI_SCHEME = 'erd-studio-layer'; /** * Provides file decorations (color) for layer folders in the sidebar tree. diff --git a/src/providers/SemanticEditorProvider.ts b/src/providers/SemanticEditorProvider.ts index 4220f99..8541f88 100644 --- a/src/providers/SemanticEditorProvider.ts +++ b/src/providers/SemanticEditorProvider.ts @@ -15,6 +15,7 @@ */ import * as crypto from 'crypto'; +import { getErdStudioSetting } from '../services/configService'; import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; @@ -381,7 +382,7 @@ export class SemanticEditorProvider implements vscode.CustomTextEditorProvider { break; } case 'refreshManifest': { - await vscode.commands.executeCommand('dbtSemantic.refreshManifest'); + await vscode.commands.executeCommand('erdStudio.refreshManifest'); break; } case 'viewFile': { @@ -2758,9 +2759,7 @@ export class SemanticEditorProvider implements vscode.CustomTextEditorProvider { const report = panel.lastDiscrepancyReport; const manifest = await this.manifestService.loadManifest(this.workspaceRoot); const ymlData = await this.ymlParserService.loadYmlData(this.workspaceRoot, undefined); - const semanticDir = vscode.workspace - .getConfiguration('dbtSemantic') - .get('semanticDir', '.erd-studio'); + const semanticDir = getErdStudioSetting('semanticDir', '.erd-studio'); // Build resolutions from selections const models: ModelResolution[] = []; @@ -2948,9 +2947,7 @@ export class SemanticEditorProvider implements vscode.CustomTextEditorProvider { * Uses --dangerously-skip-permissions so file edits proceed without prompts. */ private async handleLaunchClaudeSync(): Promise { - const semanticDir = vscode.workspace - .getConfiguration('dbtSemantic') - .get('semanticDir', '.erd-studio'); + const semanticDir = getErdStudioSetting('semanticDir', '.erd-studio'); const planPath = `${semanticDir}/.sync-plan.json`; const prompt = `Execute the erd-studio sync plan at ${planPath} using the erd-studio skill. Read .claude/skills/erd-studio/SYNC.md for the action reference and follow the execution steps.`; diff --git a/src/services/configService.ts b/src/services/configService.ts new file mode 100644 index 0000000..e6450d5 --- /dev/null +++ b/src/services/configService.ts @@ -0,0 +1,26 @@ +import * as vscode from 'vscode'; + +/** + * Read an ERD Studio setting. + * + * The extension was originally published with `dbtSemantic.*` setting keys. + * Users who configured those keys before the `erdStudio.*` rename must keep + * their values, so resolution order is: + * + * 1. explicit `erdStudio.` (folder > workspace > global) + * 2. explicit `dbtSemantic.` (folder > workspace > global) + * 3. the provided default + */ +export function getErdStudioSetting(key: string, defaultValue: T): T { + const current = vscode.workspace.getConfiguration('erdStudio').inspect(key); + const legacy = vscode.workspace.getConfiguration('dbtSemantic').inspect(key); + return ( + current?.workspaceFolderValue ?? + current?.workspaceValue ?? + current?.globalValue ?? + legacy?.workspaceFolderValue ?? + legacy?.workspaceValue ?? + legacy?.globalValue ?? + defaultValue + ); +} diff --git a/src/services/recoveryService.ts b/src/services/recoveryService.ts index 9f48aae..20f8b80 100644 --- a/src/services/recoveryService.ts +++ b/src/services/recoveryService.ts @@ -15,7 +15,7 @@ import * as vscode from 'vscode'; * in sync with the `customEditors` contribution in package.json. Per CLAUDE.md * this identifier is part of the legacy public API and must not be renamed. */ -export const DOMAIN_EDITOR_VIEW_TYPE = 'dbtSemantic.domainEditor'; +export const DOMAIN_EDITOR_VIEW_TYPE = 'erdStudio.domainEditor'; /** * True when at least one editor tab is showing a domain canvas. Used to diff --git a/test/unit/domainTreeProvider.test.ts b/test/unit/domainTreeProvider.test.ts index 8d45156..fd5661f 100644 --- a/test/unit/domainTreeProvider.test.ts +++ b/test/unit/domainTreeProvider.test.ts @@ -296,7 +296,7 @@ describe('DomainTreeProvider', () => { const item = provider.getTreeItem(element); expect(item.command).toEqual({ - command: 'dbtSemantic.openDomain', + command: 'erdStudio.openDomain', title: 'Open Domain', arguments: ['/path/to/test.json'], }); @@ -309,7 +309,7 @@ describe('DomainTreeProvider', () => { expect(item.collapsibleState).toBe(TreeItemCollapsibleState.None); expect(item.contextValue).toBe('newDomain'); expect(item.command).toEqual({ - command: 'dbtSemantic.createDomain', + command: 'erdStudio.createDomain', title: 'Create Domain', arguments: ['gold'], });