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
2 changes: 1 addition & 1 deletion .agent/CheatSheet.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Devran AI Kit — CheatSheet

> **Version**: v5.2.3 | **Quick Reference** for all capabilities
> **Version**: v5.2.4 | **Quick Reference** for all capabilities
> **Session**: Start with `/project-status`, end with session-end checklist

---
Expand Down
2 changes: 1 addition & 1 deletion .agent/commands/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Your complete guide to the Devran AI Kit. Type `/help` for a quick overview, or

## Quick Overview

**Devran AI Kit v5.2.3** — Trust-Grade AI Development Framework
**Devran AI Kit v5.2.4** — Trust-Grade AI Development Framework

| Category | Count | Description |
|:---------|:------|:------------|
Expand Down
2 changes: 1 addition & 1 deletion .agent/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": "1.0.0",
"kitVersion": "5.2.3",
"kitVersion": "5.2.4",
"lastAuditedAt": null,
"description": "Devran AI Kit — Trust-Grade AI Development Framework",
"repository": "https://github.com/devran-ai/kit",
Expand Down
2 changes: 1 addition & 1 deletion .agent/session-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

**Branch**: —
**Repository**: —
**Framework**: Devran AI Kit v5.2.0
**Framework**: Devran AI Kit v5.2.4

### Key File Locations

Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to Devran AI Kit will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.2.4] — 2026-04-09

### Fixed

- `addToGitignore()` now gitignores all Kit-generated artifacts — bridge directories and `.worktreeinclude`, not just `.agent/`
- Parent directory coverage check uses line-level matching — `.cursor/rules/kit-governance.mdc` no longer falsely covers `.cursor/commands/`
- After `kit init`, `git status` shows zero untracked Kit artifacts

### Changed

- `addToGitignore()` accepts `detectedIDEs` parameter to gitignore only relevant bridge directories
- `.agent/session-context.md` version reference updated from v5.2.0 to v5.2.4

## [5.2.3] — 2026-04-09

### Added
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
</p>

<p align="center">
<a href="https://github.com/devran-ai/kit"><img src="https://img.shields.io/badge/version-5.2.3-blue?style=for-the-badge" alt="Version" height="36" /></a>
<a href="https://github.com/devran-ai/kit"><img src="https://img.shields.io/badge/version-5.2.4-blue?style=for-the-badge" alt="Version" height="36" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="License" height="36" /></a>
<a href="tests/"><img src="https://img.shields.io/badge/tests-1000%20passing-brightgreen?style=for-the-badge" alt="Tests" height="36" /></a>
<a href="tests/"><img src="https://img.shields.io/badge/tests-1001%20passing-brightgreen?style=for-the-badge" alt="Tests" height="36" /></a>
<a href="package.json"><img src="https://img.shields.io/badge/dependencies-0-brightgreen?style=for-the-badge" alt="Dependencies" height="36" /></a>
</p>
<p align="center">
Expand Down Expand Up @@ -43,7 +43,7 @@
| Cross-IDE support | Single IDE | Single IDE | 5 IDEs from one source of truth |
| Plugin marketplace | None | None | Trust-verified skill marketplace |
| Telegram control | None | None | Full IDE control from your phone |
| Test suite | None | None | 984 tests with security validation |
| Test suite | None | None | 1001 tests with security validation |
| Runtime dependencies | Varies | Varies | **Zero** |

## Quick Start
Expand Down Expand Up @@ -117,7 +117,9 @@ Onboarding (`/greenfield` or `/brownfield`) is a one-time pre-SDLC phase. Each s

See the full **[CHANGELOG](CHANGELOG.md)** for detailed release notes.

**Latest (v5.2.3):** Automatic Worktree Support — `.worktreeinclude` generation for Claude Code, `post-checkout` git hook for manual worktrees. Zero-friction install: bridge files are local-only, `kit init` no longer modifies existing `.gitignore` entries. 1000 tests passing.
**Latest (v5.2.4):** Complete gitignore coverage — `kit init` now gitignores all generated artifacts (bridge dirs, `.worktreeinclude`) so `git status` stays clean. 1001 tests passing.

**v5.2.3:** Automatic Worktree Support — `.worktreeinclude` generation for Claude Code, `post-checkout` git hook for manual worktrees. Zero-friction install: bridge files are local-only, `kit init` no longer modifies existing `.gitignore` entries.

**v5.2.0:** Universal Slash Command Bridge Generation — IDE-native `/` command bridges for Claude Code, Cursor, OpenCode, VS Code Copilot, and Windsurf with auto-detection, provenance-based safe overwrite, and 9 security hardening measures.

