diff --git a/Claude.md b/Claude.md index 67ff35b..b671f94 100644 --- a/Claude.md +++ b/Claude.md @@ -116,6 +116,8 @@ https://developers.google.com/search/docs/fundamentals/seo-starter-guide https://studiohawk.com.au/blog/how-to-optimise-ai-overviews/ https://about.ads.microsoft.com/en/blog/post/october-2025/optimizing-your-content-for-inclusion-in-ai-search-answers +https://documentation.platformos.com/use-cases/implementing-social-media-preview-cards + ## Project Structure ``` diff --git a/CoveragePlan.md b/CoveragePlan.md deleted file mode 100644 index 790d80d..0000000 --- a/CoveragePlan.md +++ /dev/null @@ -1,124 +0,0 @@ -# Plan: Get Test Coverage to 100% - -## Context -Coverage is at 78% (5187/6634 statements). Major gaps are dead code, unused logger methods, untested semantic/AI features, and uncovered error branches. Strategy: delete dead code first (biggest bang for buck), then add tests for remaining gaps. - -## Phase 1: Delete Dead Code (~300+ statements removed) - -### 1a. Logger — remove unused methods -**File:** `src/utils/logger.ts` -- Delete `tag()` (lines 77-84) — **zero callers** in entire codebase -- Delete `quick()` (lines 103-112) — **zero callers** -- Delete `config()` (lines 117-133) — **zero callers** -- Keep `filter()` — called from `CommandTreeProvider.ts:92` - -### 1b. Test helpers — remove unused exports -**File:** `src/test/helpers/helpers.ts` -- Delete `getTreeView()` (line 43-46) — returns `undefined`, never imported -- Delete `filterTasks()` (line 61-65) — never imported by any test -- Delete `runTask()` (line 76-78) — never imported by any test -- Delete `waitForCondition()` (line 132-145) — never imported by any test -- Delete `captureTerminalOutput()` (line 242-255) — never imported, always returns `""` -- Delete `readFile()` (line 122-125) — never imported (tests use `fs.readFileSync` directly) - -### 1c. Test types — remove unused config helpers -**File:** `src/test/helpers/test-types.ts` -- Delete `getExcludePatternsDefault()` (line 121-126) — zero callers -- Delete `getSortOrderDefault()` (line 131-136) — zero callers -- Delete `getSortOrderEnum()` (line 141-146) — zero callers -- Delete `getSortOrderEnumDescriptions()` (line 151-156) — zero callers - -### 1d. Semantic — remove unused function -**File:** `src/semantic/modelSelection.ts` -- Delete `pickConcreteModel()` (line 38-48) — never imported anywhere - -### 1e. Extension — inline trivial passthrough -**File:** `src/extension.ts` -- Inline `isAiEnabled()` (line 466-468) — just returns its input; replace 2 call sites with direct boolean check - -### 1f. Deno — fix duplicate + regex violation -**File:** `src/discovery/deno.ts` -- Delete local `removeJsonComments()` (line 96-100) — duplicate of `src/utils/fileUtils.ts` version AND uses illegal regex -- Import `removeJsonComments` from `../utils/fileUtils` instead -- Delete local `truncate()` if it exists in a shared util (check first) - -## Phase 2: Add Missing Tests - -### 2a. Logger unit tests -- Test `info()`, `warn()`, `error()` with disabled state (`setEnabled(false)`) -- Test `filter()` method -- Test with and without `data` parameter - -### 2b. fileUtils edge cases -- Test `removeJsonComments()` with unterminated block comments -- Test `removeJsonComments()` with strings containing `//` and `/*` -- Test `readFile()` error path -- Test `parseJson()` with malformed input - -### 2c. TaskRunner param format tests -- Test `"flag"` format -- Test `"flag-equals"` format -- Test `"dashdash-args"` format -- Test empty param value skipping - -### 2d. Discovery branch coverage -- Test early return when no source files exist (cargo, gradle, maven, deno) -- Test `readFile` failure path (skip unreadable files) -- Test non-string script values in npm/deno - -### 2e. DB error handling -- Test `addColumnIfMissing()` when column already exists -- Test `registerCommand()` upsert conflict path -- Test `getRow()` null result - -### 2f. Config branch coverage -- Test `load()` when DB returns error -- Test `addTaskToTag()` when DB fails -- Test `removeTaskFromTag()` when DB fails - -### 2g. Semantic module tests -- Unit test `resolveModel()` — all branches (saved ID found, saved ID not found, no models, user cancels) -- Unit test `modelSelection.ts` pure functions -- Mock-based tests for `summariseScript`, `summaryPipeline` functions - -## Phase 3: Verify - -- Run `make test` (includes `--coverage`) -- Check coverage report for remaining gaps -- Iterate until 100% - -## Critical Files -- `src/utils/logger.ts` — delete 3 methods -- `src/test/helpers/helpers.ts` — delete 6 functions -- `src/test/helpers/test-types.ts` — delete 4 functions -- `src/semantic/modelSelection.ts` — delete 1 function -- `src/extension.ts` — inline 1 function -- `src/discovery/deno.ts` — fix regex violation + remove duplicate -- New/modified test files for Phase 2 - ---- - -## TODO - -### Phase 1: Delete Dead Code -- [x] 1a. Delete `tag()`, `quick()`, `config()` from `src/utils/logger.ts` — ALREADY DONE -- [x] 1b. Delete `getTreeView()`, `filterTasks()`, `runTask()`, `waitForCondition()`, `captureTerminalOutput()`, `readFile()` from `src/test/helpers/helpers.ts` — ALREADY DONE -- [x] 1c. Delete `getExcludePatternsDefault()`, `getSortOrderDefault()`, `getSortOrderEnum()`, `getSortOrderEnumDescriptions()` from `src/test/helpers/test-types.ts` — ALREADY DONE -- [x] 1d. ~~Delete `pickConcreteModel()`~~ — ACTUALLY USED (summariser.ts + unit tests). Plan was wrong. -- [x] 1e. ~~Inline `isAiEnabled()`~~ — ALREADY DONE (function no longer exists) -- [x] 1f. Fix deno.ts — ALREADY DONE (regex `removeJsonComments` deleted, imports from `fileUtils`) - -### Phase 2: Add Missing Tests -- [x] 2a. Logger unit tests — BLOCKED as unit test (vscode dep). Coverage comes from e2e usage. -- [x] 2b. fileUtils edge cases (unterminated comments, strings with comment chars, malformed JSON) — `src/test/e2e/fileUtils.e2e.test.ts` (8 tests) -- [x] 2c. TaskRunner param format tests (flag, flag-equals, dashdash-args, empty skip) — `src/test/unit/taskRunner.unit.test.ts` (11 tests, all passing) -- [x] 2d. Discovery branch coverage — BLOCKED as unit test (vscode dep). Branches exercised by existing e2e fixture tests. -- [x] 2e. DB error handling (addColumnIfMissing, registerCommand upsert, getRow null) — `src/test/e2e/db.e2e.test.ts` (12 tests) -- [x] 2f. Config branch coverage — BLOCKED as unit test (vscode dep). Error paths are defensive code, covered by e2e tag tests. -- [x] 2g. Semantic module tests (resolveModel branches, pure functions, mock summarise tests) — ALREADY DONE in `modelSelection.unit.test.ts` - -### Phase 3: Verify -- [x] Run `npm test` — **217 passing, 7 failing** (all 7 failures are Copilot auth timeouts in headless test env, not code bugs) -- [ ] Run `npm run test:coverage` for coverage report — needs Copilot auth or skip AI tests -- [ ] Check coverage report for remaining gaps -- [ ] Iterate until 100% diff --git a/README.md b/README.md index b49e1a5..a285179 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ CommandTree in action

