This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is the official Puppet extension for Visual Studio Code — a TypeScript VSCode extension client. It does not contain the Puppet language intelligence itself; that lives in the Puppet Editor Services language server (Ruby), which is downloaded and bundled at build time ("vendored"). This repo is primarily a Language Server Protocol (LSP) client plus VSCode-specific features (commands, views, debugging, status bar).
The build is driven by psake (PowerShell), not plain npm. PowerShell (pwsh) and the psake module are required. The npm build/watch scripts shell out to build.ps1.
npm install # install node deps
npm run build # full build: npm install + vendor + tsc (via build.ps1 -> psakefile.ps1)
npm run compile # TypeScript compile only (tsc -p ./), output to ./out
npm run watch # build once, then tsc -watch
./build.ps1 -task clean,vendor # re-download the language server + syntax (see Vendoring below)To run/debug the extension interactively: open the repo in VSCode and press F5 (launches an Extension Development Host). Vendored resources must exist first (./build.ps1 -task vendor).
npm run lint # eslint --ext .ts src
npm run fix # eslint --fix
npm run format # prettier --write on **/*.{ts,js,json}
npm test # compiles, then runs integration tests in a headless VSCode (out/test/runtest.js)
npm run test:coverage # same, with nyc/lcov coverageTests are VSCode integration tests (Mocha, tdd UI, chai + sinon), launched via @vscode/test-electron which downloads a real VSCode and runs the suite inside it — there is no pure-unit mocha runner. src/test/runtest.ts is the entry point; src/test/suite/index.ts globs **/*.test.js from the compiled out/test dir. Because tests run compiled JS, you must npm run compile (or npm test which does it via pretest) before test changes take effect. There is no built-in single-test filter in the npm scripts; narrow runs by temporarily using Mocha's .only or commenting the glob.
Note: many tests resolve a real PDK/Puppet install path; CI installs the PDK on each OS before running (see .github/workflows/vscode-ci.yml). The full suite is run across Linux/Windows/macOS.
The language server and syntax grammar are not committed — they are fetched into vendor/ during the build. psakefile.ps1 reads the editorComponents block in package.json to decide what to fetch:
editorServices.release/editorSyntax.release— download a tagged GitHub release (default).githubref/githubuser/githubrepo— fetch from a specific repo/branch instead.directory— copy from a local checkout (useful when developing the language server alongside this extension).
The VendorEditorServices / VendorEditorSyntax tasks have preconditions that skip if vendor/languageserver or syntaxes/puppet.tmLanguage already exist, so run clean first to force a refresh. See README_BUILD.md for all options. Cytoscape (used by the node graph) is also vendored from node_modules.
The extension entry point is src/extension.ts (activate/deactivate). Activation flow:
- Reads VSCode workspace settings →
ISettings(src/settings.ts), warns on legacy/deprecated settings. - Builds an
IAggregateConfiguration(src/configuration.ts) — this resolves the abstract settings into concrete paths: which Puppet install to use (PDK vs Agent,auto-detected), Ruby dirs, RUBYLIB/PATH env, SSL paths, and PDK Ruby instance discovery (src/configuration/pdkResolver.ts, src/configuration/pathResolver.ts). This is the single source of truth for "how do I invoke the bundled Ruby". - Constructs a list of Features and a ConnectionHandler.
Every discrete capability is an IFeature (a vscode.Disposable, src/feature.ts). They live in src/feature/ and are instantiated into extensionFeatures[] in activate(), then all disposed in deactivate(). To add a capability, create a new IFeature and push it onto that array. Examples: PDKFeature (PDK commands), DebuggingFeature, FormatDocumentFeature, PuppetNodeGraphFeature, PuppetStatusBarFeature, the Puppetfile hover/completion features.
src/handler.ts defines the abstract ConnectionHandler wrapping a vscode-languageclient LanguageClient. Two concrete subclasses choose the transport based on puppet.editorService.protocol:
- src/handlers/stdio.ts —
StdioConnectionHandler(default): spawns the bundledpuppet-languageserverRuby process over stdio. - src/handlers/tcp.ts —
TcpConnectionHandler: connects to a local or remote editor services over TCP.
The handler starts the client, listens for telemetry, and polls PuppetVersionRequest to drive the status bar ("Loading facts/functions/types/classes…"). Custom LSP message types are in src/messages.ts.
- src/views/ —
TreeDataProviders for the Puppet activity-bar toolbar (Facts, Puppetfile). Registered at the end ofactivate(). - src/logging/ —
ILoggerimplementations (output channel, file, stdout, null). - src/telemetry.ts — Application Insights reporter (
reporter); only command names/config are collected, never file contents. - src/forge.ts — Puppet Forge API calls (e.g. latest PDK version check, module hover info) via axios.
Commands, menus, language definitions (puppet, puppetfile), grammars, snippets, the debugger type, the activity-bar view container, and all puppet.* configuration settings are declared in the contributes block of package.json. When adding a command, register it in both contributes.commands and the relevant menu group, and wire its handler in a feature.
- TypeScript is compiled non-strict (
strict: falsein tsconfig.json); target es6/commonjs, output toout/. - ESLint uses
@typescript-eslintwithprettier; runnpm run fixbefore committing. - Commit messages: first line ≤50 chars, imperative mood, prefixed with the GitHub issue as
(GH-XXXX) message(see CONTRIBUTING.md). Branch naming:GH-1234-short_description. - The two language IDs (
puppet,puppetfile) and the debugger type (Puppet) are hardcoded constants in src/extension.ts and must not change.
- At the start of a coding session, review the repository structure and any relevant README or documentation files to understand the area you are working in.
- Always read the files relevant to the task before suggesting or making a change.
- Never merge a pull request.
- Never work directly on the
mainormasterbranch. - Never push a branch without explicit instruction.
- Never delete a file without permission — this applies even after a blanket "yes to all".
- Never output, log, save, or hardcode security-sensitive values — this includes passwords, tokens, API keys, private keys, secrets, and credentials of any kind. Do not write them to files, include them in commit messages, or print them in responses.