Expand Down Expand Up @@ -227,7 +229,7 @@ kit/
├── create-kit-app/ # Project scaffolder
├── docs/ # MkDocs documentation site
├── examples/ # Starter examples (minimal, full-stack)
└── tests/ # 1000 tests (unit, structural, integration, security)
└── tests/ # 1001 tests (unit, structural, integration, security)
```

## Security
Expand Down
4 changes: 2 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Architecture

Devran AI Kit v5.2.3 is an engineered framework with a **43-module runtime engine**, 26 agents, 39 skills, 40 commands, 25 workflows, and 15 governance rules.
Devran AI Kit v5.2.4 is an engineered framework with a **43-module runtime engine**, 26 agents, 39 skills, 40 commands, 25 workflows, and 15 governance rules.

---

## Architecture Overview

```
┌─────────────────────────────────────────────────────────────────────┐
│ DEVRAN AI KIT v5.2.3
│ DEVRAN AI KIT v5.2.4
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
Expand Down
9 changes: 6 additions & 3 deletions lib/commands/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,14 @@ function initCommand(options, ctx) {
const { addToGitignore, cleanupLegacyClaudeTracking } = require('../io');
const { execSync } = require('child_process');
try {
const result = addToGitignore(targetDir);
const result = addToGitignore(targetDir, detectedIDEs);
if (result.added) {
log(' ✓ .agent/ added to .gitignore (local dev tooling)', 'green');
const entries = result.entries || [];
for (const entry of entries) {
log(` ✓ ${entry} added to .gitignore`, 'green');
}
} else {
log(' ✓ .agent/ already in .gitignore', 'green');
log(' ✓ .gitignore already configured', 'green');
}
} catch (err) {
log(` ⚠️ Could not update .gitignore: ${err.message}`, 'yellow');
Expand Down
57 changes: 42 additions & 15 deletions lib/io.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,30 +148,57 @@ function safeCopyDirSync(src, dest) {
* @param {string} projectRoot - Project root directory
* @returns {{ added: boolean, reason: string }}
*/
function addToGitignore(projectRoot) {
function addToGitignore(projectRoot, detectedIDEs) {
const { IDE_BRIDGE_DIRS } = require('./constants');
const gitignorePath = path.join(projectRoot, '.gitignore');
const marker = '# Devran AI Kit';
const block = [
'',
'# Devran AI Kit (local dev tooling)',
'# Install: npx @devran-ai/kit init',
'.agent/',
].join('\n') + '\n';

// Build the full list of entries that must be gitignored
const requiredEntries = ['.agent/'];
if (Array.isArray(detectedIDEs)) {
for (const ide of detectedIDEs) {
if (IDE_BRIDGE_DIRS[ide]) {
requiredEntries.push(IDE_BRIDGE_DIRS[ide]);
}
}
}
requiredEntries.push('.worktreeinclude');
Comment on lines +157 to +165
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve robustness and prevent duplicate entries in .gitignore if detectedIDEs contains duplicates, it's better to use a Set to collect the required entries. This ensures each entry is unique before being processed and keeps the code clean.

Suggested change
const requiredEntries = ['.agent/'];
if (Array.isArray(detectedIDEs)) {
for (const ide of detectedIDEs) {
if (IDE_BRIDGE_DIRS[ide]) {
requiredEntries.push(IDE_BRIDGE_DIRS[ide]);
}
}
}
requiredEntries.push('.worktreeinclude');
const requiredEntriesSet = new Set(['.agent/']);
if (Array.isArray(detectedIDEs)) {
for (const ide of detectedIDEs) {
if (IDE_BRIDGE_DIRS[ide]) {
requiredEntriesSet.add(IDE_BRIDGE_DIRS[ide]);
}
}
}
requiredEntriesSet.add('.worktreeinclude');
const requiredEntries = [...requiredEntriesSet];


let content = '';
if (fs.existsSync(gitignorePath)) {
content = fs.readFileSync(gitignorePath, 'utf-8');
// Primary check: is .agent/ already ignored?
if (content.includes('.agent/')) {
if (content.includes(marker)) {
return { added: false, reason: 'already-present' };
}
return { added: false, reason: 'already-ignored' };
}

// Find entries not yet covered by existing gitignore patterns
// A parent dir pattern (e.g. .claude/) covers child paths (e.g. .claude/commands/)
// We check for standalone lines only — .cursor/rules/foo does NOT cover .cursor/commands/
const lines = content.split('\n').map(l => l.trim());
const missing = requiredEntries.filter(entry => {
if (lines.includes(entry)) return false;
// Check if a parent directory pattern exists as its own gitignore line
const parts = entry.replace(/\/$/, '').split('/');
for (let i = 1; i < parts.length; i++) {
const parent = parts.slice(0, i).join('/') + '/';
if (lines.includes(parent)) return false;
}
return true;
});

if (missing.length === 0) {
return { added: false, reason: content.includes(marker) ? 'already-present' : 'already-ignored' };
}

// Build the block to append
const blockLines = [];
if (!content.includes(marker)) {
blockLines.push('', '# Devran AI Kit (local dev tooling)', '# Install: npx @devran-ai/kit init');
} else {
blockLines.push('');
}
blockLines.push(...missing);

fs.appendFileSync(gitignorePath, block, 'utf-8');
return { added: true, reason: 'added' };
fs.appendFileSync(gitignorePath, blockLines.join('\n') + '\n', 'utf-8');
return { added: true, reason: 'added', entries: missing };
}

/**
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devran-ai/kit",
"version": "5.2.3",
"version": "5.2.4",
"description": "Trust-grade AI development framework — zero-dependency runtime engine for agent orchestration, workflow governance, and skill management.",
"main": "bin/kit.js",
"bin": {
Expand Down
72 changes: 50 additions & 22 deletions tests/unit/gitignore.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,66 +22,94 @@ describe('addToGitignore', () => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});

it('creates .gitignore if it does not exist', () => {
it('creates .gitignore with all entries for detected IDEs', () => {
const { addToGitignore } = loadModule();
const result = addToGitignore(tmpDir);
const result = addToGitignore(tmpDir, ['claude', 'cursor']);

expect(result.added).toBe(true);
expect(result.reason).toBe('added');
expect(fs.existsSync(path.join(tmpDir, '.gitignore'))).toBe(true);

const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf-8');
expect(content).toContain('.agent/');
expect(content).toContain('.claude/commands/');
expect(content).toContain('.cursor/commands/');
expect(content).toContain('.worktreeinclude');
expect(content).toContain('# Devran AI Kit');
});

it('appends to existing .gitignore', () => {
const { addToGitignore } = loadModule();
fs.writeFileSync(path.join(tmpDir, '.gitignore'), 'node_modules/\n', 'utf-8');

const result = addToGitignore(tmpDir);
const result = addToGitignore(tmpDir, ['claude']);

expect(result.added).toBe(true);
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf-8');
expect(content).toContain('node_modules/');
expect(content).toContain('.agent/');
expect(content).toContain('.claude/commands/');
expect(content).toContain('.worktreeinclude');
});

it('skips if .agent/ already present (idempotent)', () => {
it('skips entries already covered by parent dir pattern', () => {
const { addToGitignore } = loadModule();
fs.writeFileSync(path.join(tmpDir, '.gitignore'), '.agent/\n', 'utf-8');
// .claude/ covers .claude/commands/
fs.writeFileSync(path.join(tmpDir, '.gitignore'),
'.agent/\n.claude/\n.worktreeinclude\n', 'utf-8');

const result = addToGitignore(tmpDir);
const result = addToGitignore(tmpDir, ['claude']);

expect(result.added).toBe(false);
expect(result.reason).toBe('already-ignored');
});

it('skips if marker comment already present', () => {
it('does NOT treat specific file patterns as parent dir coverage', () => {
const { addToGitignore } = loadModule();
fs.writeFileSync(
path.join(tmpDir, '.gitignore'),
'# Devran AI Kit\n.agent/\n',
'utf-8'
);
// .cursor/rules/kit-governance.mdc is a specific file — does NOT cover .cursor/commands/
fs.writeFileSync(path.join(tmpDir, '.gitignore'),
'.agent/\n.cursor/rules/kit-governance.mdc\n.worktreeinclude\n', 'utf-8');

const result = addToGitignore(tmpDir);
const result = addToGitignore(tmpDir, ['cursor']);

expect(result.added).toBe(false);
expect(result.reason).toBe('already-present');
expect(result.added).toBe(true);
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf-8');
expect(content).toContain('.cursor/commands/');
});

it('returns { added: true } when entry was added', () => {
it('adds only missing bridge dirs when .agent/ already present', () => {
const { addToGitignore } = loadModule();
const result = addToGitignore(tmpDir);
expect(result).toEqual({ added: true, reason: 'added' });
fs.writeFileSync(path.join(tmpDir, '.gitignore'), '.agent/\n', 'utf-8');

const result = addToGitignore(tmpDir, ['claude', 'cursor']);

expect(result.added).toBe(true);
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf-8');
expect(content).toContain('.claude/commands/');
expect(content).toContain('.cursor/commands/');
expect(content).toContain('.worktreeinclude');
// .agent/ should NOT be duplicated
expect(content.match(/\.agent\//g)).toHaveLength(1);
});

it('returns { added: false } when skipped', () => {
it('skips if all entries already present (idempotent)', () => {
const { addToGitignore } = loadModule();
fs.writeFileSync(path.join(tmpDir, '.gitignore'),
'# Devran AI Kit\n.agent/\n.claude/commands/\n.worktreeinclude\n', 'utf-8');

const result = addToGitignore(tmpDir, ['claude']);

expect(result.added).toBe(false);
expect(result.reason).toBe('already-present');
});

it('works with no detectedIDEs argument (backward compat)', () => {
const { addToGitignore } = loadModule();
fs.writeFileSync(path.join(tmpDir, '.gitignore'), '.agent/\n', 'utf-8');
const result = addToGitignore(tmpDir);
expect(result).toEqual({ added: false, reason: 'already-ignored' });

expect(result.added).toBe(true);
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf-8');
expect(content).toContain('.agent/');
expect(content).toContain('.worktreeinclude');
});
});

Expand Down
Loading