Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
dcfc24b
feat: Add webview utilities and login page for TaskSync Remote
sgaabdu4 Mar 23, 2026
844257d
refactor: Clean up formatting in tool call handling and webview types
sgaabdu4 Mar 23, 2026
167b6e2
fix: address Copilot PR review feedback
sgaabdu4 Mar 23, 2026
1904344
security: bundle mermaid locally, remove CDN dependency
sgaabdu4 Mar 23, 2026
1a3e4e2
style: format code for consistency and readability across multiple files
sgaabdu4 Mar 23, 2026
b3b47fd
style: fix biome formatting issues
sgaabdu4 Mar 23, 2026
ab3521a
fix: address second round of Copilot PR review feedback
sgaabdu4 Mar 23, 2026
f9b130e
fix: address third round of Copilot PR review feedback
sgaabdu4 Mar 24, 2026
9bc6ada
refactor: DRY gitService resolveFilePath helper, add cert host-parsin…
sgaabdu4 Mar 24, 2026
b45bf23
docs: add .github/copilot-instructions.md for Copilot code review
sgaabdu4 Mar 24, 2026
6d872a6
docs: add path-specific Copilot code review instructions
sgaabdu4 Mar 24, 2026
3e071fe
docs: sync AGENTS.md with copilot-instructions.md
sgaabdu4 Mar 24, 2026
9314309
fix: handle undefined attachments in queue prompts and improve error …
sgaabdu4 Mar 24, 2026
2bbc6be
docs: add intentional-limitation comment to esbuild regex extractor
sgaabdu4 Mar 24, 2026
c2347d5
fix: address round-5 Copilot review comments
sgaabdu4 Mar 24, 2026
c895401
fix: revert summary wording to ALWAYS, remove query length cap
sgaabdu4 Mar 24, 2026
d647049
fix: format code for better readability in tools and persistence modules
sgaabdu4 Mar 24, 2026
77eb5c6
fix: remove unnecessary defensive code from Copilot review
sgaabdu4 Mar 24, 2026
13011fe
restore: keep defensive coding in tools.ts and terminalContext.ts
sgaabdu4 Mar 24, 2026
4072de1
ci: add duplicate-block scanner, CI workflow, pre-push hook, and call…
sgaabdu4 Mar 24, 2026
e44d88b
ci: auto-activate git hooks on npm install
sgaabdu4 Mar 24, 2026
92b702e
fix: address Round 6 Copilot review comments
sgaabdu4 Mar 24, 2026
ffa13af
fix: address Round 7 Copilot review comments
sgaabdu4 Mar 24, 2026
1f043ea
docs: clarify reconnection constants are build-script defaults in esb…
sgaabdu4 Mar 24, 2026
e898563
docs: update .github/instructions and documentation with Round 7 changes
sgaabdu4 Mar 24, 2026
f2045bc
fix: async I/O, unified scanner, MCP hardening, CSP tightening
sgaabdu4 Mar 24, 2026
412abb9
fix: resolve Copilot review comments (round 8)
sgaabdu4 Mar 24, 2026
7b1f119
fix: dispose cancelled flag, stale-execution timestamp, test organiza…
sgaabdu4 Mar 24, 2026
477d148
fix: import path, resolve formatting, rename _MAX_OUTPUT_BYTES
sgaabdu4 Mar 24, 2026
fec6642
fix: correct formatting in index.ts and remoteSettingsHandler.ts
sgaabdu4 Mar 24, 2026
afbb6d4
fix: safe server.close, no-op reorder guard, unref sound processes
sgaabdu4 Mar 24, 2026
e6ded72
fix: guard disposeProvider against non-function resolvers in pendingR…
sgaabdu4 Mar 24, 2026
dfd4389
fix: restore mocks, format index signature, add [TaskSync] error prefix
sgaabdu4 Mar 24, 2026
d57c0f8
docs: add TLS-optional and PWA install tips to Tailscale section
sgaabdu4 Mar 24, 2026
b603a32
fix: show 'Working…' indicator immediately on remote send
sgaabdu4 Mar 24, 2026
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
26 changes: 26 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh
# Pre-push hook: runs build, type-check, tests, lint, and duplicate scanner
# Install: git config core.hooksPath .githooks

