@3lineas/grooveskills 1.1.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/domains/detector/project-detector.ts","../src/domains/detector/detect-agents.ts","../src/domains/detector/detect-dependencies.ts","../src/domains/registry/skill-catalog.ts","../src/domains/ui/ui-orchestrator.ts","../src/domains/ui/banners.ts","../src/domains/ui/prompt-skills.ts","../src/domains/ui/prompt-agents.ts","../src/domains/ui/prompt-harness.ts","../src/domains/ui/prompt-language.ts","../src/domains/ui/prompt-confirm-overwrite.ts","../src/domains/installer/verify-skill-exists.ts","../src/domains/installer/install-orchestrator.ts","../src/domains/adapters/antigravity.adapter.ts","../src/domains/project-store/project-paths.ts","../src/domains/adapters/link-helper.ts","../src/domains/adapters/claude.adapter.ts","../src/domains/adapters/cursor.adapter.ts","../src/domains/adapters/gemini.adapter.ts","../src/domains/project-store/sync-project-store.ts","../src/domains/installer/resolve-skills-source.ts","../src/domains/harness/install-harness.ts","../src/domains/harness/harness-languages.ts","../src/domains/harness/harness-templates.ts","../src/domains/harness/upsert-agent-instructions.ts","../src/domains/harness/write-project-config.ts","../src/main.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { detectAgents } from \"@/domains/detector/detect-agents\";\nimport { detectDependencies } from \"@/domains/detector/detect-dependencies\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { ProjectContext } from \"@/types/context.types\";\n\nexport function detectProjectContext(targetPath: string): ProjectContext {\n const detectedAgents = detectAgents(targetPath);\n const { dependencies, exists } = detectDependencies(targetPath);\n\n const suggestedSkillIds: string[] = [\n \"odd-ai\",\n \"best-practices\",\n \"ux-writing\",\n \"error-handling-logging\",\n \"clean-architecture-ddd\",\n ];\n\n for (const skill of SKILL_CATALOG) {\n if (skill.dependencies.length === 0) {\n continue;\n }\n const hasMatch = skill.dependencies.some((dep) => dependencies.includes(dep));\n if (hasMatch && !suggestedSkillIds.includes(skill.id)) {\n suggestedSkillIds.push(skill.id);\n }\n }\n\n const harnessExists = existsSync(join(targetPath, \".grooveskills\", \"memory\", \"context.md\"));\n\n return {\n targetPath,\n detectedDependencies: dependencies,\n suggestedSkillIds,\n detectedAgents,\n packageJsonExists: exists,\n harnessExists,\n };\n}\n","import { readdirSync } from \"node:fs\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport function detectAgents(targetPath: string): AgentId[] {\n const detected: AgentId[] = [];\n\n try {\n const entries = new Set(readdirSync(targetPath));\n\n if (entries.has(\".agents\")) {\n detected.push(\"antigravity\");\n }\n if (entries.has(\".claude\")) {\n detected.push(\"claude\");\n }\n if (entries.has(\".cursor\")) {\n detected.push(\"cursor\");\n }\n if (entries.has(\".gemini\")) {\n detected.push(\"gemini\");\n }\n } catch {\n // If directory cannot be read, return empty list gracefully\n }\n\n return detected;\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface PackageJsonDetection {\n dependencies: string[];\n exists: boolean;\n}\n\nexport function detectDependencies(targetPath: string): PackageJsonDetection {\n const detected = new Set<string>();\n let hasManifest = false;\n\n const packageJsonPath = join(targetPath, \"package.json\");\n if (existsSync(packageJsonPath)) {\n hasManifest = true;\n try {\n const raw = readFileSync(packageJsonPath, \"utf-8\");\n const parsed = JSON.parse(raw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n for (const dep of Object.keys(parsed.dependencies ?? {})) {\n detected.add(dep);\n }\n for (const dep of Object.keys(parsed.devDependencies ?? {})) {\n detected.add(dep);\n }\n } catch {\n // Ignore JSON parse errors gracefully\n }\n }\n\n const cargoPath = join(targetPath, \"Cargo.toml\");\n if (existsSync(cargoPath)) {\n hasManifest = true;\n detected.add(\"rust\");\n }\n\n const pyprojectPath = join(targetPath, \"pyproject.toml\");\n const requirementsPath = join(targetPath, \"requirements.txt\");\n if (existsSync(pyprojectPath) || existsSync(requirementsPath)) {\n hasManifest = true;\n detected.add(\"python\");\n }\n\n return {\n dependencies: Array.from(detected),\n exists: hasManifest,\n };\n}\n","import type { SkillMetadata } from \"@/types/skill.types\";\n\nexport const SKILL_CATALOG: SkillMetadata[] = [\n {\n id: \"groove-harness\",\n name: \"GrooveSkills Harness\",\n description: \"Lightweight project harness, context memory, and ODD 3-lane task execution (Answer, Task, Spec) for AI coding agents\",\n dependencies: [],\n directoryName: \"groove-harness\",\n },\n {\n id: \"odd-ai\",\n name: \"Organic & Outcome-Driven Development (ODD)\",\n description: \"7-step ODD protocol for AI agents: authorize, explore, classify, outcome hypotheses, and verifiable evidence receipts\",\n dependencies: [],\n directoryName: \"odd-ai\",\n },\n {\n id: \"best-practices\",\n name: \"Universal Best Practices\",\n description: \"Multi-language clean code standards, early returns, no barrel files, strict typing, <200 lines\",\n dependencies: [],\n directoryName: \"best-practices\",\n },\n {\n id: \"ux-writing\",\n name: \"UX Writing & Microcopy Standards\",\n description: \"Persuasive, empathetic, professional bilingual microcopy (ES/EN) for error messages, forms, CTAs, toasts, and empty states\",\n dependencies: [],\n directoryName: \"ux-writing\",\n },\n {\n id: \"typescript-clean\",\n name: \"TypeScript Clean Code (TS 5.5+)\",\n description: \"Advanced strict TypeScript, discriminated unions, satisfies, const generics, unknown over any, and zero unsafe casts\",\n dependencies: [\"typescript\"],\n directoryName: \"typescript-clean\",\n },\n {\n id: \"rust-clean\",\n name: \"Rust Clean Code (Rust 2024)\",\n description: \"Idiomatic Rust clean code: let-else guard clauses, no unwrap in production, thiserror typed errors, Newtypes, zero barrel files, <200 lines\",\n dependencies: [\"rust\"],\n directoryName: \"rust-clean\",\n },\n {\n id: \"python-clean\",\n name: \"Python Clean Code (Python 3.12+)\",\n description: \"Modern Python standards: guard clauses (no nested ifs), strict typing (zero Any), uv, Ruff, Pyright, Pydantic v2 boundaries, <200 lines\",\n dependencies: [\"python\"],\n directoryName: \"python-clean\",\n },\n {\n id: \"error-handling-logging\",\n name: \"Error Handling & Structured Logging\",\n description: \"Deterministic error management with AppError, Result/ActionResponse contracts, and structured context logging\",\n dependencies: [],\n directoryName: \"error-handling-logging\",\n },\n {\n id: \"valibot-validation\",\n name: \"Valibot Schema Validation\",\n description: \"Boundary schema validation with Valibot (* as v from 'valibot'), strict type inference, and friendly error messages\",\n dependencies: [\"valibot\"],\n directoryName: \"valibot-validation\",\n },\n {\n id: \"clean-architecture-ddd\",\n name: \"Clean Architecture & DDD\",\n description: \"Domain-driven design, isolated single-purpose Actions, pure functions, immutability, zero barrel files, <200 lines per file\",\n dependencies: [],\n directoryName: \"clean-architecture-ddd\",\n },\n {\n id: \"testing-vitest\",\n name: \"Vitest Testing Standards\",\n description: \"Clean unit and integration testing with Vitest: AAA pattern, behavioral testing over mocks, and boundary edge cases\",\n dependencies: [\"vitest\"],\n directoryName: \"testing-vitest\",\n },\n {\n id: \"hono\",\n name: \"Hono Architecture (Valibot)\",\n description: \"Enterprise Hono API standard with Valibot validation, isolated Actions layer, and RPC bindings\",\n dependencies: [\"hono\", \"@hono/valibot-validator\", \"@hono/standard-validator\"],\n directoryName: \"hono\",\n },\n {\n id: \"react-core\",\n name: \"React Core Fundamentals\",\n description: \"Opinionated React fundamentals: function components, JSX, immutable state, core hooks, lists, and controlled inputs\",\n dependencies: [\"react\", \"react-dom\"],\n directoryName: \"react-core\",\n },\n {\n id: \"react-advanced\",\n name: \"React 19 Advanced & Compiler Architecture\",\n description: \"Modern React 19 platform features: React Compiler auto-memoization, concurrent rendering, use(), Actions, virtualization, and RSC boundaries\",\n dependencies: [\"react\", \"react-dom\"],\n directoryName: \"react-advanced\",\n },\n {\n id: \"react-create-page\",\n name: \"React Page & View Architecture\",\n description: \"Clean architecture for React pages: declarative page coordinators, domain hooks, isolated API actions, Valibot + Formisch forms, and atomic co-location\",\n dependencies: [\"react\", \"react-dom\"],\n directoryName: \"react-create-page\",\n },\n];\n","import * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { renderBanner } from \"@/domains/ui/banners\";\nimport { promptSkills } from \"@/domains/ui/prompt-skills\";\nimport { promptAgents } from \"@/domains/ui/prompt-agents\";\nimport { promptHarness } from \"@/domains/ui/prompt-harness\";\nimport { promptLanguage } from \"@/domains/ui/prompt-language\";\nimport { promptConfirmOverwrite } from \"@/domains/ui/prompt-confirm-overwrite\";\nimport { verifySkillExists } from \"@/domains/installer/verify-skill-exists\";\nimport { installSkills } from \"@/domains/installer/install-orchestrator\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { ProjectContext } from \"@/types/context.types\";\nimport type { AgentId } from \"@/types/agent.types\";\nimport type { ProjectLanguage } from \"@/types/harness.types\";\n\nasync function resolveLanguageSelection(harnessEnabled: boolean): Promise<ProjectLanguage> {\n if (!harnessEnabled) {\n return \"es\";\n }\n\n const langChoice = await promptLanguage(\"es\");\n if (p.isCancel(langChoice)) {\n p.cancel(\"Installation cancelled. Have a wonderful day!\");\n process.exit(0);\n }\n\n return langChoice as ProjectLanguage;\n}\n\nasync function resolveOverwriteConfirmation(\n targetPath: string,\n selectedSkills: string[],\n selectedAgents: AgentId[]\n): Promise<boolean> {\n const anyExists = selectedSkills.some((skillId) => {\n const meta = SKILL_CATALOG.find((s) => s.id === skillId);\n return meta ? verifySkillExists(targetPath, meta.directoryName, selectedAgents) : false;\n });\n\n if (!anyExists) {\n return true;\n }\n\n const confirm = await promptConfirmOverwrite();\n if (p.isCancel(confirm) || !confirm) {\n p.cancel(\"Installation stopped to protect existing skills.\");\n process.exit(0);\n }\n\n return Boolean(confirm);\n}\n\nexport async function runInteractiveUi(context: ProjectContext): Promise<void> {\n console.log(renderBanner());\n p.intro(pc.magenta(\"Welcome to GrooveSkills! Let's tailor your AI agents with clean architectural standards.\"));\n\n if (context.detectedDependencies.length > 0) {\n p.note(\n `Detected dependencies: ${context.detectedDependencies.map((d) => pc.bold(d)).join(\", \")}\\n` +\n `Active AI folders: ${context.detectedAgents.map((a) => pc.green(a)).join(\", \") || \"None (will be created)\"}`,\n \"Project Environment\"\n );\n }\n\n const selectedSkills = await promptSkills(context.suggestedSkillIds);\n if (p.isCancel(selectedSkills)) {\n p.cancel(\"Installation cancelled. Have a wonderful day!\");\n process.exit(0);\n }\n\n const selectedAgents = await promptAgents(context.detectedAgents);\n if (p.isCancel(selectedAgents)) {\n p.cancel(\"Installation cancelled. Have a wonderful day!\");\n process.exit(0);\n }\n\n const harnessChoice = await promptHarness(context.harnessExists);\n if (p.isCancel(harnessChoice)) {\n p.cancel(\"Installation cancelled. Have a wonderful day!\");\n process.exit(0);\n }\n\n const harnessEnabled = Boolean(harnessChoice);\n const selectedLanguage = await resolveLanguageSelection(harnessEnabled);\n const forceOverwrite = await resolveOverwriteConfirmation(\n context.targetPath,\n selectedSkills as string[],\n selectedAgents as AgentId[]\n );\n\n const s = p.spinner();\n s.start(\"Installing and adapting skills across your configured AI agents...\");\n\n const result = await installSkills({\n targetPath: context.targetPath,\n selectedSkillIds: selectedSkills as string[],\n selectedAgents: selectedAgents as AgentId[],\n forceOverwrite,\n enableHarness: harnessEnabled,\n detectedDependencies: context.detectedDependencies,\n language: selectedLanguage,\n });\n\n s.stop(pc.green(\"All skills and harness have been successfully configured!\"));\n\n const harnessStatus = result.harnessInitialized\n ? pc.green(`Initialized in .grooveskills/ (Language: ${selectedLanguage})`)\n : pc.dim(\"Skipped\");\n\n p.note(\n `Configured skills: ${result.installedSkills.map((s) => pc.bold(s)).join(\", \")}\\n` +\n `Target agents: ${result.configuredAgents.map((a) => pc.cyan(a)).join(\", \")}\\n` +\n `GrooveSkills Harness: ${harnessStatus}`,\n \"Installation Summary\"\n );\n\n p.outro(pc.green(\"Your AI programming pair is now empowered with your team's architectural habits! 🚀\"));\n}\n","import pc from \"picocolors\";\n\nexport function renderBanner(): string {\n const title = pc.bold(pc.white(\" GROOVE SKILLS \"));\n const badge = pc.bgMagenta(pc.black(title));\n const subtitle = pc.dim(\"Multi-Agent AI Skills & Architectural Standards\");\n\n return `${badge} ${subtitle}\\n`;\n}\n","import * as p from \"@clack/prompts\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\n\nexport async function promptSkills(suggestedSkillIds: string[]): Promise<string[] | symbol> {\n const options = SKILL_CATALOG.map((skill) => {\n const isSuggested = suggestedSkillIds.includes(skill.id);\n return {\n value: skill.id,\n label: skill.name,\n hint: isSuggested ? \"Suggested based on your project stack\" : skill.description,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Which skills would you like to install in this project?\",\n options,\n initialValues: suggestedSkillIds,\n required: true,\n });\n\n return selected;\n}\n","import * as p from \"@clack/prompts\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport async function promptAgents(detectedAgents: AgentId[]): Promise<AgentId[] | symbol> {\n const options: Array<{ value: AgentId; label: string; hint: string }> = [\n { value: \"antigravity\", label: \"Antigravity\", hint: \".agents/skills (Google Agentic IDE)\" },\n { value: \"claude\", label: \"Claude Code\", hint: \".claude/skills (Anthropic Claude Code)\" },\n { value: \"cursor\", label: \"Cursor\", hint: \".cursor/rules/*.mdc (Cursor IDE Rules)\" },\n { value: \"gemini\", label: \"Gemini Code Assist\", hint: \".gemini/skills (Google Gemini)\" },\n ];\n\n const initialValues: AgentId[] = detectedAgents.length > 0 ? detectedAgents : [\"antigravity\"];\n\n const selected = await p.multiselect({\n message: \"Which AI agents should be configured?\",\n options,\n initialValues,\n required: true,\n });\n\n return selected as AgentId[] | symbol;\n}\n","import * as p from \"@clack/prompts\";\n\nexport async function promptHarness(harnessExists: boolean): Promise<boolean | symbol> {\n const message = harnessExists\n ? \"GrooveSkills Harness is already initialized. Would you like to update agent rules and memory templates?\"\n : \"Would you like to initialize the GrooveSkills Harness in .grooveskills/ (project memory, ADR, and 3-lane task execution)?\";\n\n const confirm = await p.confirm({\n message,\n initialValue: true,\n });\n\n return confirm;\n}\n","import * as p from \"@clack/prompts\";\nimport type { ProjectLanguage } from \"@/types/harness.types\";\n\nexport async function promptLanguage(defaultLanguage: ProjectLanguage = \"es\"): Promise<ProjectLanguage | symbol> {\n const options = [\n { value: \"es\", label: \"Español (Spanish)\", hint: \"Recomendado para proyectos en español\" },\n { value: \"en\", label: \"English\", hint: \"Standard international English\" },\n { value: \"pt\", label: \"Português (Portuguese)\", hint: \"Português para o Brasil e Portugal\" },\n { value: \"it\", label: \"Italiano (Italian)\", hint: \"Comunicazione in lingua italiana\" },\n { value: \"fr\", label: \"Français (French)\", hint: \"Communication en langue française\" },\n ];\n\n const selected = await p.select({\n message: \"Which language should AI agents use for user-facing copy and communication?\",\n options,\n initialValue: defaultLanguage,\n });\n\n return selected as ProjectLanguage | symbol;\n}\n","import * as p from \"@clack/prompts\";\n\nexport async function promptConfirmOverwrite(): Promise<boolean | symbol> {\n return await p.confirm({\n message: \"Some skills already exist in this project. Would you like to overwrite them with the latest version?\",\n initialValue: true,\n });\n}\n","import { lstatSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nconst AGENT_DESTINATION_MAP: Record<AgentId, (dir: string) => string> = {\n antigravity: (dir) => join(\".agents\", \"skills\", dir),\n claude: (dir) => join(\".claude\", \"skills\", dir),\n cursor: (dir) => join(\".cursor\", \"rules\", `${dir}.mdc`),\n gemini: (dir) => join(\".gemini\", \"skills\", dir),\n};\n\nexport function verifySkillExists(\n targetPath: string,\n skillDirectoryName: string,\n agents: AgentId[]\n): boolean {\n for (const agent of agents) {\n const relativePathResolver = AGENT_DESTINATION_MAP[agent];\n const destination = join(targetPath, relativePathResolver(skillDirectoryName));\n\n try {\n lstatSync(destination);\n return true;\n } catch {\n // Path does not exist\n }\n }\n\n return false;\n}\n","import { join } from \"node:path\";\nimport { AntigravityAdapter } from \"@/domains/adapters/antigravity.adapter\";\nimport { ClaudeAdapter } from \"@/domains/adapters/claude.adapter\";\nimport { CursorAdapter } from \"@/domains/adapters/cursor.adapter\";\nimport { GeminiAdapter } from \"@/domains/adapters/gemini.adapter\";\nimport { syncProjectStore } from \"@/domains/project-store/sync-project-store\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { installHarness } from \"@/domains/harness/install-harness\";\nimport { writeProjectConfig } from \"@/domains/harness/write-project-config\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { InstallOptions, InstallResult } from \"@/types/installer.types\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nconst ADAPTER_REGISTRY: Record<AgentId, AgentAdapter> = {\n antigravity: new AntigravityAdapter(),\n claude: new ClaudeAdapter(),\n cursor: new CursorAdapter(),\n gemini: new GeminiAdapter(),\n};\n\nexport async function installSkills(options: InstallOptions): Promise<InstallResult> {\n const skillsToInstall = [...options.selectedSkillIds];\n\n if (options.enableHarness && !skillsToInstall.includes(\"groove-harness\")) {\n skillsToInstall.push(\"groove-harness\");\n }\n\n if (options.enableHarness && !skillsToInstall.includes(\"odd-ai\")) {\n skillsToInstall.push(\"odd-ai\");\n }\n\n syncProjectStore(options.targetPath, skillsToInstall, options.selectedAgents);\n\n const projectSkillsDir = getProjectSkillsDir(options.targetPath);\n const createdFiles: string[] = [];\n\n for (const skillId of skillsToInstall) {\n const skill = SKILL_CATALOG.find((item) => item.id === skillId);\n if (!skill) {\n continue;\n }\n\n const skillSourceDir = join(projectSkillsDir, skill.directoryName);\n\n for (const agentId of options.selectedAgents) {\n const adapter = ADAPTER_REGISTRY[agentId];\n if (!adapter) {\n continue;\n }\n\n const files = await adapter.installSkill(options.targetPath, skill, skillSourceDir);\n createdFiles.push(...files);\n }\n }\n\n let harnessInitialized = false;\n if (options.enableHarness) {\n const harnessFiles = installHarness({\n targetPath: options.targetPath,\n selectedAgents: options.selectedAgents,\n selectedSkillIds: skillsToInstall,\n detectedDependencies: options.detectedDependencies || [],\n language: options.language,\n });\n createdFiles.push(...harnessFiles);\n harnessInitialized = true;\n }\n\n const configPath = writeProjectConfig(\n options.targetPath,\n skillsToInstall,\n options.selectedAgents,\n Boolean(options.enableHarness),\n options.language\n );\n createdFiles.push(configPath);\n\n return {\n installedSkills: skillsToInstall,\n configuredAgents: options.selectedAgents,\n createdFiles,\n harnessInitialized,\n language: options.language,\n };\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class AntigravityAdapter implements AgentAdapter {\n readonly id = \"antigravity\" as const;\n readonly name = \"Antigravity\";\n readonly targetRelativeDir = \".agents/skills\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const parentDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true });\n }\n\n const destination = join(parentDir, skill.directoryName);\n const projectSkillDir = join(getProjectSkillsDir(targetPath), skill.directoryName);\n\n createOrReplaceSymlink(projectSkillDir, destination, \"dir\");\n\n return [destination];\n }\n}\n","import { join } from \"node:path\";\n\nexport function getProjectStoreDir(targetPath: string): string {\n return join(targetPath, \".grooveskills\");\n}\n\nexport function getProjectSkillsDir(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"skills\");\n}\n\nexport function getProjectCursorRulesDir(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"cursor-rules\");\n}\n\nexport function getProjectMemoryDir(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"memory\");\n}\n\nexport function getProjectTasksDir(targetPath: string): string {\n return join(getProjectMemoryDir(targetPath), \"tasks\");\n}\n\nexport function getProjectConfigPath(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"config.json\");\n}\n","import { lstatSync, unlinkSync, rmSync, symlinkSync } from \"node:fs\";\nimport { dirname, relative } from \"node:path\";\n\nfunction removeExistingLinkPath(path: string): void {\n try {\n const lstat = lstatSync(path);\n\n if (lstat.isDirectory() && !lstat.isSymbolicLink()) {\n rmSync(path, { recursive: true, force: true });\n return;\n }\n\n unlinkSync(path);\n } catch {\n // If path does not exist, exit early\n }\n}\n\nexport function createOrReplaceSymlink(\n target: string,\n linkPath: string,\n type: \"dir\" | \"file\"\n): void {\n removeExistingLinkPath(linkPath);\n\n const linkDir = dirname(linkPath);\n const relativeTarget = relative(linkDir, target);\n\n symlinkSync(relativeTarget, linkPath, type);\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class ClaudeAdapter implements AgentAdapter {\n readonly id = \"claude\" as const;\n readonly name = \"Claude Code\";\n readonly targetRelativeDir = \".claude/skills\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const parentDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true });\n }\n\n const destination = join(parentDir, skill.directoryName);\n const projectSkillDir = join(getProjectSkillsDir(targetPath), skill.directoryName);\n\n createOrReplaceSymlink(projectSkillDir, destination, \"dir\");\n\n return [destination];\n }\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectCursorRulesDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class CursorAdapter implements AgentAdapter {\n readonly id = \"cursor\" as const;\n readonly name = \"Cursor\";\n readonly targetRelativeDir = \".cursor/rules\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const rulesDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(rulesDir)) {\n mkdirSync(rulesDir, { recursive: true });\n }\n\n const filename = `${skill.id}.mdc`;\n const destination = join(rulesDir, filename);\n const projectRuleFile = join(getProjectCursorRulesDir(targetPath), filename);\n\n createOrReplaceSymlink(projectRuleFile, destination, \"file\");\n\n return [destination];\n }\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class GeminiAdapter implements AgentAdapter {\n readonly id = \"gemini\" as const;\n readonly name = \"Gemini Code Assist\";\n readonly targetRelativeDir = \".gemini/skills\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const parentDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true });\n }\n\n const destination = join(parentDir, skill.directoryName);\n const projectSkillDir = join(getProjectSkillsDir(targetPath), skill.directoryName);\n\n createOrReplaceSymlink(projectSkillDir, destination, \"dir\");\n\n return [destination];\n }\n}\n","import { cpSync, mkdirSync, existsSync, writeFileSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n getProjectSkillsDir,\n getProjectCursorRulesDir,\n} from \"@/domains/project-store/project-paths\";\nimport { resolveSkillsSourceRoot } from \"@/domains/installer/resolve-skills-source\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport function syncProjectStore(\n targetPath: string,\n selectedSkillIds: string[],\n selectedAgents: AgentId[]\n): void {\n const bundledSkillsDir = resolveSkillsSourceRoot();\n const projectSkillsDir = getProjectSkillsDir(targetPath);\n const projectCursorRulesDir = getProjectCursorRulesDir(targetPath);\n\n if (!existsSync(projectSkillsDir)) {\n mkdirSync(projectSkillsDir, { recursive: true });\n }\n\n const needsCursorRules = selectedAgents.includes(\"cursor\");\n if (needsCursorRules && !existsSync(projectCursorRulesDir)) {\n mkdirSync(projectCursorRulesDir, { recursive: true });\n }\n\n for (const skillId of selectedSkillIds) {\n const skill = SKILL_CATALOG.find((item) => item.id === skillId);\n if (!skill) {\n continue;\n }\n\n const sourceSkillDir = join(bundledSkillsDir, skill.directoryName);\n const destSkillDir = join(projectSkillsDir, skill.directoryName);\n\n if (existsSync(sourceSkillDir)) {\n cpSync(sourceSkillDir, destSkillDir, { recursive: true });\n }\n\n if (!needsCursorRules) {\n continue;\n }\n\n const skillMdPath = join(destSkillDir, \"SKILL.md\");\n if (!existsSync(skillMdPath)) {\n continue;\n }\n\n const content = readFileSync(skillMdPath, \"utf-8\");\n const mdcHeader = `---\ndescription: ${skill.description}\nglobs: [\"**/*\"]\nalwaysApply: false\n---\n\n`;\n const cleanedBody = content.replace(/^---[\\s\\S]*?---\\s*/, \"\");\n const targetMdc = join(projectCursorRulesDir, `${skill.id}.mdc`);\n writeFileSync(targetMdc, `${mdcHeader}${cleanedBody}`, \"utf-8\");\n }\n}\n","import { fileURLToPath } from \"node:url\";\nimport { dirname, resolve, join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\n\nexport function resolveSkillsSourceRoot(): string {\n const currentFilePath = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFilePath);\n\n // 1. From dist/ in published npm package or local build: dist/../skills\n const candidateFromDist = resolve(currentDir, \"../skills\");\n if (existsSync(candidateFromDist)) {\n return candidateFromDist;\n }\n\n // 2. From src/domains/installer/ during development: ../../../skills\n const candidateFromSrc = resolve(currentDir, \"../../../skills\");\n if (existsSync(candidateFromSrc)) {\n return candidateFromSrc;\n }\n\n // 3. Search upward for the package root containing a skills directory\n let searchDir = currentDir;\n for (let i = 0; i < 5; i++) {\n const candidate = join(searchDir, \"skills\");\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(searchDir);\n if (parent === searchDir) {\n break;\n }\n searchDir = parent;\n }\n\n throw new Error(\n `GrooveSkills internal error: Unable to locate bundled skills directory from ${currentDir}`\n );\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n getProjectMemoryDir,\n getProjectTasksDir,\n} from \"@/domains/project-store/project-paths\";\nimport {\n buildContextTemplate,\n buildDecisionsTemplate,\n buildTaskTemplate,\n} from \"@/domains/harness/harness-templates\";\nimport { upsertAgentInstructions } from \"@/domains/harness/upsert-agent-instructions\";\nimport type { HarnessInstallOptions } from \"@/types/harness.types\";\n\nexport function installHarness(options: HarnessInstallOptions): string[] {\n const memoryDir = getProjectMemoryDir(options.targetPath);\n const tasksDir = getProjectTasksDir(options.targetPath);\n const language = options.language ?? \"es\";\n\n if (!existsSync(tasksDir)) {\n mkdirSync(tasksDir, { recursive: true });\n }\n\n const createdFiles: string[] = [];\n\n const contextPath = join(memoryDir, \"context.md\");\n if (!existsSync(contextPath)) {\n writeFileSync(contextPath, buildContextTemplate(options.detectedDependencies, language), \"utf-8\");\n createdFiles.push(contextPath);\n }\n\n const decisionsPath = join(memoryDir, \"decisions.md\");\n if (!existsSync(decisionsPath)) {\n writeFileSync(decisionsPath, buildDecisionsTemplate(language), \"utf-8\");\n createdFiles.push(decisionsPath);\n }\n\n const templateTaskPath = join(tasksDir, \"_template.md\");\n if (!existsSync(templateTaskPath)) {\n writeFileSync(templateTaskPath, buildTaskTemplate(), \"utf-8\");\n createdFiles.push(templateTaskPath);\n }\n\n const instructions = upsertAgentInstructions(options.targetPath, options.selectedAgents, language);\n createdFiles.push(...instructions);\n\n return createdFiles;\n}\n","import type { ProjectLanguage } from \"@/types/harness.types\";\n\nexport interface LanguageDefinition {\n code: ProjectLanguage;\n name: string;\n nativeName: string;\n instruction: string;\n}\n\nexport const SUPPORTED_LANGUAGES: Record<ProjectLanguage, LanguageDefinition> = {\n es: {\n code: \"es\",\n name: \"Spanish\",\n nativeName: \"Español\",\n instruction: \"Todos los mensajes, validaciones, errores, CTAs y comunicaciones con el usuario deben redactarse estrictamente en Español. El tono debe ser empático, amable, persuasivo y profesional.\",\n },\n en: {\n code: \"en\",\n name: \"English\",\n nativeName: \"English\",\n instruction: \"All user-facing messages, form validations, errors, CTAs, and notifications must be written strictly in English. Tone must be empathetic, friendly, persuasive, and professional.\",\n },\n pt: {\n code: \"pt\",\n name: \"Portuguese\",\n nativeName: \"Português\",\n instruction: \"Todas as mensagens, validações, erros, CTAs e comunicações voltadas para o usuário devem ser redigidas estritamente em Português. O tom deve ser empático, amigável, persuasivo e profissional.\",\n },\n it: {\n code: \"it\",\n name: \"Italian\",\n nativeName: \"Italiano\",\n instruction: \"Tutti i messaggi, le convalide, gli errori, i pulsanti/CTA e le comunicazioni rivolte all'utente devono essere scritti rigorosamente in Italiano. Il tono deve essere empatico, cordiale, persuasivo e professionale.\",\n },\n fr: {\n code: \"fr\",\n name: \"French\",\n nativeName: \"Français\",\n instruction: \"Tous les messages, validations, erreurs, boutons d'appel à l'action (CTA) et notifications destinés à l'utilisateur doivent être rédigés strictement en Français. Le ton doit être empathique, courtois, persuasif et professionnel.\",\n },\n};\n","import type { ProjectLanguage } from \"@/types/harness.types\";\nimport { SUPPORTED_LANGUAGES } from \"@/domains/harness/harness-languages\";\n\nexport function buildContextTemplate(\n detectedDependencies: string[],\n language: ProjectLanguage = \"es\"\n): string {\n const depsFormatted = detectedDependencies.length > 0\n ? detectedDependencies.map((d) => `- \\`${d}\\``).join(\"\\n\")\n : \"- (No external dependencies detected)\";\n\n const langConfig = SUPPORTED_LANGUAGES[language];\n\n return `# Project Context & Architecture\n\nThis file provides AI agents with instant architectural orientation for this project.\n\n## 1. Stack & Dependencies\n${depsFormatted}\n\n## 2. Directory Structure Conventions\n- Follow single-responsibility per file (<200 lines).\n- Maintain direct imports with path aliases; avoid barrel files.\n- Keep domain boundaries explicit and clean.\n\n## 3. Communication & User Copy Language\n- **Configured Language**: ${langConfig.nativeName} (\\`${language}\\`).\n- **Policy**: ${langConfig.instruction}\n\n## 4. Essential Commands\n- Build: Refer to \\`package.json\\` scripts.\n- Typecheck: Refer to TypeScript configuration.\n- Tests: Refer to test runner configuration.\n`;\n}\n\nexport function buildDecisionsTemplate(language: ProjectLanguage = \"es\"): string {\n const now = new Date().toISOString().split(\"T\")[0];\n const langConfig = SUPPORTED_LANGUAGES[language];\n\n return `# Architecture Decision Records (ADR)\n\nAn append-only log of significant technical and architectural choices.\n\n| Date | Title | Decision | Reason & Consequences |\n| :--- | :--- | :--- | :--- |\n| ${now} | Adopt GrooveSkills Harness | Initialized \\`.grooveskills/\\` control plane with ODD | Clean, encapsulated agent memory, 3-lane ODD flow, and ${langConfig.nativeName} copy standard |\n`;\n}\n\nexport function buildTaskTemplate(): string {\n return `---\nstatus: in-progress\ncreatedAt: \\${CURRENT_DATE}\n---\n\n# Feature / Task Title\n\n## Outcome Hypothesis\nDescribe the expected behavioral outcome:\nBy [Output / Technical Change], [Outcome / Verifiable Behavior] will occur, proven by [Evidence / Test / Build Command].\n\n## Scope\n- In scope:\n- Out of scope:\n\n## Checklist\n- [ ] Task 1: (Define expected observed proof)\n- [ ] Task 2: (Define expected observed proof)\n\n## Evidence\n- Observed test/typecheck/build commands or runtime outputs proving completion.\n\n## Next\n- Next concrete step if interrupted.\n`;\n}\n\nexport function buildAgentHarnessBlock(language: ProjectLanguage = \"es\"): string {\n const langConfig = SUPPORTED_LANGUAGES[language];\n\n return `<!-- grooveskills:harness:start -->\n# GrooveSkills Harness — Agent Rules & Memory\n\nThis project uses the **GrooveSkills Harness** located in \\`.grooveskills/\\`.\n\n## 1. Three-Lane ODD Protocol\n- **Authorize & Explore**: Follow the 7-step ODD protocol (Authorize, Explore, Resolve, Classify, Track & Hypothesize, Execute, Verify).\n- **Lane 1 (Answer)**: Explanations, audits, or questions. Read-only; write zero code.\n- **Lane 2 (Task)**: Direct implementation. Declare Outcome Hypothesis and checklist in \\`.grooveskills/memory/tasks/<slug>.md\\`. Only check off tasks with observed evidence under \\`Evidence\\`.\n- **Lane 3 (Spec)**: Ambiguous or high-impact architecture. Clarify and validate the spec in \\`.grooveskills/memory/tasks/<slug>.md\\` before writing code.\n\n## 2. User Communication Language (${langConfig.nativeName})\n- **Language**: \\`${language}\\` (${langConfig.nativeName}).\n- **Requirement**: ${langConfig.instruction}\n\n## 3. Memory Locations\n- Architecture context: \\`.grooveskills/memory/context.md\\`\n- Technical decisions (ADR): \\`.grooveskills/memory/decisions.md\\`\n- Active tasks & evidence: \\`.grooveskills/memory/tasks/\\`\n<!-- grooveskills:harness:end -->`;\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { buildAgentHarnessBlock } from \"@/domains/harness/harness-templates\";\nimport type { AgentId } from \"@/types/agent.types\";\nimport type { ProjectLanguage } from \"@/types/harness.types\";\n\nconst START_MARKER = \"<!-- grooveskills:harness:start -->\";\nconst END_MARKER = \"<!-- grooveskills:harness:end -->\";\n\nfunction applyHarnessBlock(filePath: string, language: ProjectLanguage = \"es\"): void {\n const block = buildAgentHarnessBlock(language);\n\n if (!existsSync(filePath)) {\n writeFileSync(filePath, `${block}\\n`, \"utf-8\");\n return;\n }\n\n const existingContent = readFileSync(filePath, \"utf-8\");\n\n if (existingContent.includes(START_MARKER) && existingContent.includes(END_MARKER)) {\n const regex = new RegExp(`${START_MARKER}[\\\\s\\\\S]*?${END_MARKER}`, \"g\");\n const updated = existingContent.replace(regex, block);\n writeFileSync(filePath, updated, \"utf-8\");\n return;\n }\n\n const separator = existingContent.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n writeFileSync(filePath, `${existingContent}${separator}${block}\\n`, \"utf-8\");\n}\n\nexport function upsertAgentInstructions(\n targetPath: string,\n selectedAgents: AgentId[],\n language: ProjectLanguage = \"es\"\n): string[] {\n const updatedFiles: string[] = [];\n\n const agentsMdPath = join(targetPath, \"AGENTS.md\");\n applyHarnessBlock(agentsMdPath, language);\n updatedFiles.push(agentsMdPath);\n\n if (selectedAgents.includes(\"claude\")) {\n const claudeMdPath = join(targetPath, \"CLAUDE.md\");\n applyHarnessBlock(claudeMdPath, language);\n updatedFiles.push(claudeMdPath);\n }\n\n return updatedFiles;\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { getProjectConfigPath } from \"@/domains/project-store/project-paths\";\nimport type { GrooveSkillsConfig, ProjectLanguage } from \"@/types/harness.types\";\nimport type { AgentId } from \"@/types/agent.types\";\n\ninterface ParsedConfigState {\n skills: string[];\n agents: AgentId[];\n harness: boolean;\n language?: ProjectLanguage;\n}\n\nfunction readExistingConfig(configPath: string): ParsedConfigState {\n const fallback: ParsedConfigState = {\n skills: [],\n agents: [],\n harness: false,\n };\n\n if (!existsSync(configPath)) {\n return fallback;\n }\n\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<GrooveSkillsConfig>;\n\n return {\n skills: Array.isArray(parsed.skills) ? parsed.skills : [],\n agents: Array.isArray(parsed.agents) ? parsed.agents : [],\n harness: typeof parsed.harness === \"boolean\" ? parsed.harness : false,\n language: typeof parsed.language === \"string\" ? (parsed.language as ProjectLanguage) : undefined,\n };\n } catch {\n return fallback;\n }\n}\n\nexport function writeProjectConfig(\n targetPath: string,\n newSkills: string[],\n newAgents: AgentId[],\n harnessEnabled: boolean,\n language?: ProjectLanguage\n): string {\n const configPath = getProjectConfigPath(targetPath);\n const existing = readExistingConfig(configPath);\n\n const mergedSkills = Array.from(new Set([...existing.skills, ...newSkills]));\n const mergedAgents = Array.from(new Set([...existing.agents, ...newAgents]));\n const resolvedLanguage = language ?? existing.language ?? \"es\";\n const isHarnessActive = existing.harness || harnessEnabled;\n\n const config: GrooveSkillsConfig = {\n version: 1,\n harness: isHarnessActive,\n ...(isHarnessActive ? { language: resolvedLanguage } : {}),\n agents: mergedAgents,\n skills: mergedSkills,\n updatedAt: new Date().toISOString(),\n };\n\n writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\n return configPath;\n}\n","import { detectProjectContext } from \"@/domains/detector/project-detector\";\nimport { runInteractiveUi } from \"@/domains/ui/ui-orchestrator\";\nimport { installSkills } from \"@/domains/installer/install-orchestrator\";\nimport type { AgentId } from \"@/types/agent.types\";\nimport type { ProjectLanguage } from \"@/types/harness.types\";\n\nexport interface CliOptions {\n skills?: string[];\n agents?: AgentId[];\n yes?: boolean;\n harness?: boolean;\n language?: ProjectLanguage;\n}\n\nexport async function runGrooveSkills(options: CliOptions = {}): Promise<void> {\n const targetPath = process.cwd();\n const context = detectProjectContext(targetPath);\n\n const hasSkills = options.skills && options.skills.length > 0;\n const hasAgents = options.agents && options.agents.length > 0;\n const isDirectHarness = Boolean(options.harness) && hasAgents;\n\n if ((hasSkills && hasAgents) || isDirectHarness) {\n await installSkills({\n targetPath,\n selectedSkillIds: options.skills || [],\n selectedAgents: options.agents || [],\n forceOverwrite: Boolean(options.yes),\n enableHarness: options.harness,\n detectedDependencies: context.detectedDependencies,\n language: options.language,\n });\n return;\n }\n\n await runInteractiveUi(context);\n}\n"],"mappings":"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","names":["existsSync","join","existsSync","join","p","pc","p","p","confirm","p","p","join","join","existsSync","join","join","lstatSync","join","existsSync","mkdirSync","existsSync","join","join","existsSync","mkdirSync","mkdirSync","existsSync","join","join","existsSync","mkdirSync","mkdirSync","existsSync","join","join","existsSync","mkdirSync","mkdirSync","existsSync","readFileSync","join","dirname","join","existsSync","existsSync","mkdirSync","join","readFileSync","existsSync","mkdirSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","join","existsSync","writeFileSync","readFileSync","join","existsSync","mkdirSync","join","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","join","confirm","pc","s"]}
package/dist/cli.js CHANGED
@@ -1,18 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runGrooveSkills
4
- } from "./chunk-5Q6O3BRA.js";
4
+ } from "./chunk-M7ZPBGQE.js";
5
5
 
