diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index 0b1c87e8..704a7ea8 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -664,3 +664,72 @@ describe("ExperimentalConfigSchema feature flags", () => { } }) }) + +describe("GitMasterConfigSchema", () => { + test("accepts boolean true for commit_footer", () => { + //#given + const config = { commit_footer: true } + + //#when + const result = GitMasterConfigSchema.safeParse(config) + + //#then + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.commit_footer).toBe(true) + } + }) + + test("accepts boolean false for commit_footer", () => { + //#given + const config = { commit_footer: false } + + //#when + const result = GitMasterConfigSchema.safeParse(config) + + //#then + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.commit_footer).toBe(false) + } + }) + + test("accepts string value for commit_footer", () => { + //#given + const config = { commit_footer: "Custom footer text" } + + //#when + const result = GitMasterConfigSchema.safeParse(config) + + //#then + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.commit_footer).toBe("Custom footer text") + } + }) + + test("defaults commit_footer to true when not provided", () => { + //#given + const config = {} + + //#when + const result = GitMasterConfigSchema.safeParse(config) + + //#then + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.commit_footer).toBe(true) + } + }) + + test("rejects number for commit_footer", () => { + //#given + const config = { commit_footer: 123 } + + //#when + const result = GitMasterConfigSchema.safeParse(config) + + //#then + expect(result.success).toBe(false) + }) +}) diff --git a/src/config/schema.ts b/src/config/schema.ts index 387e08c7..f6d15d61 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -339,10 +339,10 @@ export const BabysittingConfigSchema = z.object({ }) export const GitMasterConfigSchema = z.object({ - /** Add "Ultraworked with Sisyphus" footer to commit messages (default: true) */ - commit_footer: z.boolean().default(true), - /** Add "Co-authored-by: Sisyphus" trailer to commit messages (default: true) */ - include_co_authored_by: z.boolean().default(true), + /** Add "Ultraworked with Sisyphus" footer to commit messages (default: true). Can be boolean or custom string. */ + commit_footer: z.union([z.boolean(), z.string()]).default(true), + /** Add "Co-authored-by: Sisyphus" trailer to commit messages (default: true) */ + include_co_authored_by: z.boolean().default(true), }) export const BrowserAutomationProviderSchema = z.enum(["playwright", "agent-browser", "dev-browser"]) diff --git a/src/features/opencode-skill-loader/skill-content.test.ts b/src/features/opencode-skill-loader/skill-content.test.ts index 4ea84671..60f777ed 100644 --- a/src/features/opencode-skill-loader/skill-content.test.ts +++ b/src/features/opencode-skill-loader/skill-content.test.ts @@ -314,6 +314,44 @@ describe("resolveMultipleSkillsAsync", () => { expect(gitMasterContent).toContain("Co-authored-by: Sisyphus") }) + it("should inject custom string footer when commit_footer is a string", async () => { + // given: git-master skill with custom string footer + const skillNames = ["git-master"] + const customFooter = "Custom footer from my team" + const options = { + gitMasterConfig: { + commit_footer: customFooter, + include_co_authored_by: false, + }, + } + + // when: resolving with custom footer config + const result = await resolveMultipleSkillsAsync(skillNames, options) + + // then: custom footer is injected instead of default + const gitMasterContent = result.resolved.get("git-master") + expect(gitMasterContent).toContain(customFooter) + expect(gitMasterContent).not.toContain("Ultraworked with [Sisyphus]") + }) + + it("should use default Sisyphus footer when commit_footer is boolean true", async () => { + // given: git-master skill with boolean true footer + const skillNames = ["git-master"] + const options = { + gitMasterConfig: { + commit_footer: true, + include_co_authored_by: false, + }, + } + + // when: resolving with boolean true footer config + const result = await resolveMultipleSkillsAsync(skillNames, options) + + // then: default Sisyphus footer is injected + const gitMasterContent = result.resolved.get("git-master") + expect(gitMasterContent).toContain("Ultraworked with [Sisyphus]") + }) + it("should handle empty array", async () => { // given: empty skill names const skillNames: string[] = [] diff --git a/src/features/opencode-skill-loader/skill-content.ts b/src/features/opencode-skill-loader/skill-content.ts index 3b359629..27d00291 100644 --- a/src/features/opencode-skill-loader/skill-content.ts +++ b/src/features/opencode-skill-loader/skill-content.ts @@ -97,9 +97,10 @@ export function injectGitMasterConfig(template: string, config?: GitMasterConfig sections.push(``) if (commitFooter) { + const footerText = typeof commitFooter === "string" ? commitFooter : "Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)" sections.push(`1. **Footer in commit body:**`) sections.push("```") - sections.push(`Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)`) + sections.push(footerText) sections.push("```") sections.push(``) } @@ -113,14 +114,16 @@ export function injectGitMasterConfig(template: string, config?: GitMasterConfig } if (commitFooter && includeCoAuthoredBy) { + const footerText = typeof commitFooter === "string" ? commitFooter : "Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)" sections.push(`**Example (both enabled):**`) sections.push("```bash") - sections.push(`git commit -m "{Commit Message}" -m "Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)" -m "Co-authored-by: Sisyphus "`) + sections.push(`git commit -m "{Commit Message}" -m "${footerText}" -m "Co-authored-by: Sisyphus "`) sections.push("```") } else if (commitFooter) { + const footerText = typeof commitFooter === "string" ? commitFooter : "Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)" sections.push(`**Example:**`) sections.push("```bash") - sections.push(`git commit -m "{Commit Message}" -m "Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)"`) + sections.push(`git commit -m "{Commit Message}" -m "${footerText}"`) sections.push("```") } else if (includeCoAuthoredBy) { sections.push(`**Example:**`)