set -e

echo "🔍 Running pre-push checks..."

cd tasksync-chat

echo "📦 Building..."
node esbuild.js > /dev/null 2>&1

echo "🔎 Type-checking..."
npx tsc --noEmit

echo "🧪 Running tests..."
npx vitest run

echo "🧹 Linting..."
npm run lint

echo "🔁 Running code quality checks..."
node scripts/check-code-quality.js

echo "✅ All pre-push checks passed!"
102 changes: 102 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# TaskSync — Copilot Repository Instructions

## What This Repository Does

TaskSync is a human-in-the-loop workflow toolkit for AI-assisted development. The primary codebase is the VS Code extension in `tasksync-chat/`. It provides a sidebar with smart prompt queuing, Autopilot mode, an MCP server, and remote access via WebSocket.

## Project Layout

- `tasksync-chat/src/extension.ts` — Extension entry point
- `tasksync-chat/src/tools.ts` — VS Code language model tool definitions (`ask_user`)
- `tasksync-chat/src/webview/webviewProvider.ts` — Orchestrator: owns state, creates webview, delegates to handlers
- `tasksync-chat/src/webview/webviewTypes.ts` — Shared types (`P` interface, message unions)
- `tasksync-chat/src/webview/webviewUtils.ts` — Shared helpers (`debugLog()`, `mergeAndDedup()`, `notifyQueueChanged()`)
- `tasksync-chat/src/webview/*Handlers.ts` — Handler modules receive a `P` interface (no circular imports)
- `tasksync-chat/src/mcp/mcpServer.ts` — MCP server (Streamable HTTP, port 3579)
- `tasksync-chat/src/server/` — Remote server, auth, git operations, HTML service
- `tasksync-chat/src/constants/` — Shared constants (config keys, file exclusions, remote constants)
- `tasksync-chat/src/context/` — Context providers (files, terminal, problems)
- `tasksync-chat/src/utils/` — Utilities (ID generation, image handling)
- `tasksync-chat/esbuild.js` — Build script (extension, webview, shared constants, mermaid)
- `tasksync-chat/biome.json` — Biome linter/formatter config
- `tasksync-chat/vitest.config.ts` — Test config
- `tasksync-chat/web/` — Remote access PWA (login, service worker)
- `Prompt/` — Standalone prompt/protocol markdown files (not actively developed)

## Build, Test, and Validate

All commands run from `tasksync-chat/`:

```bash
cd tasksync-chat
npm install # Always run first
npm run validate # Full validation: build + tsc + test + lint + code quality scanner
```

Or run individually:

```bash
node esbuild.js # Build → dist/extension.js, media/webview.js, web/shared-constants.js
npx tsc --noEmit # Type-check (must produce 0 errors)
npx vitest run # Run all tests (387+ tests, must all pass)
npm run lint # Biome lint (must produce 0 issues)
npm run check-code # Code quality scanner (duplicates, sync I/O, etc.)
```

Always run these four checks (build, tsc, vitest, lint) after making changes. The CI workflow (`.github/workflows/auto-release.yml`) runs on pushes to `main` — it installs deps, builds, version-bumps, packages VSIX, and creates a GitHub release.

Build output: `dist/` (extension bundle), `media/webview.js` (webview bundle), `web/shared-constants.js` (auto-generated for remote PWA).

## Code Style and Conventions