-CommandTree scans your project and surfaces all runnable commands across 19 tool types in a single tree view. Filter by text or tag, search by meaning with AI-powered semantic search, and run in terminal or debugger. +CommandTree scans your project and surfaces all runnable commands across 21 tool types in a single tree view. Filter by text or tag, and run in terminal or debugger. ## AI Summaries (powered by GitHub Copilot) @@ -19,8 +19,7 @@ Summaries are stored locally and only regenerate when the underlying script chan ## Features - **AI Summaries** - GitHub Copilot describes each command in plain language, with security warnings for dangerous operations -- **AI-Powered Search** - Find commands by meaning, not just name — local embeddings, no data leaves your machine -- **Auto-discovery** - 19 command types including shell scripts, npm, Make, Python, PowerShell, Gradle, Cargo, Maven, Docker Compose, .NET, and more +- **Auto-discovery** - 21 command types including shell scripts, npm, Make, Python, PowerShell, Gradle, Cargo, Maven, Docker Compose, .NET, C# Script, F# Script, and more - **Quick Launch** - Pin frequently-used commands to a dedicated panel at the top - **Tagging** - Right-click any command to add or remove tags - **Filtering** - Filter the tree by text search or by tag @@ -51,6 +50,8 @@ Summaries are stored locally and only regenerate when the underlying script chan | Composer Scripts | `composer.json` (PHP) | | Docker Compose | `docker-compose.yml` | | .NET Projects | `.csproj`, `.fsproj` | +| C# Scripts | `.csx` files | +| F# Scripts | `.fsx` files | | Markdown Files | `.md` files | ## Getting Started diff --git a/website/eleventy.config.js b/website/eleventy.config.js index ea27c90..ed69b9b 100644 --- a/website/eleventy.config.js +++ b/website/eleventy.config.js @@ -18,11 +18,13 @@ export default function(eleventyConfig) { eleventyConfig.addPassthroughCopy("src/assets"); eleventyConfig.addPassthroughCopy({ "src/favicon.ico": "favicon.ico" }); + eleventyConfig.addPassthroughCopy({ "src/site.webmanifest": "site.webmanifest" }); const faviconLinks = [ ' ', ' ', ' ', + ' ', ].join("\n"); const isIconLink = (line) => { @@ -144,13 +146,21 @@ export default function(eleventyConfig) { if (!this.page.outputPath?.endsWith(".html")) { return content; } - const ogImageAltTag = ' '; + const altText = "CommandTree - One sidebar, every command in VS Code. Auto-discover 21 command types with AI-powered summaries."; + const ogImageAltTag = ` `; + const twitterImageAltTag = ` `; const ogImageHeightTag = 'og:image:height'; const insertionPoint = content.indexOf(ogImageHeightTag); if (insertionPoint < 0) { return content; } const lineEnd = content.indexOf("\n", insertionPoint); if (lineEnd < 0) { return content; } - return content.slice(0, lineEnd + 1) + ogImageAltTag + "\n" + content.slice(lineEnd + 1); + const withOgAlt = content.slice(0, lineEnd + 1) + ogImageAltTag + "\n" + content.slice(lineEnd + 1); + const twitterImageTag = 'twitter:image" content='; + const twitterInsert = withOgAlt.indexOf(twitterImageTag); + if (twitterInsert < 0) { return withOgAlt; } + const twitterLineEnd = withOgAlt.indexOf("\n", twitterInsert); + if (twitterLineEnd < 0) { return withOgAlt; } + return withOgAlt.slice(0, twitterLineEnd + 1) + twitterImageAltTag + "\n" + withOgAlt.slice(twitterLineEnd + 1); }); eleventyConfig.addTransform("articleMeta", function(content) { @@ -237,6 +247,38 @@ export default function(eleventyConfig) { return content.replace("", scriptTag + "\n"); }); + eleventyConfig.addTransform("softwareAppSchema", function(content) { + if (!this.page.outputPath?.endsWith(".html")) { + return content; + } + if (this.page.url !== "/") { + return content; + } + const softwareSchema = { + "@context": "https://schema.org", + "@type": "SoftwareApplication", + "name": "CommandTree", + "applicationCategory": "DeveloperApplication", + "operatingSystem": "Windows, macOS, Linux", + "description": "VS Code extension that auto-discovers 21 command types — shell scripts, npm, Make, Gradle, Cargo, Docker Compose, .NET, and more — in one sidebar with AI-powered summaries.", + "url": "https://commandtree.dev", + "downloadUrl": "https://marketplace.visualstudio.com/items?itemName=nimblesite.commandtree", + "softwareRequirements": "Visual Studio Code", + "offers": { + "@type": "Offer", + "price": "0", + "priceCurrency": "USD", + }, + "author": { + "@type": "Organization", + "name": "Nimblesite Pty Ltd", + "url": "https://www.nimblesite.co", + }, + }; + const scriptTag = `\n `; + return content.replace("", scriptTag + "\n"); + }); + return { dir: { input: "src", output: "_site" }, markdownTemplateEngine: "njk", diff --git a/website/src/_data/site.json b/website/src/_data/site.json index db76f6f..cc32404 100644 --- a/website/src/_data/site.json +++ b/website/src/_data/site.json @@ -7,7 +7,7 @@ "keywords": "VS Code extension, command runner, task runner, script discovery, npm scripts, shell scripts, makefile, workspace automation, developer tools", "themeColor": "#2a8c7a", "ogImage": "/assets/images/og-image.png", - "ogImageAlt": "CommandTree - One sidebar, every command in VS Code. Auto-discover 19 command types with AI-powered summaries.", + "ogImageAlt": "CommandTree - One sidebar, every command in VS Code. Auto-discover 21 command types with AI-powered summaries.", "ogImageWidth": "1200", "ogImageHeight": "630", "organization": { diff --git a/website/src/blog/introducing-commandtree.md b/website/src/blog/introducing-commandtree.md index 67d0d7f..378af37 100644 --- a/website/src/blog/introducing-commandtree.md +++ b/website/src/blog/introducing-commandtree.md @@ -35,9 +35,10 @@ Install CommandTree and a new panel appears in your VS Code sidebar. Every runna - Gradle, Cargo, Maven, Ant, and Just - Taskfile, Deno, Rake, and Composer - Docker Compose services and .NET projects +- C# scripts and F# scripts - Markdown files -That is 19 command types discovered automatically. Click the play button. Done. +That is 21 command types discovered automatically. Click the play button. Done. ## AI-Powered Summaries diff --git a/website/src/docs/discovery.md b/website/src/docs/discovery.md index 465f395..771ad7f 100644 --- a/website/src/docs/discovery.md +++ b/website/src/docs/discovery.md @@ -1,7 +1,7 @@ --- layout: layouts/docs.njk -title: Auto-Discovery of 18+ Command Types - CommandTree Docs -description: How CommandTree auto-discovers shell scripts, npm, Make, Gradle, Cargo, Maven, Docker Compose, .NET, and 18+ command types in your VS Code workspace. +title: Auto-Discovery of 21 Command Types - CommandTree Docs +description: How CommandTree auto-discovers shell scripts, npm, Make, Gradle, Cargo, Maven, Docker Compose, .NET, C# Script, F# Script, and 21 command types in your VS Code workspace. eleventyNavigation: key: Command Discovery order: 2 @@ -9,7 +9,7 @@ eleventyNavigation: # Command Discovery -CommandTree auto-discovers 18+ command types — including shell scripts, npm scripts, Makefiles, Gradle, Cargo, Maven, Docker Compose, and .NET projects — by recursively scanning your workspace. Discovery respects [exclude patterns](/docs/configuration/) and runs in the background. +CommandTree auto-discovers 21 command types — including shell scripts, npm scripts, Makefiles, Gradle, Cargo, Maven, Docker Compose, .NET projects, C# scripts, and F# scripts — by recursively scanning your workspace. Discovery respects [exclude patterns](/docs/configuration/) and runs in the background. ## Shell Scripts @@ -90,6 +90,14 @@ Discovers services from `docker-compose.yml` / `docker-compose.yaml` files. Discovers `.csproj` and `.fsproj` project files for build/run/test commands. +## C# Scripts + +Discovers `.csx` files and runs them via `dotnet script`. + +## F# Scripts + +Discovers `.fsx` files and runs them via `dotnet fsi`. + ## Markdown Files Discovers `.md` files in the workspace. diff --git a/website/src/docs/index.md b/website/src/docs/index.md index 0c31fb7..55a52d9 100644 --- a/website/src/docs/index.md +++ b/website/src/docs/index.md @@ -1,7 +1,7 @@ --- layout: layouts/docs.njk title: Getting Started with CommandTree - VS Code Command Runner -description: Install CommandTree for VS Code and discover shell scripts, npm scripts, Makefiles, and 18+ command types automatically in one sidebar. +description: Install CommandTree for VS Code and discover shell scripts, npm scripts, Makefiles, and 21 command types automatically in one sidebar. eleventyNavigation: key: Getting Started order: 1 @@ -9,7 +9,7 @@ eleventyNavigation: # Getting Started -CommandTree is a free VS Code extension that scans your workspace and surfaces all runnable commands — shell scripts, npm scripts, Makefiles, and 18 other types — in a single tree view sidebar panel. +CommandTree is a free VS Code extension that scans your workspace and surfaces all runnable commands — shell scripts, npm scripts, Makefiles, and 18 more types — in a single tree view sidebar panel. ## Installation @@ -58,6 +58,8 @@ code --install-extension commandtree-*.vsix | Composer Scripts | `composer.json` | | Docker Compose | `docker-compose.yml` | | .NET Projects | `.csproj` / `.fsproj` | +| C# Scripts | `.csx` files | +| F# Scripts | `.fsx` files | | Markdown Files | `.md` files | Discovery respects [exclude patterns](/docs/configuration/) in settings and runs in the background. If [GitHub Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) is installed, each discovered command is automatically described in plain language — hover over any command to see what it does. Learn more about [how discovery works](/docs/discovery/) and [AI summaries](/docs/ai-summaries/). @@ -66,7 +68,7 @@ Discovery respects [exclude patterns](/docs/configuration/) in settings and runs ### What command types does CommandTree discover? -CommandTree discovers 19 command types: shell scripts, npm scripts, Makefile targets, VS Code tasks, launch configurations, Python scripts, PowerShell scripts, Gradle tasks, Cargo tasks, Maven goals, Ant targets, Just recipes, Taskfile tasks, Deno tasks, Rake tasks, Composer scripts, Docker Compose services, .NET projects, and Markdown files. +CommandTree discovers 21 command types: shell scripts, npm scripts, Makefile targets, VS Code tasks, launch configurations, Python scripts, PowerShell scripts, Gradle tasks, Cargo tasks, Maven goals, Ant targets, Just recipes, Taskfile tasks, Deno tasks, Rake tasks, Composer scripts, Docker Compose services, .NET projects, C# scripts, F# scripts, and Markdown files. ### Does CommandTree require GitHub Copilot? diff --git a/website/src/favicon.ico b/website/src/favicon.ico index 64a2722..67f6031 100644 Binary files a/website/src/favicon.ico and b/website/src/favicon.ico differ diff --git a/website/src/index.njk b/website/src/index.njk index ca2b7b1..70f5556 100644 --- a/website/src/index.njk +++ b/website/src/index.njk @@ -1,7 +1,7 @@ --- layout: layouts/base.njk title: CommandTree - One Sidebar, Every Command in VS Code -description: CommandTree discovers all runnable commands in your VS Code workspace — shell scripts, npm, Make, Gradle, Docker Compose, and 18+ types — in one sidebar with AI summaries. +description: CommandTree discovers all runnable commands in your VS Code workspace — shell scripts, npm, Make, Gradle, Docker Compose, .NET, C# Script, F# Script, and 21 types — in one sidebar with AI summaries. ---
@@ -55,7 +55,7 @@ description: CommandTree discovers all runnable commands in your VS Code workspa
🔍

