- Fix critical bugs: coder-agent name (CoderAgent→coder-agent), manifest path in session-start.sh, /oac:setup ghost command replaced with /install-context - Fix hooks.json: add timeout/async, add description, restore matcher - Fix session-start.sh: dual-format output (Claude Code + Cursor/OpenCode), remove invalid JSON escapes for $ and backtick - Fix agent spec compliance: disallowedTools on read-only agents, WebFetch on external-scout, haiku model on context-scout, example blocks on 3 agents - Fix skill descriptions: triggering conditions only (no workflow summaries) per superpowers empirical testing — prevents Claude shortcutting skill content - Add Red Flags + Rationalization tables to 4 discipline skills - Add install-context skill + command replacing oac-setup/oac-plan/oac-add-context - Add cleanup-tmp.sh (was missing, broke /oac:cleanup) - Add TypeScript installer (install-context.ts/js) with profile-based download - Update plugin.json: keywords, homepage for marketplace discoverability - Update README: correct skill count, fix structure diagram, remove stale refs - Remove obsolete files: FIRST-TIME-SETUP.md, INSTALL.md, QUICK-START.md, download-context.sh, verify-context.sh, load-config.sh, context-manager skill, oac-setup/oac-plan/oac-add-context commands
135 lines
3 KiB
TypeScript
135 lines
3 KiB
TypeScript
/**
|
|
* Git Sparse Checkout Utilities
|
|
* Handles git sparse-checkout operations for downloading specific paths
|
|
*/
|
|
|
|
import { execSync } from 'child_process'
|
|
import { existsSync, rmSync, mkdirSync } from 'fs'
|
|
import { join } from 'path'
|
|
|
|
export interface GitSparseOptions {
|
|
repository: string
|
|
branch: string
|
|
paths: string[]
|
|
targetDir: string
|
|
verbose?: boolean
|
|
}
|
|
|
|
export interface GitSparseResult {
|
|
success: boolean
|
|
commit: string
|
|
error?: string
|
|
}
|
|
|
|
/**
|
|
* Clone repository with sparse checkout
|
|
*/
|
|
export async function sparseClone(
|
|
options: GitSparseOptions
|
|
): Promise<GitSparseResult> {
|
|
const { repository, branch, paths, targetDir, verbose } = options
|
|
|
|
try {
|
|
// Clean up target directory if it exists
|
|
if (existsSync(targetDir)) {
|
|
rmSync(targetDir, { recursive: true, force: true })
|
|
}
|
|
|
|
// Create parent directory
|
|
const parentDir = join(targetDir, '..')
|
|
if (!existsSync(parentDir)) {
|
|
mkdirSync(parentDir, { recursive: true })
|
|
}
|
|
|
|
// Clone with sparse checkout (no working tree files)
|
|
if (verbose) {
|
|
console.log(`Cloning ${repository}...`)
|
|
}
|
|
|
|
execSync(
|
|
`git clone --depth 1 --filter=blob:none --sparse --branch ${branch} https://github.com/${repository}.git "${targetDir}"`,
|
|
{ stdio: verbose ? 'inherit' : 'pipe' }
|
|
)
|
|
|
|
// Configure sparse checkout for requested paths
|
|
if (verbose) {
|
|
console.log('Configuring sparse checkout...')
|
|
}
|
|
|
|
const sparseCheckoutPaths = paths.join(' ')
|
|
execSync(`cd "${targetDir}" && git sparse-checkout set ${sparseCheckoutPaths}`, {
|
|
stdio: verbose ? 'inherit' : 'pipe',
|
|
})
|
|
|
|
// Get commit SHA
|
|
const commit = execSync(`cd "${targetDir}" && git rev-parse HEAD`, {
|
|
encoding: 'utf-8',
|
|
}).trim()
|
|
|
|
if (verbose) {
|
|
console.log(`Downloaded commit: ${commit}`)
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
commit,
|
|
}
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
commit: '',
|
|
error: error instanceof Error ? error.message : String(error),
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copy files from sparse checkout to target location
|
|
*/
|
|
export function copyFiles(
|
|
sourceDir: string,
|
|
targetDir: string,
|
|
verbose?: boolean
|
|
): void {
|
|
if (!existsSync(sourceDir)) {
|
|
throw new Error(`Source directory not found: ${sourceDir}`)
|
|
}
|
|
|
|
// Create target directory if it doesn't exist
|
|
if (!existsSync(targetDir)) {
|
|
mkdirSync(targetDir, { recursive: true })
|
|
}
|
|
|
|
// Copy files
|
|
if (verbose) {
|
|
console.log(`Copying files from ${sourceDir} to ${targetDir}...`)
|
|
}
|
|
|
|
execSync(`cp -r "${sourceDir}"/* "${targetDir}"/`, {
|
|
stdio: verbose ? 'inherit' : 'pipe',
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Clean up temporary directory
|
|
*/
|
|
export function cleanup(dir: string, verbose?: boolean): void {
|
|
if (existsSync(dir)) {
|
|
if (verbose) {
|
|
console.log(`Cleaning up ${dir}...`)
|
|
}
|
|
rmSync(dir, { recursive: true, force: true })
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if git is available
|
|
*/
|
|
export function checkGitAvailable(): boolean {
|
|
try {
|
|
execSync('command -v git', { stdio: 'ignore' })
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|