- **TypeScript** with `"strict": true`, ES2022 target, CommonJS modules
- **Indentation:** Tabs (enforced by Biome)
- **Quotes:** Double quotes (enforced by Biome)
- **Imports:** Auto-organized by Biome (`organizeImports: on`)
- **Type assertions:** Use `satisfies` over `as` (e.g., `} satisfies ToWebviewMessage`). `satisfies` validates shape at compile time; `as` silently bypasses checks.
- **Async I/O:** Always prefer async file operations over synchronous equivalents. Never use synchronous blocking calls on the extension host.
- **Logging:** Use `debugLog()` from `webviewUtils.ts` (gated behind `tasksync.debugLogging` config). Use `console.error` only for genuine errors. Never use `console.log` or `console.warn` in production code.
- **Changelog:** Update `CHANGELOG.md` for every user-facing change using the format `## TaskSync vX.Y.Z (MM-DD-YY)` (two-digit year).

## SSOT / DRY / KISS / YAGNI Principles

These principles are mandatory for all changes:

- **Single Source of Truth (SSOT):** Every concept, constant, type, or piece of logic must have exactly one canonical definition. Do not duplicate config keys, message types, validation logic, or shared helpers. Constants live in `src/constants/`. Shared types live in `webviewTypes.ts`. Shared helpers live in `webviewUtils.ts`.
- **Don't Repeat Yourself (DRY):** If logic is used in more than one place, extract it into a shared helper. Examples already in the codebase: `debugLog()`, `mergeAndDedup()`, `notifyQueueChanged()`, `hasQueuedItems()`, `resolveFilePath()` (gitService). When you see the same pattern in 3+ call sites, extract it.
- **Keep It Simple, Stupid (KISS):** Prefer the simplest solution that works. Do not add abstraction layers, configuration options, or indirection without clear justification. A small amount of duplication is acceptable if the alternative is a complex abstraction for only 2 call sites.
- **You Aren't Gonna Need It (YAGNI):** Do not add features, parameters, or code paths "just in case." Only implement what is needed for the current task. Do not design for hypothetical future requirements.
- **Handler pattern:** All handler modules (`*Handlers.ts`) receive a `P` interface — do not add direct imports from `webviewProvider.ts`. This prevents circular dependencies.

## Security Best Practices

Follow OWASP Top 10 principles. Specific patterns enforced in this codebase:

- **Timing-safe comparison:** Use `crypto.timingSafeEqual` with fixed-length digests (SHA-256) for PIN/secret comparison — never early-return on length differences. See `remoteAuthService.ts` `comparePinTimingSafe()`.
- **Path traversal prevention:** All file paths from remote clients must be validated with `isValidFilePath()` in `gitService.ts` — rejects `..`, absolute paths (when no workspace), null bytes, backticks, and shells metacharacters. Use `path.isAbsolute()` instead of `startsWith("/")` for cross-platform correctness.
- **Command injection prevention:** Use `child_process.spawn` with argument arrays — never `exec` or string interpolation in shell commands. See `gitService.ts` `unstage()`.
- **No credentials in code:** Never commit secrets, API keys, or tokens. Auth uses ephemeral PINs with session tokens and lockout after failed attempts.
- **Input validation at boundaries:** Validate all user/remote input at the entry point. Trust internal code and framework guarantees — do not add redundant validation deep in call stacks.
- **TLS certificates:** `generateSelfSignedCert` strips ports and brackets from hosts before SAN detection. Always test IPv4, IPv6 (`::1`), bracketed IPv6 (`[::1]:port`), and hostname:port formats.
- **Security headers:** Set `Content-Security-Policy`, `X-Content-Type-Options`, `X-Frame-Options`, and `X-XSS-Protection` on all HTTP responses. See `serverUtils.ts` `setSecurityHeaders()`.
- **Origin validation:** Check `Origin` and `Host` headers on WebSocket upgrade requests. See `serverUtils.ts` `isAllowedOrigin()`.

## Testing Strategy

