SkillOps is a bundled Node-based VS Code extension with an isolated browser webview. Its host and webview organization keeps product domains separate, lifecycle composition explicit, and browser code isolated from the extension host.
src/
extension.ts activation entry point
container.ts command/provider lifecycle composition
constants.commands.ts typed command identifiers
commands/ VS Code command classes
skills/
models/ skill and generation models
generation/ normalization, paths, deterministic plans
templates/ generated skill assets
skillInput.ts VS Code input flow
skillWriter.ts workspace filesystem boundary
insights/
models/ events, sessions, usage, reports, settings
parser/ partially readable JSONL parsing
usage/ token and rate-limit extraction
analysis/ project matching, skill matching, efficiency
session/ Codex session discovery and skill catalog
claude/ Claude scanning, matching, usage, and activity
gemini/ Gemini scanning, matching, usage, and activity
settings/ normalization and VS Code configuration
insightsService.ts report construction
system/ focused host utilities
sidebar/ static Activity Bar launcher
webviews/
skillCreation/ typed creation panel host and protocol
runInsights/
protocol.ts typed host/guest messages
registration.ts panel descriptor
runInsightsWebview.ts provider and lifecycle
viewModelMapper.ts domain-to-webview mapping
apps/runInsights/
index.html CSP-controlled document shell
styles.css VS Code theme-aware presentation
main.ts browser entry point
app.ts Lit state and message handling
components/ focused Lit render components
apps/skillCreation/ native-styled Lit creation form
scripts/
build.mjs extension and webview production builds
test/
unit/ domain and webview integration tests
fixtures/ representative inputs and expected data
models/parsers → domain services → commands/webview providers → container → extension
protocol → webview provider and browser app
The container composes commands and long-lived webview providers. Business domains do not import commands, the container, or extension activation. The browser app imports only its serializable protocol and browser-safe components.
Skills and insights do not import commands or webview code. Cross-domain lifecycle coordination belongs in src/container.ts.
The Activity Bar container hosts a static native tree that groups actions under Codex, Claude, and Gemini. Creating or resolving the tree performs no session I/O. Session discovery starts only after the user invokes Show Run Insights.
skills/generation/skillGenerator.ts creates a deterministic plan without importing VS Code. skills/skillPlanExecutor.ts executes discriminated operations against a small target contract and is tested independently. skills/skillWriter.ts implements that contract with workspace.fs; input collection and command orchestration remain separate.
VS Code has no atomic multi-file write API. Filesystem operations therefore run sequentially to make partial-failure reporting deterministic. Parallel writes would introduce parent-directory races and unpredictable partial output. Existing skill directories are rejected before the first write.
The ordered executor is a promise reduction rather than a mutable write loop. Generation and analysis use immutable map, flatMap, filter, find, and reduce pipelines where they make the transformation clearer. Imperative control flow is retained only at lifecycle and external-I/O boundaries where it better expresses cancellation, disposal, or error translation.
Repeated product identifiers are centralized rather than scattered: commands in src/constants.commands.ts, generated paths and messages in the skills domain, Codex schemas and configuration in the insights domain, and typed webview message names in src/webviews/runInsights/protocol.ts.
Creation commands select the target workspace before opening one reusable creation panel. Its Lit form collects the name, description, scripts-folder option, and assets-folder option, while the extension host remains responsible for normalization, duplicate protection, and ordered writes.
The extension host reads configured Codex, Claude, and Gemini homes without modifying them. Shared parsing, report models, and webview mapping stay provider-neutral; provider-specific scanning, matching, and usage behavior lives in claude/, gemini/, or the existing Codex-focused modules. insightsService.ts selects and composes the requested provider.
Run Insights has an explicit protocol, registration descriptor, provider, and app. RunInsightsWebviewProvider owns only panel lifecycle, asset resolution, refresh scheduling, and typed messaging. It loads packaged HTML, CSS, and JavaScript files from dist/webview; no browser application code is embedded in the extension host.
The provider creates or reveals one panel before starting asynchronous discovery. Refresh requests are sequenced, so results from an older scan cannot replace a newer report. The Lit app owns the selected skill and run and preserves both while they remain present in refreshed data.
The browser application is a Lit custom element and owns selectors and visual state. It has no filesystem or network access. Lit escapes interpolated untrusted values, and the document enforces a strict Content Security Policy with a nonce-protected local script.
scripts/build.mjs produces two bundles:
dist/extension.jsfor the Node extension host;dist/webview/run-insights.jsfor the browser.
It also copies the HTML and CSS assets. Production packaging disables source maps and .vscodeignore excludes sources, tests, fixtures, scripts, and development configuration.