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
1 change: 1 addition & 0 deletions src/cli/commands/repo_init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export const repoUpgradeCommand = new Command()
upgradedAt: result.upgradedAt,
skillsUpdated: result.skillsUpdated,
settingsUpdated: result.settingsUpdated,
gitignoreCreated: result.gitignoreCreated,
tool: result.tool,
};

Expand Down
8 changes: 8 additions & 0 deletions src/domain/repo/repo_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export interface RepoUpgradeResult {
upgradedAt: string;
skillsUpdated: string[];
settingsUpdated: boolean;
gitignoreCreated: boolean;
tool: AiTool;
}

Expand Down Expand Up @@ -231,6 +232,12 @@ export class RepoService {
settingsUpdated = await this.updateClaudeSettings(repoPath);
}

// Create .gitignore if it doesn't exist
const gitignoreCreated = await this.createGitignoreIfNotExists(
repoPath,
tool,
);

// createUpgradeMarker always sets upgradedAt, but TypeScript doesn't know this
if (!updatedMarker.upgradedAt) {
throw new Error(
Expand All @@ -245,6 +252,7 @@ export class RepoService {
upgradedAt: updatedMarker.upgradedAt,
skillsUpdated,
settingsUpdated,
gitignoreCreated,
tool,
};
}
Expand Down
39 changes: 39 additions & 0 deletions src/domain/repo/repo_service_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,45 @@ Deno.test("RepoService.upgrade skips settings for non-claude tools", async () =>
});
});

Deno.test("RepoService.upgrade creates .gitignore if missing", async () => {
await withTempDir(async (tempDir) => {
const service = new RepoService("0.1.0");
const repoPath = RepoPath.create(tempDir);

// Init (creates .gitignore), then delete it
await service.init(repoPath);
const gitignorePath = join(tempDir, ".gitignore");
await Deno.remove(gitignorePath);

// Upgrade should recreate .gitignore
const upgradeService = new RepoService("0.2.0");
const result = await upgradeService.upgrade(repoPath);

assertEquals(result.gitignoreCreated, true);

const content = await Deno.readTextFile(gitignorePath);
assertStringIncludes(content, ".swamp/telemetry/");
assertStringIncludes(content, ".swamp/secrets/keyfile");
assertStringIncludes(content, ".claude/");
});
});

Deno.test("RepoService.upgrade does not overwrite existing .gitignore", async () => {
await withTempDir(async (tempDir) => {
const service = new RepoService("0.1.0");
const repoPath = RepoPath.create(tempDir);

// Init creates .gitignore
await service.init(repoPath);

// Upgrade should leave .gitignore unchanged
const upgradeService = new RepoService("0.2.0");
const result = await upgradeService.upgrade(repoPath);

assertEquals(result.gitignoreCreated, false);
});
});

Deno.test("RepoService.init cursor instructions have MDC frontmatter", async () => {
await withTempDir(async (tempDir) => {
const service = new RepoService("0.1.0");
Expand Down
1 change: 1 addition & 0 deletions src/presentation/output/repo_output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface RepoUpgradeData {
upgradedAt: string;
skillsUpdated: string[];
settingsUpdated: boolean;
gitignoreCreated: boolean;
tool: string;
}

Expand Down