- **Framework:** Vitest, 14 test files, 387+ tests, ~98% coverage
- **VS Code mock:** `src/__mocks__/vscode.ts` — mocks VS Code API for unit tests
- **Test setup:** Tests that use git operations must set `(vscode.workspace as any).workspaceFolders` in `beforeEach`
- **Coverage requirement:** Maintain or improve coverage. Add tests for new logic, especially:
- Security-sensitive code (auth, path validation, input parsing)
- Edge cases in parsing (IPv6, ports, special characters)
- Error handling paths

## Architecture Notes

- The `ask_user` tool (registered in `tools.ts`, handled in `toolCallHandler.ts`) is the core interaction primitive.
- Queue, history, and settings are per-workspace (workspace-scoped storage with global fallback).
- Session state uses a boolean `sessionTerminated` flag — do not use string matching for termination detection.
- Debounced history saves (2 s) for disk I/O performance.
- Remote server uses WebSocket over HTTP with PIN-based auth and session tokens.
- MCP server uses Streamable HTTP transport with `/sse` backward-compat routing.
- `esbuild.js` watch mode monitors `remoteConstants.ts` changes and rebuilds shared constants with 100ms debounce.
42 changes: 42 additions & 0 deletions .github/instructions/security.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
applyTo: "tasksync-chat/src/server/**"
---

# Security Standards (Server Code)

All code in `src/server/` handles remote client connections and must follow strict security practices.

## Timing-Safe Comparison
- Use `crypto.timingSafeEqual` with fixed-length SHA-256 digests for PIN/secret comparison
- Never early-return on length differences — hash both inputs first
- See `remoteAuthService.ts` `comparePinTimingSafe()` for the pattern

## Path Traversal Prevention
- All file paths from remote clients must be validated with `isValidFilePath()` in `gitService.ts`
- Reject `..`, null bytes, backticks, and shell metacharacters
- Absolute paths are only allowed when they resolve under the workspace root
- Normalize backslashes to forward slashes before validation (Windows compatibility)
- Use `path.isAbsolute()` instead of `startsWith("/")` for cross-platform correctness
- Use the shared `resolveFilePath()` helper for getDiff/stage/unstage/discard operations

## Command Injection Prevention
- Use `child_process.spawn` with argument arrays — never `exec` or string interpolation
- See `gitService.ts` `unstage()` for the correct pattern

## Auth
- Auth uses ephemeral PINs with session tokens and lockout after failed attempts
- Never commit secrets, API keys, or tokens

## Input Validation
- Validate all user/remote input at the entry point (system boundary)
- Trust internal code and framework guarantees — no redundant validation deep in call stacks

## TLS Certificates
- `generateSelfSignedCert` strips ports and brackets from hosts before SAN detection
- Always test IPv4, IPv6 (`::1`), bracketed IPv6 (`[::1]:port`), and hostname:port formats

## HTTP Security
- Set `Content-Security-Policy`, `X-Content-Type-Options`, `X-Frame-Options`, `X-XSS-Protection: 0` on all responses
- Use `X-XSS-Protection: 0` (not `1; mode=block`) \u2014 the built-in XSS auditor is deprecated and can introduce vulnerabilities; CSP is the proper mitigation
- Check `Origin` and `Host` headers on WebSocket upgrade requests
- See `serverUtils.ts` `setSecurityHeaders()` and `isAllowedOrigin()`
26 changes: 26 additions & 0 deletions .github/instructions/testing.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
applyTo: "**/*.test.ts"
---

# Testing Standards

## Framework
- Vitest with 387+ tests across 14 test files (~98% coverage)
- VS Code API is mocked in `src/__mocks__/vscode.ts`

## Test Setup
- Tests that use git operations must set `(vscode.workspace as any).workspaceFolders` in `beforeEach`
- Always call `vi.restoreAllMocks()` in `beforeEach` to prevent test pollution

## Coverage
- Maintain or improve the current ~98% coverage
- Add tests for security-sensitive code (auth, path validation, input parsing)
- Add tests for edge cases (IPv6, ports, special characters, Windows paths)
- Add tests for error handling paths

