From 4539d395766e3e5c2e3e3c2b2ea66f66b726e67c Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Wed, 15 Jul 2026 16:02:23 +0500 Subject: [PATCH] refactor: update names, load defaults from package.json --- docs/PLAN.md | 6 +- package-lock.json | 4 +- package.json | 92 ++++++++++++++--------------- src/config.ts | 60 +++++++++++++++++++ src/extension.ts | 6 +- src/storage/VscodeConfigProvider.ts | 19 ++++-- src/ui/taskCommands.ts | 14 ++--- src/views/taskDashboardPanel.ts | 6 +- src/views/taskKanbanPanel.ts | 4 +- src/views/taskTreeItem.ts | 2 +- todo.md | 6 +- tsconfig.app.json | 4 +- tsconfig.test.json | 2 +- 13 files changed, 146 insertions(+), 79 deletions(-) create mode 100644 src/config.ts diff --git a/docs/PLAN.md b/docs/PLAN.md index 68ad3e7..cbe700f 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -1,4 +1,4 @@ -# xboct-flow — VS Code Extension +# XBOCTuK Flow — VS Code Extension ## Хранение @@ -22,7 +22,7 @@ updated: 2026-07-12T10:00:00Z **Структура папок:** - `.vscode/tasks/` — проектные задачи -- глобальная папка — настраивается (`xboctFlow.globalPath`) +- глобальная папка — настраивается (`xboctukFlow.globalPath`) Оба пути настраиваются через VS Code settings. @@ -30,7 +30,7 @@ updated: 2026-07-12T10:00:00Z Через **Custom Editor** + **WebView**: -1. **Activity Bar** — вкладка XBOCT flow +1. **Activity Bar** — вкладка XBOCTuK Flow 2. **Task Dashboard** — WebView в editor area со split layout: - Левая панель — список задач с фильтрацией/группировкой - Правая панель — содержимое выбранной задачи (редактируемый markdown) diff --git a/package-lock.json b/package-lock.json index b5cd5de..54b1a14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "xboct-flow", + "name": "xboctuk-flow", "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "xboct-flow", + "name": "xboctuk-flow", "version": "0.0.1", "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 449ab12..dfcd0a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "xboct-flow", - "displayName": "XBOCT flow", + "name": "xboctuk-flow", + "displayName": "XBOCTuK Flow", "description": "Local-first task management for solo developers and small teams", "version": "0.0.1", "publisher": "", @@ -25,55 +25,55 @@ "contributes": { "commands": [ { - "command": "xboctFlow.createTask", - "title": "XBOCT flow: Create Task", + "command": "xboctukFlow.createTask", + "title": "XBOCTuK Flow: Create Task", "icon": "$(add)" }, { - "command": "xboctFlow.openTask", - "title": "XBOCT flow: Open Task", + "command": "xboctukFlow.openTask", + "title": "XBOCTuK Flow: Open Task", "icon": "$(go-to-file)" }, { - "command": "xboctFlow.deleteTask", - "title": "XBOCT flow: Delete Task", + "command": "xboctukFlow.deleteTask", + "title": "XBOCTuK Flow: Delete Task", "icon": "$(trash)" }, { - "command": "xboctFlow.changeStatus", - "title": "XBOCT flow: Change Status", + "command": "xboctukFlow.changeStatus", + "title": "XBOCTuK Flow: Change Status", "icon": "$(sync)" }, { - "command": "xboctFlow.openDashboard", - "title": "XBOCT flow: Open Dashboard", + "command": "xboctukFlow.openDashboard", + "title": "XBOCTuK Flow: Open Dashboard", "icon": "$(dashboard)" }, { - "command": "xboctFlow.openInDashboard", - "title": "XBOCT flow: Edit in Dashboard", + "command": "xboctukFlow.openInDashboard", + "title": "XBOCTuK Flow: Edit in Dashboard", "icon": "$(edit)" }, { - "command": "xboctFlow.openKanban", - "title": "XBOCT flow: Open Kanban", + "command": "xboctukFlow.openKanban", + "title": "XBOCTuK Flow: Open Kanban", "icon": "$(layout)" } ], "configuration": { - "title": "XBOCT flow", + "title": "XBOCTuK Flow", "properties": { - "xboctFlow.projectPath": { + "xboctukFlow.projectPath": { "type": "string", "default": ".vscode/tasks", "description": "Path to project-level tasks folder (relative to workspace root)" }, - "xboctFlow.globalPath": { + "xboctukFlow.globalPath": { "type": "string", "default": "", "description": "Path to global tasks folder (absolute path, shared across projects)" }, - "xboctFlow.fileExtension": { + "xboctukFlow.fileExtension": { "type": "string", "default": ".task.md", "enum": [ @@ -88,17 +88,17 @@ "viewsContainers": { "activitybar": [ { - "id": "xboctFlow", - "title": "XBOCT flow", + "id": "xboctukFlow", + "title": "XBOCTuK Flow", "icon": "media/icon.svg" } ] }, "views": { - "xboctFlow": [ + "xboctukFlow": [ { "type": "tree", - "id": "xboctFlow.tasks", + "id": "xboctukFlow.tasks", "name": "Tasks", "icon": "media/icon.svg" } @@ -107,60 +107,60 @@ "menus": { "view/title": [ { - "command": "xboctFlow.createTask", - "when": "view == xboctFlow.tasks", + "command": "xboctukFlow.createTask", + "when": "view == xboctukFlow.tasks", "group": "navigation@1" }, { - "command": "xboctFlow.openDashboard", - "when": "view == xboctFlow.tasks", + "command": "xboctukFlow.openDashboard", + "when": "view == xboctukFlow.tasks", "group": "navigation@2" }, { - "command": "xboctFlow.openKanban", - "when": "view == xboctFlow.tasks", + "command": "xboctukFlow.openKanban", + "when": "view == xboctukFlow.tasks", "group": "navigation@3" } ], "view/item/context": [ { - "command": "xboctFlow.openTask", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.openTask", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "inline@1" }, { - "command": "xboctFlow.openInDashboard", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.openInDashboard", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "inline@2" }, { - "command": "xboctFlow.changeStatus", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.changeStatus", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "inline@3" }, { - "command": "xboctFlow.deleteTask", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.deleteTask", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "inline@4" }, { - "command": "xboctFlow.openTask", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.openTask", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "1_task@1" }, { - "command": "xboctFlow.openInDashboard", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.openInDashboard", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "1_task@2" }, { - "command": "xboctFlow.changeStatus", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.changeStatus", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "1_task@3" }, { - "command": "xboctFlow.deleteTask", - "when": "view == xboctFlow.tasks && viewItem == task", + "command": "xboctukFlow.deleteTask", + "when": "view == xboctukFlow.tasks && viewItem == task", "group": "1_task@4" } ] diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..38f44eb --- /dev/null +++ b/src/config.ts @@ -0,0 +1,60 @@ +/** + * Reads extension settings metadata from package.json (single source of truth). + * Defaults / enum for Settings UI live in package.json `contributes.configuration`. + */ +import packageJson from "../package.json"; + +type ConfigProperty = { + type?: string; + default?: string | number | boolean | string[]; + enum?: string[]; + description?: string; +}; + +type PackageJsonShape = { + contributes: { + configuration: { + title: string; + properties: Record; + }; + }; +}; + +const pkg = packageJson as PackageJsonShape; +const properties = pkg.contributes.configuration.properties; + +/** VS Code configuration section (`xboctukFlow` from keys like `xboctukFlow.projectPath`). */ +export function getConfigSection(): string { + const firstKey = Object.keys(properties)[0]; + if (!firstKey) { + throw new Error("package.json has no contributes.configuration.properties"); + } + const dot = firstKey.indexOf("."); + if (dot <= 0) { + throw new Error(`Invalid configuration key: ${firstKey}`); + } + return firstKey.slice(0, dot); +} + +export type SettingKey = "projectPath" | "globalPath" | "fileExtension"; + +function property(key: SettingKey): ConfigProperty { + const fullKey = `${getConfigSection()}.${key}`; + const prop = properties[fullKey]; + if (!prop) { + throw new Error(`Missing package.json setting: ${fullKey}`); + } + return prop; +} + +/** Default from package.json (same as Settings UI default). */ +export function getSettingDefault(key: SettingKey): string { + const value = property(key).default; + if (typeof value === "string") { + return value; + } + if (value === undefined || value === null) { + return ""; + } + return String(value); +} diff --git a/src/extension.ts b/src/extension.ts index df0db93..cda2d8c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -22,7 +22,7 @@ export function activate(context: vscode.ExtensionContext) { }; context.subscriptions.push( - vscode.window.registerTreeDataProvider("xboctFlow.tasks", tree), + vscode.window.registerTreeDataProvider("xboctukFlow.tasks", tree), ); const ext = config.getFileExtension(); @@ -41,8 +41,8 @@ export function activate(context: vscode.ExtensionContext) { vscode.StatusBarAlignment.Left, ); statusBarItem.text = "$(checklist) Tasks"; - statusBarItem.command = "xboctFlow.openDashboard"; - statusBarItem.tooltip = "XBOCT flow — Open Dashboard"; + statusBarItem.command = "xboctukFlow.openDashboard"; + statusBarItem.tooltip = "XBOCTuK Flow — Open Dashboard"; statusBarItem.show(); context.subscriptions.push(statusBarItem); diff --git a/src/storage/VscodeConfigProvider.ts b/src/storage/VscodeConfigProvider.ts index d40d40a..51cb5f7 100644 --- a/src/storage/VscodeConfigProvider.ts +++ b/src/storage/VscodeConfigProvider.ts @@ -1,5 +1,6 @@ import * as path from "path"; import * as vscode from "vscode"; +import { getConfigSection, getSettingDefault } from "@/config"; import { IConfigProvider } from "@/ports"; export class VscodeConfigProvider implements IConfigProvider { @@ -7,18 +8,24 @@ export class VscodeConfigProvider implements IConfigProvider { const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; if (!workspaceRoot) return undefined; - const config = vscode.workspace.getConfiguration("xboctFlow"); - const relativePath = config.get("projectPath") ?? ".vscode/tasks"; + const config = vscode.workspace.getConfiguration(getConfigSection()); + // get() already merges package.json defaults; fallback for safety. + const relativePath = + config.get("projectPath") ?? getSettingDefault("projectPath"); return path.join(workspaceRoot, relativePath); } getGlobalTaskPath(): string | undefined { - const config = vscode.workspace.getConfiguration("xboctFlow"); - return config.get("globalPath") || undefined; + const config = vscode.workspace.getConfiguration(getConfigSection()); + const globalPath = + config.get("globalPath") ?? getSettingDefault("globalPath"); + return globalPath || undefined; } getFileExtension(): string { - const config = vscode.workspace.getConfiguration("xboctFlow"); - return config.get("fileExtension") ?? ".task.md"; + const config = vscode.workspace.getConfiguration(getConfigSection()); + return ( + config.get("fileExtension") ?? getSettingDefault("fileExtension") + ); } } diff --git a/src/ui/taskCommands.ts b/src/ui/taskCommands.ts index c1e5ad9..4dac342 100644 --- a/src/ui/taskCommands.ts +++ b/src/ui/taskCommands.ts @@ -226,27 +226,27 @@ export function registerTaskCommands( deps: TaskCommandDeps, ): void { context.subscriptions.push( - vscode.commands.registerCommand("xboctFlow.createTask", () => + vscode.commands.registerCommand("xboctukFlow.createTask", () => runCreateTask(deps), ), - vscode.commands.registerCommand("xboctFlow.openTask", (item?: unknown) => + vscode.commands.registerCommand("xboctukFlow.openTask", (item?: unknown) => runOpenTask(deps, item), ), - vscode.commands.registerCommand("xboctFlow.deleteTask", (item?: unknown) => + vscode.commands.registerCommand("xboctukFlow.deleteTask", (item?: unknown) => runDeleteTask(deps, item), ), vscode.commands.registerCommand( - "xboctFlow.changeStatus", + "xboctukFlow.changeStatus", (item?: unknown) => runChangeStatus(deps, item), ), - vscode.commands.registerCommand("xboctFlow.openDashboard", () => + vscode.commands.registerCommand("xboctukFlow.openDashboard", () => runOpenDashboard(deps), ), vscode.commands.registerCommand( - "xboctFlow.openInDashboard", + "xboctukFlow.openInDashboard", (item?: unknown) => runOpenInDashboard(deps, item), ), - vscode.commands.registerCommand("xboctFlow.openKanban", () => + vscode.commands.registerCommand("xboctukFlow.openKanban", () => runOpenKanban(deps), ), ); diff --git a/src/views/taskDashboardPanel.ts b/src/views/taskDashboardPanel.ts index c141f9e..f7d930e 100644 --- a/src/views/taskDashboardPanel.ts +++ b/src/views/taskDashboardPanel.ts @@ -56,8 +56,8 @@ export class TaskDashboardPanel { } const panel = vscode.window.createWebviewPanel( - "xboctFlow.dashboard", - "XBOCT flow", + "xboctukFlow.dashboard", + "XBOCTuK Flow", vscode.ViewColumn.One, { enableScripts: true, @@ -181,7 +181,7 @@ export class TaskDashboardPanel { return; case "createTask": - await vscode.commands.executeCommand("xboctFlow.createTask"); + await vscode.commands.executeCommand("xboctukFlow.createTask"); await this.reloadTasks(); return; } diff --git a/src/views/taskKanbanPanel.ts b/src/views/taskKanbanPanel.ts index 409be35..38dbfdc 100644 --- a/src/views/taskKanbanPanel.ts +++ b/src/views/taskKanbanPanel.ts @@ -39,8 +39,8 @@ export class TaskKanbanPanel { } const panel = vscode.window.createWebviewPanel( - "xboctFlow.kanban", - "XBOCT flow — Kanban", + "xboctukFlow.kanban", + "XBOCTuK Flow — Kanban", vscode.ViewColumn.One, { enableScripts: true, diff --git a/src/views/taskTreeItem.ts b/src/views/taskTreeItem.ts index 2592097..5efbd6e 100644 --- a/src/views/taskTreeItem.ts +++ b/src/views/taskTreeItem.ts @@ -21,7 +21,7 @@ export class TaskTreeItem extends vscode.TreeItem { }`, ); this.command = { - command: "xboctFlow.openTask", + command: "xboctukFlow.openTask", title: "Open Task", arguments: [this], }; diff --git a/todo.md b/todo.md index 372d7af..d16935b 100644 --- a/todo.md +++ b/todo.md @@ -47,15 +47,15 @@ headless/тестов можно оставить; editor-save — optional path [x] **Боковая панель** -- кнопка открытия dashboard (view title → `xboctFlow.openDashboard`) +- кнопка открытия dashboard (view title → `xboctukFlow.openDashboard`) - кнопки на задаче (inline): open file, edit in dashboard - (`xboctFlow.openInDashboard` + preselect), delete + (`xboctukFlow.openInDashboard` + preselect), delete - change status остаётся в context menu [x] **Dashboard: кнопка создания задачи** - `+ Task` в toolbar → inbound `createTask` → host - `executeCommand("xboctFlow.createTask")` → reload list + `executeCommand("xboctukFlow.createTask")` → reload list [x] **Kanban** diff --git a/tsconfig.app.json b/tsconfig.app.json index 67129f1..f1962de 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -3,7 +3,7 @@ "module": "commonjs", "target": "ES2022", "outDir": "out", - "rootDir": "src", + "rootDir": ".", "lib": ["ES2022"], "sourceMap": true, "strict": true, @@ -17,6 +17,6 @@ "@/*": ["./src/*"] } }, - "include": ["src/**/*"], + "include": ["src/**/*", "package.json"], "exclude": ["node_modules", "out", ".vscode-test", "src/**/*.test.ts"] } diff --git a/tsconfig.test.json b/tsconfig.test.json index 998f9ad..914cac6 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -6,6 +6,6 @@ "declaration": false, "types": ["node"] }, - "include": ["src/**/*", "tests/**/*"], + "include": ["src/**/*", "tests/**/*", "package.json"], "exclude": ["node_modules", "out", ".vscode-test"] }