Auto-Discovery

-

Recursively scans your workspace for shell scripts, npm scripts, Makefile targets, VS Code commands, launch configs, and Python scripts.

+

Recursively scans your workspace for 21 command types including shell scripts, npm, Make, Gradle, Cargo, Docker Compose, .NET, C# Script, F# Script, and more.

@@ -218,6 +218,20 @@ description: CommandTree discovers all runnable commands in your VS Code workspa

.csproj / .fsproj

+
+ 🟣 +
+

C# Scripts

+

.csx files

+
+
+
+ 🔵 +
+

F# Scripts

+

.fsx files

+
+
📝
diff --git a/website/src/site.webmanifest b/website/src/site.webmanifest new file mode 100644 index 0000000..d68ed03 --- /dev/null +++ b/website/src/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "CommandTree", + "short_name": "CommandTree", + "description": "One sidebar for every command in your VS Code workspace. AI-powered.", + "start_url": "/", + "display": "browser", + "background_color": "#ffffff", + "theme_color": "#2a8c7a", + "icons": [ + { + "src": "/assets/images/favicon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/assets/images/favicon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/website/tests/homepage.spec.ts b/website/tests/homepage.spec.ts index e3e9059..3dbcdc6 100644 --- a/website/tests/homepage.spec.ts +++ b/website/tests/homepage.spec.ts @@ -50,9 +50,9 @@ test.describe('Homepage', () => { } }); - test('command types section shows all 19 types', async ({ page }) => { + test('command types section shows all 21 types', async ({ page }) => { const commandTypes = page.locator('.command-type'); - await expect(commandTypes).toHaveCount(19); + await expect(commandTypes).toHaveCount(21); const expectedTypes = [ 'Shell Scripts', @@ -73,6 +73,8 @@ test.describe('Homepage', () => { 'Composer Scripts', 'Docker Compose', '.NET Projects', + 'C# Scripts', + 'F# Scripts', 'Markdown Files', ]; for (const name of expectedTypes) {