## Patterns
- Use `describe` blocks grouped by function or class method
- Use descriptive test names: "throws for invalid file path", "strips port from hostname"
- Test both happy paths and error conditions
- For async operations, use `await expect(...).rejects.toThrow()`
- Import constants from `remoteConstants.ts` in tests — do not hard-code values (SSOT)
36 changes: 36 additions & 0 deletions .github/instructions/typescript.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
applyTo: "**/*.ts,**/*.tsx"
---

# TypeScript Conventions

## Strict Mode
- TypeScript strict mode is enabled — do not use `any` or suppress type errors with `as` casts
- Use `satisfies` over `as` for message types (e.g., `} satisfies ToWebviewMessage`)
- `satisfies` validates shape at compile time; `as` silently bypasses checks

## Style
- Indentation: tabs (enforced by Biome)
- Quotes: double quotes (enforced by Biome)
- Imports: auto-organized by Biome — do not manually reorder

## Async I/O
- Always prefer async file operations over synchronous equivalents
- Never use synchronous blocking calls on the VS Code extension host

## Logging
- Use `debugLog()` from `webviewUtils.ts` for debug output (gated behind `tasksync.debugLogging`)
- Use `console.error` only for genuine error/failure paths
- Never use `console.log` or `console.warn` in production code

## SSOT / DRY
- Constants live in `src/constants/` — do not duplicate config keys
- Shared types live in `webviewTypes.ts` — one canonical definition per type
- Shared helpers live in `webviewUtils.ts` — extract repeated logic (3+ call sites) into helpers
- Handler modules (`*Handlers.ts`) receive a `P` interface — do not import from `webviewProvider.ts` directly

## KISS / YAGNI
- Prefer the simplest solution that works
- Do not add abstraction layers without clear justification
- Do not add features or code paths "just in case"
- Small duplication is acceptable if the alternative is complex abstraction for only 2 call sites
27 changes: 27 additions & 0 deletions .github/instructions/webview.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
applyTo: "tasksync-chat/src/webview/**"
---

# Webview Architecture

## Handler Pattern
- All handler modules (`*Handlers.ts`) receive a `P` interface (from `webviewTypes.ts`)
- Do not import directly from `webviewProvider.ts` — this prevents circular dependencies
- `webviewProvider.ts` is the orchestrator: owns state, creates webview, delegates to handlers

## Shared Helpers (DRY)
- Shared logic lives in `webviewUtils.ts`: `debugLog()`, `mergeAndDedup()`, `notifyQueueChanged()`, `hasQueuedItems()`
- When the same pattern appears in 3+ handler files, extract it to `webviewUtils.ts`

## Types
- Shared types live in `webviewTypes.ts` — one canonical definition per message type
- Use `satisfies` for message type validation (e.g., `} satisfies ToWebviewMessage`)

## Session State
- Uses a boolean `sessionTerminated` flag — do not use string matching for termination detection
- Debounced history saves (2 s) for disk I/O performance

## Storage
- Queue, history, and settings are per-workspace (workspace-scoped storage with global fallback)
- Queue enforces `MAX_QUEUE_SIZE` (100) and `MAX_QUEUE_PROMPT_LENGTH` (100000) limits
- Use `await fs.promises.mkdir(path, { recursive: true })` for directory creation \u2014 never `fs.existsSync`
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI

on:
pull_request:
branches: [main]
paths:
- 'tasksync-chat/**'
- '.github/workflows/ci.yml'

jobs:
validate:
runs-on: ubuntu-latest
defaults:
run:
working-directory: tasksync-chat
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: tasksync-chat/package-lock.json

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Type-check
run: npx tsc --noEmit

- name: Test
run: npm test

- name: Lint
run: npm run lint

- name: Code quality checks
run: npm run check-code
Loading
Loading