Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions extensions/vscode/.vscodeignore
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
# Development/editor state
.vscode/**
.vscode-test/**
src/**
!src/**/*.d.ts
!src/ui/webview/gitpilotWorkspaceTemplate.html
!src/ui/webview/gitpilotWorkspace.css
**/*.map
.gitignore

# Source and build tooling are not runtime assets.
src/**
scripts/**
Makefile
EXTENSION_DOCS.md
tsconfig.json
package-lock.json
node_modules/**

# TypeScript/source maps and temporary files.
**/*.ts
!out/**
# Exclude Windows "Copy" artifacts (e.g., "extension copy.ts")
**/*.tsx
**/*.map
**/* copy*.ts
**/* copy*.tsx
**/* copy*.js
**/*.copy.ts
**/*.backup.ts
**/*.bak.ts
**/*.bak.ts

# Previously generated packages should not be nested in new packages.
*.vsix

# Keep compiled runtime output and public assets.
!out/**
!resources/**
!README.md
!CHANGELOG.md
!LICENSE
19 changes: 14 additions & 5 deletions extensions/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,13 @@
},
{
"id": "gitpilot.sessionsView",
"name": "Sessions"
"name": "Sessions",
"visibility": "collapsed"
},
{
"id": "gitpilot.skillsView",
"name": "Skills & Plugins"
"name": "Skills & Plugins",
"visibility": "collapsed"
}
]
},
Expand Down Expand Up @@ -726,17 +728,24 @@
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"vscode:prepublish": "npm run compile && node scripts/remove-source-maps.js",
"compile": "tsc -p ./ && node scripts/copy-webview-assets.js",
"watch": "tsc -watch -p ./",
"lint": "eslint src --ext ts",
"lint": "node scripts/lint.js",
"package": "vsce package",
"publish": "vsce publish"
"publish": "vsce publish",
"reinstall-vsix": "npm run package && node scripts/install-latest-vsix.js"
},
"devDependencies": {
"@types/node": "^20.19.39",
"@types/vscode": "^1.110.0",
"@vscode/vsce": "^2.22.0",
"typescript": "^5.9.3"
},
"capabilities": {
"untrustedWorkspaces": {
"supported": "limited",
"description": "GitPilot can inspect trusted-safe workspace metadata in restricted mode, but blocks file modifications, terminal execution, package/plugin installation, commits, pushes, and other generated tool execution until the workspace is trusted."
}
}
}
4 changes: 4 additions & 0 deletions extensions/vscode/scripts/copy-webview-assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const filesToCopy = [
from: path.join(root, "src", "ui", "webview", "gitpilotWorkspace.css"),
to: path.join(root, "out", "ui", "webview", "gitpilotWorkspace.css"),
},
{
from: path.join(root, "src", "ui", "webview", "gitpilotWorkspace.js"),
to: path.join(root, "out", "ui", "webview", "gitpilotWorkspace.js"),
},
{
from: path.join(root, "src", "ui", "webview", "gitpilotSettingsTemplate.html"),
to: path.join(root, "out", "ui", "webview", "gitpilotSettingsTemplate.html"),
Expand Down
32 changes: 32 additions & 0 deletions extensions/vscode/scripts/install-latest-vsix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env node
const { spawnSync } = require("node:child_process");
const fs = require("node:fs");
const path = require("node:path");

const root = path.resolve(__dirname, "..");
const vsix = fs
.readdirSync(root)
.filter((name) => name.endsWith(".vsix"))
.map((name) => ({ name, mtime: fs.statSync(path.join(root, name)).mtimeMs }))
.sort((a, b) => b.mtime - a.mtime)[0];

if (!vsix) {
console.error("No .vsix file found. Run `npm run package` first.");
process.exit(1);
}

const vsixPath = path.join(root, vsix.name);
console.log(`Installing ${vsixPath} ...`);

const result = spawnSync("code", ["--install-extension", vsixPath, "--force"], {
cwd: root,
stdio: "inherit",
shell: process.platform === "win32",
});

if (result.error) {
console.error(result.error.message);
process.exit(1);
}

process.exit(result.status ?? 0);
83 changes: 83 additions & 0 deletions extensions/vscode/scripts/lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env node
/*
* Lightweight local lint gate for the VS Code extension.
*
* This intentionally avoids a global eslint dependency so `npm run lint` works
* on Windows after `npm install` with the dependencies already in package-lock.
* It performs the highest-signal local checks that are always available:
* TypeScript no-emit validation and a few repository hygiene checks.
*/
const { spawnSync } = require("node:child_process");
const fs = require("node:fs");
const path = require("node:path");

const root = path.resolve(__dirname, "..");
const srcRoot = path.join(root, "src");
const isWindows = process.platform === "win32";
const tscBin = path.join(
root,
"node_modules",
".bin",
isWindows ? "tsc.cmd" : "tsc"
);

function walk(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (entry.name === "node_modules" || entry.name === "out") {
continue;
}

const absolute = path.join(dir, entry.name);
if (entry.isDirectory()) {
walk(absolute, files);
} else if (entry.isFile() && absolute.endsWith(".ts")) {
files.push(absolute);
}
}
return files;
}

function fail(message) {
console.error(`[lint] ${message}`);
process.exitCode = 1;
}

if (!fs.existsSync(tscBin)) {
fail("TypeScript is not installed. Run `npm install` in extensions/vscode first.");
} else {
const result = spawnSync(tscBin, ["--noEmit", "-p", root], {
cwd: root,
stdio: "inherit",
shell: false,
});
if (result.status !== 0) {
fail("TypeScript no-emit validation failed.");
}
}

for (const file of walk(srcRoot)) {
const text = fs.readFileSync(file, "utf8");
const relative = path.relative(root, file).replace(/\\/g, "/");

if (/\r\n/.test(text)) {
fail(`${relative}: use LF line endings.`);
}

if (/[ \t]+$/m.test(text)) {
fail(`${relative}: remove trailing whitespace.`);
}

if (!text.endsWith("\n")) {
fail(`${relative}: add a trailing newline.`);
}

if (/try\s*\{\s*(?:import\s|(?:const|let|var)\s+[^=]+\s*=\s*require\()/m.test(text)) {
fail(`${relative}: do not wrap imports in try/catch blocks.`);
}
}

if (process.exitCode) {
process.exit(process.exitCode);
}

console.log("[lint] TypeScript and repository hygiene checks passed.");
25 changes: 25 additions & 0 deletions extensions/vscode/scripts/remove-source-maps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env node
const fs = require("node:fs");
const path = require("node:path");

const outDir = path.resolve(__dirname, "..", "out");
let removed = 0;

function walk(dir) {
if (!fs.existsSync(dir)) {
return;
}

for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const absolute = path.join(dir, entry.name);
if (entry.isDirectory()) {
walk(absolute);
} else if (entry.isFile() && entry.name.endsWith(".map")) {
fs.rmSync(absolute, { force: true });
removed += 1;
}
}
}

walk(outDir);
console.log(`Removed ${removed} source map file(s) from ${path.relative(process.cwd(), outDir) || outDir}.`);
Loading
Loading