6
6
  // bin/cli.ts
7
7
  import { Command } from "commander";
8
8
  var program = new Command();
9
- program.name("grooveskills").description("Multi-agent AI skills and architecture standards installer").version("1.1.2").option("-s, --skills <skills...>", "Specific skill IDs to install (e.g. best-practices hono groove-harness)").option("-a, --agents <agents...>", "Target AI agents (antigravity claude cursor gemini)").option("-y, --yes", "Automatically confirm overwrite of existing skills", false).option("--harness", "Initialize or update GrooveSkills project harness in .grooveskills/").option("--no-harness", "Skip harness initialization").action(async (options) => {
9
+ program.name("grooveskills").description("Multi-agent AI skills and architecture standards installer").version("1.3.1").option("-s, --skills <skills...>", "Specific skill IDs to install (e.g. best-practices hono groove-harness)").option("-a, --agents <agents...>", "Target AI agents (antigravity claude cursor gemini)").option("-y, --yes", "Automatically confirm overwrite of existing skills", false).option("--harness", "Initialize or update GrooveSkills project harness in .grooveskills/").option("--no-harness", "Skip harness initialization").option("-l, --language <lang>", "Project user copy language (es, en, pt, it, fr)", "es").action(async (options) => {
10
10
  try {
11
11
  await runGrooveSkills({
12
12
  skills: options.skills,
13
13
  agents: options.agents,
14
14
  yes: options.yes,
15
- harness: options.harness
15
+ harness: options.harness,
16
+ language: options.language || "es"
16
17
  });
17
18
  } catch (error) {
18
19
  console.error("An unexpected error occurred while running GrooveSkills:", error);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { runGrooveSkills } from \"@/main\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nconst program = new Command();\n\nprogram\n .name(\"grooveskills\")\n .description(\"Multi-agent AI skills and architecture standards installer\")\n .version(__VERSION__)\n .option(\"-s, --skills <skills...>\", \"Specific skill IDs to install (e.g. best-practices hono groove-harness)\")\n .option(\"-a, --agents <agents...>\", \"Target AI agents (antigravity claude cursor gemini)\")\n .option(\"-y, --yes\", \"Automatically confirm overwrite of existing skills\", false)\n .option(\"--harness\", \"Initialize or update GrooveSkills project harness in .grooveskills/\")\n .option(\"--no-harness\", \"Skip harness initialization\")\n .action(async (options: { skills?: string[]; agents?: string[]; yes?: boolean; harness?: boolean }) => {\n try {\n await runGrooveSkills({\n skills: options.skills,\n agents: options.agents as AgentId[] | undefined,\n yes: options.yes,\n harness: options.harness,\n });\n } catch (error) {\n console.error(\"An unexpected error occurred while running GrooveSkills:\", error);\n process.exit(1);\n }\n });\n\nprogram.parse();\n"],"mappings":";;;;;;AACA,SAAS,eAAe;AAIxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,cAAc,EACnB,YAAY,4DAA4D,EACxE,QAAQ,OAAW,EACnB,OAAO,4BAA4B,yEAAyE,EAC5G,OAAO,4BAA4B,qDAAqD,EACxF,OAAO,aAAa,sDAAsD,KAAK,EAC/E,OAAO,aAAa,qEAAqE,EACzF,OAAO,gBAAgB,6BAA6B,EACpD,OAAO,OAAO,YAAwF;AACrG,MAAI;AACF,UAAM,gBAAgB;AAAA,MACpB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ;AAAA,MAChB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,MAAM,4DAA4D,KAAK;AAC/E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QAAQ,MAAM;","names":[]}
1
+ {"version":3,"sources":["../bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { runGrooveSkills } from \"@/main\";\nimport type { AgentId } from \"@/types/agent.types\";\nimport type { ProjectLanguage } from \"@/types/harness.types\";\n\nconst program = new Command();\n\nprogram\n .name(\"grooveskills\")\n .description(\"Multi-agent AI skills and architecture standards installer\")\n .version(__VERSION__)\n .option(\"-s, --skills <skills...>\", \"Specific skill IDs to install (e.g. best-practices hono groove-harness)\")\n .option(\"-a, --agents <agents...>\", \"Target AI agents (antigravity claude cursor gemini)\")\n .option(\"-y, --yes\", \"Automatically confirm overwrite of existing skills\", false)\n .option(\"--harness\", \"Initialize or update GrooveSkills project harness in .grooveskills/\")\n .option(\"--no-harness\", \"Skip harness initialization\")\n .option(\"-l, --language <lang>\", \"Project user copy language (es, en, pt, it, fr)\", \"es\")\n .action(async (options: {\n skills?: string[];\n agents?: string[];\n yes?: boolean;\n harness?: boolean;\n language?: string;\n }) => {\n try {\n await runGrooveSkills({\n skills: options.skills,\n agents: options.agents as AgentId[] | undefined,\n yes: options.yes,\n harness: options.harness,\n language: (options.language as ProjectLanguage) || \"es\",\n });\n } catch (error) {\n console.error(\"An unexpected error occurred while running GrooveSkills:\", error);\n process.exit(1);\n }\n });\n\nprogram.parse();\n"],"mappings":";;;;;;AACA,SAAS,eAAe;AAKxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,cAAc,EACnB,YAAY,4DAA4D,EACxE,QAAQ,OAAW,EACnB,OAAO,4BAA4B,yEAAyE,EAC5G,OAAO,4BAA4B,qDAAqD,EACxF,OAAO,aAAa,sDAAsD,KAAK,EAC/E,OAAO,aAAa,qEAAqE,EACzF,OAAO,gBAAgB,6BAA6B,EACpD,OAAO,yBAAyB,mDAAmD,IAAI,EACvF,OAAO,OAAO,YAMT;AACJ,MAAI;AACF,UAAM,gBAAgB;AAAA,MACpB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ;AAAA,MAChB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB,UAAW,QAAQ,YAAgC;AAAA,IACrD,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,MAAM,4DAA4D,KAAK;AAC/E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QAAQ,MAAM;","names":[]}
package/dist/main.d.ts CHANGED
@@ -1,10 +1,13 @@
1
1
  type AgentId = "antigravity" | "claude" | "cursor" | "gemini";
2
2
 
3
+ type ProjectLanguage = "es" | "en" | "pt" | "it" | "fr";
4
+
3
5
  interface CliOptions {
4
6
  skills?: string[];
5
7
  agents?: AgentId[];
6
8
  yes?: boolean;
7
9
  harness?: boolean;
10
+ language?: ProjectLanguage;
8
11
  }
9
12
  declare function runGrooveSkills(options?: CliOptions): Promise<void>;
10
13
 
package/dist/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runGrooveSkills
3
- } from "./chunk-5Q6O3BRA.js";
3
+ } from "./chunk-M7ZPBGQE.js";
4
4
  export {
5
5
  runGrooveSkills
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3lineas/grooveskills",
3
- "version": "1.1.2",
3
+ "version": "1.3.1",
4
4
  "description": "Multi-agent CLI to install opinionated AI coding skills and architectural standards (Hono, React, Next.js, and more)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: clean-architecture-ddd
3
+ description: Domain-driven design, clean architecture, isolated Actions layer, strict separation of concerns, pure domain logic, immutability, zero barrel files, and hard 200-line limit per file. TRIGGER when structuring new features, refactoring domain entities, organizing modules/actions/repositories, or designing service boundaries.
4
+ ---
5
+
6
+ # Clean Architecture & Domain-Driven Design (DDD)
7
+
8
+ Architectural guidelines for organizing code into decoupled domain modules, isolated business actions, pure functions, and thin adapters.
9
+
10
+ ---
11
+
12
+ ## 1. Golden Rules (Non-negotiable)
13
+
14
+ 1. **Domain Isolation (Features by Business Domain)**:
15
+ - Group files by business domain (`users/`, `billing/`, `orders/`), never by technical type alone (`controllers/`, `services/`).
16
+
17
+ 2. **Actions Layer for Business Logic**:
18
+ - Encapsulate every single business use case in an isolated Action (`src/actions/<domain>/<action-name>.action.ts`).
19
+ - One business action per file. Routers and UI controllers remain thin.
20
+
21
+ 3. **Inversion of Dependencies**:
22
+ - Business actions do not depend directly on database drivers or external HTTP clients.
23
+ - Inject repository interfaces, database handles, or clients into the action.
24
+
25
+ 4. **Immutability and Pure Functions**:
26
+ - Domain calculation and transformation logic must be pure and free of side effects.
27
+ - Do not mutate entities in place. Return updated copies (`{ ...user, status: "active" }`).
28
+
29
+ 5. **Zero Barrel Files (`index.ts`)**:
30
+ - Import directly from the exact file defining the symbol. Barrel files create circular dependency traps and bloat bundle sizes.
31
+
32
+ 6. **Hard Size Limit: 200 Lines Max**:
33
+ - If an action, entity, or router grows past 150 lines, split sub-responsibilities into atomic helpers.
34
+
35
+ ---
36
+
37
+ ## 2. Directory Structure
38
+
39
+ ```text
40
+ src/
41
+ ├── actions/ # Pure business logic actions
42
+ │ └── billing/
43
+ │ ├── charge-subscription.action.ts # One action per file (<100 lines)
44
+ │ └── cancel-subscription.action.ts
45
+ ├── domains/ # Domain models, types & pure logic
46
+ │ └── billing/
47
+ │ ├── billing.types.ts
48
+ │ └── calculate-prorated-tax.ts # Pure function (<50 lines)
49
+ ├── infrastructure/ # Adapters, DB clients, external APIs
50
+ │ └── stripe/
51
+ │ └── stripe-client.ts
52
+ └── modules/ # Transport controllers (HTTP, CLI, Worker)
53
+ └── billing/
54
+ ├── billing.router.ts
55
+ └── charge-subscription.ts
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 3. Atomic Action Blueprint
61
+
62
+ ```ts
63
+ import type { BillingCustomer, Invoice } from "@/domains/billing/billing.types";
64
+ import { calculateProratedTax } from "@/domains/billing/calculate-prorated-tax";
65
+ import { AppError } from "@/errors/app-error";
66
+ import type { ActionResponse } from "@/types/response.types";
67
+
68
+ export interface ChargeSubscriptionInput {
69
+ customerId: string;
70
+ planId: string;
71
+ }
72
+
73
+ export async function chargeSubscriptionAction(
74
+ input: ChargeSubscriptionInput,
75
+ paymentGateway: { charge: (id: string, amount: number) => Promise<boolean> }
76
+ ): Promise<ActionResponse<Invoice>> {
77
+ if (!input.customerId || !input.planId) {
78
+ throw new AppError({ message: "Customer and Plan are required.", statusCode: 400 });
79
+ }
80
+
81
+ const baseAmount = 4900;
82
+ const tax = calculateProratedTax(baseAmount);
83
+ const total = baseAmount + tax;
84
+
85
+ const success = await paymentGateway.charge(input.customerId, total);
86
+ if (!success) {
87
+ return { success: false, error: "Payment processing was declined by provider." };
88
+ }
89
+
90
+ return {
91
+ success: true,
92
+ data: { id: "inv_123", total, customerId: input.customerId },
93
+ };
94
+ }
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 4. Sibling Skills
100
+
101
+ - **`best-practices`**: Universal clean code rules and guard clauses.
102
+ - **`error-handling-logging`**: Structured `AppError` and `ActionResponse`.
103
+ - **`valibot-validation`**: Domain input/output validation.
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: error-handling-logging
3
+ description: Deterministic error handling with custom AppError, Result/ActionResponse contracts, and structured logging. TRIGGER when designing error boundaries, writing try/catch blocks, handling I/O or network failures, creating domain exceptions, or configuring application loggers.
4
+ ---
5
+
6
+ # Error Handling & Structured Logging Standards
7
+
8
+ Enterprise-grade patterns for deterministic error handling, structured context logging, and safe API error responses.
9
+
10
+ ---
11
+
12
+ ## 1. Golden Rules (Non-negotiable)
13
+
14
+ 1. **Typed Domain Errors with `AppError`**:
15
+ - Never throw raw strings or generic untyped `Error("something failed")`.
16
+ - Throw structured `AppError` instances with HTTP status code, error code identifier, user-safe message, and optional contextual metadata.
17
+
18
+ 2. **Never Swallow Errors Silently**:
19
+ - Every `catch (err)` block must either:
20
+ - Recover with an explicit fallback value.
21
+ - Log with `Logger.error(...)` and re-throw / return an `ActionResponse` failure.
22
+ - Empty catch blocks (`catch {}`) without explicit intent are forbidden.
23
+
24
+ 3. **Separate User-Safe Messages from Internal Diagnostics**:
25
+ - The user receives polite, actionable feedback (e.g. *"Unable to complete transaction. Please try again."*).
26
+ - Internal logs receive complete diagnostic metadata (stack trace, payload params, correlation ID, elapsed time).
27
+
28
+ 4. **Result / ActionResponse for Non-fatal Domain Failures**:
29
+ - Prefer returning `{ success: false, error: "..." }` or `Result<T, E>` across service boundaries when the failure is an expected domain outcome (e.g. validation failure, duplicate email).
30
+
31
+ 5. **Structured JSON-Ready Logging**:
32
+ - Avoid `console.log("here 1")` in production code.
33
+ - Use a structured `Logger` utility emitting timestamp, level (`DEBUG`, `INFO`, `WARN`, `ERROR`), message, and contextual metadata object.
34
+
35
+ ---
36
+
37
+ ## 2. Standard Contracts
38
+
39
+ ### A. The ActionResponse Contract
40
+
41
+ ```ts
42
+ export type ActionResponse<TData = unknown, TError = string> =
43
+ | { success: true; data: TData; message?: string }
44
+ | { success: false; error: TError; message?: string; statusCode?: number };
45
+
46
+ export function successResponse<T>(data: T, message?: string): ActionResponse<T> {
47
+ return { success: true, data, message };
48
+ }
49
+
50
+ export function errorResponse(error: string, statusCode = 400): ActionResponse<never> {
51
+ return { success: false, error, statusCode };
52
+ }
53
+ ```
54
+
55
+ ### B. The `AppError` Base Class
56
+
57
+ See `templates/app-error.template.md` for full implementation.
58
+
59
+ ```ts
60
+ export class AppError extends Error {
61
+ readonly statusCode: number;
62
+ readonly code: string;
63
+ readonly details?: unknown;
64
+
65
+ constructor(opts: { message: string; statusCode?: number; code?: string; details?: unknown }) {
66
+ super(opts.message);
67
+ this.name = "AppError";
68
+ this.statusCode = opts.statusCode ?? 500;
69
+ this.code = opts.code ?? "INTERNAL_SERVER_ERROR";
70
+ this.details = opts.details;
71
+ }
72
+ }
73
+ ```
74
+
75
+ ---
76
+
77
+ ## 3. Safe Try/Catch Pattern
78
+
79
+ ```ts
80
+ import { Logger } from "@/utils/logger";
81
+ import { AppError } from "@/errors/app-error";
82
+ import { type ActionResponse, errorResponse, successResponse } from "@/types/response.types";
83
+
84
+ export async function executeSafeTask<T>(task: () => Promise<T>): Promise<ActionResponse<T>> {
85
+ try {
86
+ const result = await task();
87
+ return successResponse(result);
88
+ } catch (error: unknown) {
89
+ if (error instanceof AppError) {
90
+ Logger.warn("Expected domain error caught", { code: error.code, message: error.message });
91
+ return errorResponse(error.message, error.statusCode);
92
+ }
93
+
94
+ Logger.error("Unhandled runtime exception in task execution", { error });
95
+ return errorResponse("An unexpected error occurred. Please try again later.", 500);
96
+ }
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## 4. Templates
103
+
104
+ - `templates/app-error.template.md`: Complete extensible `AppError` implementation with serialization.
105
+ - `templates/logger.template.md`: Lightweight structured logger with log levels and JSON output formatting.
@@ -0,0 +1,44 @@
1
+ # Template: AppError Class
2
+
3
+ Copy or adapt this template when setting up error handling in your project: `src/errors/app-error.ts`.
4
+
5
+ ```ts
6
+ export interface AppErrorOptions {
7
+ message: string;
8
+ statusCode?: number;
9
+ code?: string;
10
+ details?: unknown;
11
+ cause?: unknown;
12
+ }
13
+
14
+ export class AppError extends Error {
15
+ readonly statusCode: number;
16
+ readonly code: string;
17
+ readonly details?: unknown;
18
+ readonly timestamp: string;
19
+
20
+ constructor(options: AppErrorOptions) {
21
+ super(options.message, { cause: options.cause });
22
+ this.name = "AppError";
23
+ this.statusCode = options.statusCode ?? 500;
24
+ this.code = options.code ?? "INTERNAL_SERVER_ERROR";
25
+ this.details = options.details;
26
+ this.timestamp = new Date().toISOString();
27
+
28
+ if (Error.captureStackTrace) {
29
+ Error.captureStackTrace(this, AppError);
30
+ }
31
+ }
32
+
33
+ toJSON(): Record<string, unknown> {
34
+ return {
35
+ error: this.name,
36
+ code: this.code,
37
+ message: this.message,
38
+ statusCode: this.statusCode,
39
+ details: this.details,
40
+ timestamp: this.timestamp,
41
+ };
42
+ }
43
+ }
44
+ ```
@@ -0,0 +1,41 @@
1
+ # Template: Structured Logger
2
+
3
+ Copy or adapt this template when setting up logging in your project: `src/utils/logger.ts`.
4
+
5
+ ```ts
6
+ export type LogLevel = "debug" | "info" | "warn" | "error";
7
+
8
+ export interface LogContext {
9
+ [key: string]: unknown;
10
+ }
11
+
12
+ export class Logger {
13
+ private static format(level: LogLevel, message: string, context?: LogContext): string {
14
+ const entry = {
15
+ timestamp: new Date().toISOString(),
16
+ level: level.toUpperCase(),
17
+ message,
18
+ ...(context ? { context } : {}),
19
+ };
20
+ return JSON.stringify(entry);
21
+ }
22
+
23
+ static debug(message: string, context?: LogContext): void {
24
+ if (process.env.NODE_ENV !== "production") {
25
+ console.debug(this.format("debug", message, context));
26
+ }
27
+ }
28
+
29
+ static info(message: string, context?: LogContext): void {
30
+ console.info(this.format("info", message, context));
31
+ }
32
+
33
+ static warn(message: string, context?: LogContext): void {
34
+ console.warn(this.format("warn", message, context));
35
+ }
36
+
37
+ static error(message: string, context?: LogContext): void {
38
+ console.error(this.format("error", message, context));
39
+ }
40
+ }
41
+ ```
@@ -1,37 +1,37 @@
1
1
  ---
2
2
  name: groove-harness
3
- description: Lightweight project harness, context memory, and 3-lane task execution (Answer, Task, Spec) for AI coding agents.
3
+ description: Lightweight project harness, context memory, and ODD 3-lane task execution (Answer, Task, Spec) for AI coding agents.
4
4
  ---
5
5
 
6
6
  # GrooveSkills Harness — Project Control Plane
7
7
 
8
- A lightweight, non-intrusive harness living entirely within `.grooveskills/`. It gives agents persistent project memory, clear architectural boundaries, and a disciplined 3-lane execution flow.
8
+ A lightweight, non-intrusive harness living entirely within `.grooveskills/`. It gives agents persistent project memory, clear architectural boundaries, and a disciplined Organic & Outcome-Driven (ODD) 3-lane execution flow.
9
9
 
10
10
  ---
11
11
 
12
- ## 1. The Three Execution Lanes
12
+ ## 1. The ODD 3-Lane Execution Flow
13
13
 
14
- Classify each user request into one of three lanes before taking action:
14
+ Every request is governed by the 7-step ODD protocol (*Authorize, Explore, Resolve, Classify, Track & Hypothesize, Execute, Verify*) mapped into three lanes:
15
15
 
16
16
  ### Lane 1: Answer (Read-Only)
17
- - **Trigger**: The user asks for explanations, audits, code reviews, comparisons, or architectural questions.
17
+ - **Trigger**: Explanations, audits, code reviews, comparisons, or questions.
18
18
  - **Rule**: Read-only. Write zero code, create zero artifacts, modify no files.
19
19
 
20
- ### Lane 2: Task (Direct Feature or Bugfix)
20
+ ### Lane 2: Task (Outcome-Driven Implementation)
21
21
  - **Trigger**: Concrete change, standard feature, refactor, or bugfix with clear requirements.
22
22
  - **Protocol**:
23
- 1. Locate or create `.grooveskills/memory/tasks/<slug>.md` using the format in `.grooveskills/memory/tasks/_template.md`.
24
- 2. Declare `Intent`, `Scope`, and an itemized `Checklist`.
25
- 3. Execute code changes incrementally according to project standards.
26
- 4. Only check off items once **observed evidence** is verified (e.g. `check-types`, test runs, or command outputs under `Evidence`).
23
+ 1. For non-trivial work, locate or create `.grooveskills/memory/tasks/<slug>.md`.
24
+ 2. Declare the **Outcome Hypothesis**, `Scope`, and an itemized `Checklist`.
25
+ 3. Execute code changes incrementally following clean code standards.
26
+ 4. Only check off tasks once **observed evidence** is verified (e.g. `check-types`, test runs, or command outputs under `Evidence`).
27
27
  5. Keep `Next` updated so any interruption costs nothing.
28
28
 
29
- ### Lane 3: Spec (Complex or Ambiguous Architecture)
29
+ ### Lane 3: Spec (Collaborative Design)
30
30
  - **Trigger**: Multi-component restructuring, ambiguous requirements, or high-risk domain changes.
31
31
  - **Protocol**:
32
32
  1. Draft the architectural proposal, interfaces, trade-offs, and open questions inside `.grooveskills/memory/tasks/<slug>.md`.
33
33
  2. Present the spec to the user and request explicit confirmation.
34
- 3. Once approved, switch to Lane 2 (Task) for disciplined implementation.
34
+ 3. Once approved, switch to Lane 2 (Task) for outcome-driven implementation.
35
35
 
36
36
  ---
37
37
 
@@ -39,12 +39,12 @@ Classify each user request into one of three lanes before taking action:
39
39
 
40
40
  - **`.grooveskills/memory/context.md`**: Stores project stack, architectural patterns, conventions, and key commands. Read this when starting work on a domain; update it when new dependencies or architectural standards are introduced.
41
41
  - **`.grooveskills/memory/decisions.md`**: An append-only Architecture Decision Record (ADR). Log significant technical decisions (`Date`, `Context`, `Decision`, `Consequences`).
42
- - **`.grooveskills/memory/tasks/`**: Individual feature records holding intent and observed proof.
42
+ - **`.grooveskills/memory/tasks/`**: Individual feature records holding outcome hypotheses, checklists, and observed proof.
43
43
 
44
44
  ---
45
45
 
46
46
  ## 3. Core Principles
47
47
 
48
- 1. **No Silent Changes**: Every non-trivial change is backed by an observed verification step.
48
+ 1. **Outcome-Driven Accountability**: Every non-trivial change requires an outcome hypothesis and an observed verification receipt.
49
49
  2. **Strict Encapsulation**: Keep harness and state confined to `.grooveskills/`. Do not pollute the root repository.
50
50
  3. **Respect Best Practices**: All code must follow strict typing, guard clauses, SRP, direct imports (no barrels), and file limits (<200 lines).