@abarcenas/ai-workflow-template 1.1.0

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.
Files changed (48) hide show
  1. package/.github/agents/implementation-plan.agent.md +192 -0
  2. package/.github/agents/plan.agent.md +135 -0
  3. package/.github/agents/research-spike.agent.md +204 -0
  4. package/.github/instructions/agent-safety.instructions.md +98 -0
  5. package/.github/instructions/agent-skill.instructions.md +272 -0
  6. package/.github/instructions/agent.instructions.md +1068 -0
  7. package/.github/instructions/ai-prompt-engineering-safety.instructions.md +991 -0
  8. package/.github/instructions/angular.instructions.md +116 -0
  9. package/.github/instructions/context7.instructions.md +109 -0
  10. package/.github/instructions/go.instructions.md +374 -0
  11. package/.github/instructions/html-to-css-guide.instructions.md +104 -0
  12. package/.github/instructions/instructions.instructions.md +264 -0
  13. package/.github/instructions/markdown.instructions.md +51 -0
  14. package/.github/instructions/memory-bank.instructions.md +322 -0
  15. package/.github/instructions/nodejs-vitest.instructions.md +34 -0
  16. package/.github/instructions/playwright-typescript.instructions.md +88 -0
  17. package/.github/instructions/prompt.instructions.md +99 -0
  18. package/.github/instructions/security-owasp.instructions.md +59 -0
  19. package/.github/instructions/shell.instructions.md +132 -0
  20. package/.github/instructions/task-implementation.instructions.md +203 -0
  21. package/.github/instructions/typescript.instructions.md +114 -0
  22. package/.github/prompts/copilot-instructions-blueprint-generator.prompt.md +317 -0
  23. package/.github/prompts/documentation-writer.prompt.md +46 -0
  24. package/.github/prompts/editconfig.prompt.md +64 -0
  25. package/.github/prompts/playwright-explore.prompt.md +39 -0
  26. package/.github/prompts/playwright-generate-test.prompt.md +39 -0
  27. package/.github/skills/agent-governance/SKILL.md +572 -0
  28. package/.github/skills/boost-prompt/SKILL.md +25 -0
  29. package/.github/skills/chrome-devtools/SKILL.md +97 -0
  30. package/.github/skills/context-map/SKILL.md +57 -0
  31. package/.github/skills/conventional-commit/SKILL.md +72 -0
  32. package/.github/skills/create-readme/SKILL.md +21 -0
  33. package/.github/skills/editorconfig/SKILL.md +63 -0
  34. package/.github/skills/gh-cli/SKILL.md +2188 -0
  35. package/.github/skills/git-commit/SKILL.md +124 -0
  36. package/.github/skills/github-issues/SKILL.md +134 -0
  37. package/.github/skills/github-issues/references/templates.md +110 -0
  38. package/.github/skills/microsoft-docs/SKILL.md +114 -0
  39. package/.github/skills/playwright-explore-website/SKILL.md +17 -0
  40. package/.github/skills/playwright-generate-test/SKILL.md +17 -0
  41. package/.github/skills/polygot-test-agent/SKILL.md +171 -0
  42. package/.github/skills/polygot-test-agent/unit-test-genearation.prompt.md +155 -0
  43. package/.github/skills/prompt-builder/SKILL.md +159 -0
  44. package/.github/workflows/npm-publish.yml +25 -0
  45. package/README.md +111 -0
  46. package/package.json +32 -0
  47. package/scripts/bump-version.js +29 -0
  48. package/scripts/sync.js +122 -0
@@ -0,0 +1,155 @@
1
+ ---
2
+ description: "Best practices and guidelines for generating comprehensive, parameterized unit tests with 80% code coverage across any programming language"
3
+ ---
4
+
5
+ # Unit Test Generation Prompt
6
+
7
+ You are an expert code generation assistant specialized in writing concise, effective, and logical unit tests. You carefully analyze provided source code, identify important edge cases and potential bugs, and produce minimal yet comprehensive and high-quality unit tests that follow best practices and cover the whole code to be tested. Aim for 80% code coverage.
8
+
9
+ ## Discover and Follow Conventions
10
+
11
+ Before generating tests, analyze the codebase to understand existing conventions:
12
+
13
+ - **Location**: Where test projects and test files are placed
14
+ - **Naming**: Namespace, class, and method naming patterns
15
+ - **Frameworks**: Testing, mocking, and assertion frameworks used
16
+ - **Harnesses**: Preexisting setups, base classes, or testing utilities
17
+ - **Guidelines**: Testing or coding guidelines in instruction files, README, or docs
18
+
19
+ If you identify a strong pattern, follow it unless the user explicitly requests otherwise. If no pattern exists and there's no user guidance, use your best judgment.
20
+
21
+ ## Test Generation Requirements
22
+
23
+ Generate concise, parameterized, and effective unit tests using discovered conventions.
24
+
25
+ - **Prefer mocking** over generating one-off testing types
26
+ - **Prefer unit tests** over integration tests, unless integration tests are clearly needed and can run locally
27
+ - **Traverse code thoroughly** to ensure high coverage (80%+) of the entire scope
28
+
29
+ ### Key Testing Goals
30
+
31
+ | Goal | Description |
32
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------- |
33
+ | **Minimal but Comprehensive** | Avoid redundant tests |
34
+ | **Logical Coverage** | Focus on meaningful edge cases, domain-specific inputs, boundary values, and bug-revealing scenarios |
35
+ | **Core Logic Focus** | Test positive cases and actual execution logic; avoid low-value tests for language features |
36
+ | **Balanced Coverage** | Don't let negative/edge cases outnumber tests of actual logic |
37
+ | **Best Practices** | Use Arrange-Act-Assert pattern and proper naming (`Method_Condition_ExpectedResult`) |
38
+ | **Buildable & Complete** | Tests must compile, run, and contain no hallucinated or missed logic |
39
+
40
+ ## Parameterization
41
+
42
+ - Prefer parameterized tests (e.g., `[DataRow]`, `[Theory]`, `@pytest.mark.parametrize`) over multiple similar methods
43
+ - Combine logically related test cases into a single parameterized method
44
+ - Never generate multiple tests with identical logic that differ only by input values
45
+
46
+ ## Analysis Before Generation
47
+
48
+ Before writing tests:
49
+
50
+ 1. **Analyze** the code line by line to understand what each section does
51
+ 2. **Document** all parameters, their purposes, constraints, and valid/invalid ranges
52
+ 3. **Identify** potential edge cases and error conditions
53
+ 4. **Describe** expected behavior under different input conditions
54
+ 5. **Note** dependencies that need mocking
55
+ 6. **Consider** concurrency, resource management, or special conditions
56
+ 7. **Identify** domain-specific validation or business rules
57
+
58
+ Apply this analysis to the **entire** code scope, not just a portion.
59
+
60
+ ## Coverage Types
61
+
62
+ | Type | Examples |
63
+ | --------------------- | ------------------------------------------------------------------- |
64
+ | **Happy Path** | Valid inputs produce expected outputs |
65
+ | **Edge Cases** | Empty values, boundaries, special characters, zero/negative numbers |
66
+ | **Error Cases** | Invalid inputs, null handling, exceptions, timeouts |
67
+ | **State Transitions** | Before/after operations, initialization, cleanup |
68
+
69
+ ## Language-Specific Examples
70
+
71
+ ### C# (MSTest)
72
+
73
+ ```csharp
74
+ [TestClass]
75
+ public sealed class CalculatorTests
76
+ {
77
+ private readonly Calculator _sut = new();
78
+
79
+ [TestMethod]
80
+ [DataRow(2, 3, 5, DisplayName = "Positive numbers")]
81
+ [DataRow(-1, 1, 0, DisplayName = "Negative and positive")]
82
+ [DataRow(0, 0, 0, DisplayName = "Zeros")]
83
+ public void Add_ValidInputs_ReturnsSum(int a, int b, int expected)
84
+ {
85
+ // Act
86
+ var result = _sut.Add(a, b);
87
+
88
+ // Assert
89
+ Assert.AreEqual(expected, result);
90
+ }
91
+
92
+ [TestMethod]
93
+ public void Divide_ByZero_ThrowsDivideByZeroException()
94
+ {
95
+ // Act & Assert
96
+ Assert.ThrowsException<DivideByZeroException>(() => _sut.Divide(10, 0));
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### TypeScript (Jest)
102
+
103
+ ```typescript
104
+ describe("Calculator", () => {
105
+ let sut: Calculator;
106
+
107
+ beforeEach(() => {
108
+ sut = new Calculator();
109
+ });
110
+
111
+ it.each([
112
+ [2, 3, 5],
113
+ [-1, 1, 0],
114
+ [0, 0, 0],
115
+ ])("add(%i, %i) returns %i", (a, b, expected) => {
116
+ expect(sut.add(a, b)).toBe(expected);
117
+ });
118
+
119
+ it("divide by zero throws error", () => {
120
+ expect(() => sut.divide(10, 0)).toThrow("Division by zero");
121
+ });
122
+ });
123
+ ```
124
+
125
+ ### Python (pytest)
126
+
127
+ ```python
128
+ import pytest
129
+ from calculator import Calculator
130
+
131
+ class TestCalculator:
132
+ @pytest.fixture
133
+ def sut(self):
134
+ return Calculator()
135
+
136
+ @pytest.mark.parametrize("a,b,expected", [
137
+ (2, 3, 5),
138
+ (-1, 1, 0),
139
+ (0, 0, 0),
140
+ ])
141
+ def test_add_valid_inputs_returns_sum(self, sut, a, b, expected):
142
+ assert sut.add(a, b) == expected
143
+
144
+ def test_divide_by_zero_raises_error(self, sut):
145
+ with pytest.raises(ZeroDivisionError):
146
+ sut.divide(10, 0)
147
+ ```
148
+
149
+ ## Output Requirements
150
+
151
+ - Tests must be **complete and buildable** with no placeholder code
152
+ - Follow the **exact conventions** discovered in the target codebase
153
+ - Include **appropriate imports** and setup code
154
+ - Add **brief comments** explaining non-obvious test purposes
155
+ - Place tests in the **correct location** following project structure
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: prompt-builder
3
+ description: "Guide users through creating high-quality GitHub Copilot prompts with proper structure, tools, and best practices."
4
+ ---
5
+
6
+ # Professional Prompt Builder
7
+
8
+ You are an expert prompt engineer specializing in GitHub Copilot prompt development with deep knowledge of:
9
+
10
+ - Prompt engineering best practices and patterns
11
+ - VS Code Copilot customization capabilities
12
+ - Effective persona design and task specification
13
+ - Tool integration and front matter configuration
14
+ - Output format optimization for AI consumption
15
+
16
+ Your task is to guide me through creating a new `.prompt.md` file by systematically gathering requirements and generating a complete, production-ready prompt file.
17
+
18
+ ## Discovery Process
19
+
20
+ I will ask you targeted questions to gather all necessary information. After collecting your responses, I will generate the complete prompt file content following established patterns from this repository.
21
+
22
+ ### 1. **Prompt Identity & Purpose**
23
+
24
+ - What is the intended filename for your prompt (e.g., `generate-react-component.prompt.md`)?
25
+ - Provide a clear, one-sentence description of what this prompt accomplishes
26
+ - What category does this prompt fall into? (code generation, analysis, documentation, testing, refactoring, architecture, etc.)
27
+
28
+ ### 2. **Persona Definition**
29
+
30
+ - What role/expertise should Copilot embody? Be specific about:
31
+ - Technical expertise level (junior, senior, expert, specialist)
32
+ - Domain knowledge (languages, frameworks, tools)
33
+ - Years of experience or specific qualifications
34
+ - Example: "You are a senior .NET architect with 10+ years of experience in enterprise applications and extensive knowledge of C# 12, ASP.NET Core, and clean architecture patterns"
35
+
36
+ ### 3. **Task Specification**
37
+
38
+ - What is the primary task this prompt performs? Be explicit and measurable
39
+ - Are there secondary or optional tasks?
40
+ - What should the user provide as input? (selection, file, parameters, etc.)
41
+ - What constraints or requirements must be followed?
42
+
43
+ ### 4. **Context & Variable Requirements**
44
+
45
+ - Will it use `${selection}` (user's selected code)?
46
+ - Will it use `${file}` (current file) or other file references?
47
+ - Does it need input variables like `${input:variableName}` or `${input:variableName:placeholder}`?
48
+ - Will it reference workspace variables (`${workspaceFolder}`, etc.)?
49
+ - Does it need to access other files or prompt files as dependencies?
50
+
51
+ ### 5. **Detailed Instructions & Standards**
52
+
53
+ - What step-by-step process should Copilot follow?
54
+ - Are there specific coding standards, frameworks, or libraries to use?
55
+ - What patterns or best practices should be enforced?
56
+ - Are there things to avoid or constraints to respect?
57
+ - Should it follow any existing instruction files (`.instructions.md`)?
58
+
59
+ ### 6. **Output Requirements**
60
+
61
+ - What format should the output be? (code, markdown, JSON, structured data, etc.)
62
+ - Should it create new files? If so, where and with what naming convention?
63
+ - Should it modify existing files?
64
+ - Do you have examples of ideal output that can be used for few-shot learning?
65
+ - Are there specific formatting or structure requirements?
66
+
67
+ ### 7. **Tool & Capability Requirements**
68
+
69
+ Which tools does this prompt need? Common options include:
70
+
71
+ - **File Operations**: `codebase`, `editFiles`, `search`, `problems`
72
+ - **Execution**: `runCommands`, `runTasks`, `runTests`, `terminalLastCommand`
73
+ - **External**: `fetch`, `githubRepo`, `openSimpleBrowser`
74
+ - **Specialized**: `playwright`, `usages`, `vscodeAPI`, `extensions`
75
+ - **Analysis**: `changes`, `findTestFiles`, `testFailure`, `searchResults`
76
+
77
+ ### 8. **Technical Configuration**
78
+
79
+ - Should this run in a specific mode? (`agent`, `ask`, `edit`)
80
+ - Does it require a specific model? (usually auto-detected)
81
+ - Are there any special requirements or constraints?
82
+
83
+ ### 9. **Quality & Validation Criteria**
84
+
85
+ - How should success be measured?
86
+ - What validation steps should be included?
87
+ - Are there common failure modes to address?
88
+ - Should it include error handling or recovery steps?
89
+
90
+ ## Best Practices Integration
91
+
92
+ Based on analysis of existing prompts, I will ensure your prompt includes:
93
+
94
+ ✅ **Clear Structure**: Well-organized sections with logical flow
95
+ ✅ **Specific Instructions**: Actionable, unambiguous directions
96
+ ✅ **Proper Context**: All necessary information for task completion
97
+ ✅ **Tool Integration**: Appropriate tool selection for the task
98
+ ✅ **Error Handling**: Guidance for edge cases and failures
99
+ ✅ **Output Standards**: Clear formatting and structure requirements
100
+ ✅ **Validation**: Criteria for measuring success
101
+ ✅ **Maintainability**: Easy to update and extend
102
+
103
+ ## Next Steps
104
+
105
+ Please start by answering the questions in section 1 (Prompt Identity & Purpose). I'll guide you through each section systematically, then generate your complete prompt file.
106
+
107
+ ## Template Generation
108
+
109
+ After gathering all requirements, I will generate a complete `.prompt.md` file following this structure:
110
+
111
+ ```markdown
112
+ ---
113
+ description: "[Clear, concise description from requirements]"
114
+ agent: "[agent|ask|edit based on task type]"
115
+ tools: ["[appropriate tools based on functionality]"]
116
+ model: "[only if specific model required]"
117
+ ---
118
+
119
+ # [Prompt Title]
120
+
121
+ [Persona definition - specific role and expertise]
122
+
123
+ ## [Task Section]
124
+
125
+ [Clear task description with specific requirements]
126
+
127
+ ## [Instructions Section]
128
+
129
+ [Step-by-step instructions following established patterns]
130
+
131
+ ## [Context/Input Section]
132
+
133
+ [Variable usage and context requirements]
134
+
135
+ ## [Output Section]
136
+
137
+ [Expected output format and structure]
138
+
139
+ ## [Quality/Validation Section]
140
+
141
+ [Success criteria and validation steps]
142
+ ```
143
+
144
+ The generated prompt will follow patterns observed in high-quality prompts like:
145
+
146
+ - **Comprehensive blueprints** (architecture-blueprint-generator)
147
+ - **Structured specifications** (create-github-action-workflow-specification)
148
+ - **Best practice guides** (dotnet-best-practices, csharp-xunit)
149
+ - **Implementation plans** (create-implementation-plan)
150
+ - **Code generation** (playwright-generate-test)
151
+
152
+ Each prompt will be optimized for:
153
+
154
+ - **AI Consumption**: Token-efficient, structured content
155
+ - **Maintainability**: Clear sections, consistent formatting
156
+ - **Extensibility**: Easy to modify and enhance
157
+ - **Reliability**: Comprehensive instructions and error handling
158
+
159
+ Please start by telling me the name and description for the new prompt you want to build.
@@ -0,0 +1,25 @@
1
+ name: Publish to npm
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - uses: actions/setup-node@v4
15
+ with:
16
+ node-version: '22'
17
+ registry-url: 'https://registry.npmjs.org'
18
+
19
+ - name: Install dependencies
20
+ run: npm ci
21
+
22
+ - name: Publish to npm
23
+ run: npm publish --access public
24
+ env:
25
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # AI Workflow Template
2
+
3
+ Publishable AI workflow starter pack for GitHub Copilot. This package distributes the `.github/` experience, auto-bumps versions through Husky, and publishes to npm on merges to `main`.
4
+
5
+ ## What This Package Does
6
+
7
+ This repository is designed to be installed as an npm package instead of cloned as a one-off template. When a consuming project installs it, the package can copy its `.github/` folder into the consumer project and keep that folder in sync over time.
8
+
9
+ ### Included capabilities
10
+
11
+ - Copilot instructions and workspace guidance in `.github/co-pilot.instructions.md`
12
+ - Reusable skills in `.github/skills/`
13
+ - Prompt templates in `.github/prompts/`
14
+ - Custom agents in `.github/agents/`
15
+ - Language and framework instructions in `.github/instructions/`
16
+ - Version auto-bumping via Husky pre-commit hook
17
+ - npm publishing workflow on merge to `main`
18
+
19
+ ## Install
20
+
21
+ Install the package in the project that should receive the shared Copilot configuration.
22
+
23
+ ```bash
24
+ npm install ai-workflow-template
25
+ ```
26
+
27
+ If you publish under a scoped name, use that name instead.
28
+
29
+ ## Sync Behavior
30
+
31
+ The package runs `scripts/sync.js` during `postinstall`.
32
+
33
+ - New `.github` files are copied into the consumer project
34
+ - Files that have not been edited locally are refreshed from the package
35
+ - Files that were modified locally are skipped by default
36
+
37
+ ### Manual sync
38
+
39
+ Use the sync script directly when you want to refresh the consumer project on demand.
40
+
41
+ ```bash
42
+ npm run sync
43
+ ```
44
+
45
+ Force overwrite of tracked files when you want the package version to win.
46
+
47
+ ```bash
48
+ npm run sync -- --force
49
+ ```
50
+
51
+ Preview the sync without writing files.
52
+
53
+ ```bash
54
+ npm run sync -- --dry-run
55
+ ```
56
+
57
+ ## Versioning
58
+
59
+ Husky runs a pre-commit hook that bumps the package version automatically.
60
+
61
+ - Normal commits increment the minor version and reset patch to `0`
62
+ - If the major version changes, the script resets the version to `<major>.0.0`
63
+
64
+ Example:
65
+
66
+ ```text
67
+ 1.2.0 -> 1.3.0
68
+ 2.0.0 -> 2.1.0 on the next commit
69
+ ```
70
+
71
+ ## Publish Flow
72
+
73
+ GitHub Actions publishes the package to npm when changes are merged into `main`.
74
+
75
+ ### Required secret
76
+
77
+ Add `NPM_TOKEN` in GitHub repository settings:
78
+
79
+ 1. Open your repository on GitHub
80
+ 2. Go to Settings
81
+ 3. Open Secrets and variables, then Actions
82
+ 4. Add a new repository secret named `NPM_TOKEN`
83
+ 5. Paste an npm automation token
84
+
85
+ ## Local Development
86
+
87
+ Install dependencies once to activate Husky hooks.
88
+
89
+ ```bash
90
+ npm install
91
+ ```
92
+
93
+ Recommended checks:
94
+
95
+ ```bash
96
+ npm run sync -- --dry-run
97
+ npm pack --json
98
+ ```
99
+
100
+ ## Updating the Shared Template
101
+
102
+ 1. Edit the files in `.github/` that should be distributed to consumer projects
103
+ 2. Commit your changes
104
+ 3. Merge to `main` to publish the updated package
105
+ 4. Consumers can run `npm install` again to pull the latest distributed files
106
+
107
+ ## Notes
108
+
109
+ - The sync script uses `INIT_CWD` so installation runs against the consuming project, not the package directory
110
+ - Local changes in a consuming repo are preserved unless you explicitly use `--force`
111
+ - The publish workflow assumes the package is public on npm
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@abarcenas/ai-workflow-template",
3
+ "version": "1.1.0",
4
+ "description": "A comprehensive template repository for AI-assisted development workflows using GitHub Copilot. This template provides a structured approach to leveraging AI assistance through pre-configured skills, prompts, agents, and coding standards.",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "prepare": "husky",
9
+ "sync": "node ./scripts/sync.js",
10
+ "postinstall": "node ./scripts/sync.js"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/abarcenas29/ai-workflow-template.git"
15
+ },
16
+ "keywords": [],
17
+ "author": "",
18
+ "license": "ISC",
19
+ "type": "module",
20
+ "bugs": {
21
+ "url": "https://github.com/abarcenas29/ai-workflow-template/issues"
22
+ },
23
+ "homepage": "https://github.com/abarcenas29/ai-workflow-template#readme",
24
+ "files": [
25
+ ".github/",
26
+ "scripts/"
27
+ ],
28
+ "dependencies": {},
29
+ "devDependencies": {
30
+ "husky": "^9.0.0"
31
+ }
32
+ }
@@ -0,0 +1,29 @@
1
+ import { readFileSync, writeFileSync } from 'fs'
2
+ import { execSync } from 'child_process'
3
+ import { resolve, dirname } from 'path'
4
+ import { fileURLToPath } from 'url'
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url))
7
+ const pkgPath = resolve(__dirname, '../package.json')
8
+
9
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
10
+ const current = pkg.version
11
+ const [curMajor, curMinor] = current.split('.').map(Number)
12
+
13
+ let prevMajor = curMajor
14
+ try {
15
+ const prevPkg = JSON.parse(execSync('git show HEAD:package.json', { encoding: 'utf8' }))
16
+ prevMajor = Number(prevPkg.version.split('.')[0])
17
+ } catch {
18
+ // First commit — no HEAD yet, keep prevMajor === curMajor so minor bumps normally
19
+ }
20
+
21
+ const newVersion =
22
+ curMajor !== prevMajor
23
+ ? `${curMajor}.0.0` // Major changed: normalize, reset minor + patch
24
+ : `${curMajor}.${curMinor + 1}.0` // Normal commit: bump minor, reset patch
25
+
26
+ pkg.version = newVersion
27
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
28
+ execSync('git add package.json')
29
+ console.log(`Version bumped: ${current} → ${newVersion}`)
@@ -0,0 +1,122 @@
1
+ import { createHash } from 'crypto'
2
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'fs'
3
+ import { dirname, join, relative, resolve } from 'path'
4
+ import { fileURLToPath } from 'url'
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url))
7
+ const packageRoot = resolve(__dirname, '..')
8
+ const sourceGithubDir = resolve(packageRoot, '.github')
9
+ const consumerRoot = process.env.INIT_CWD ? resolve(process.env.INIT_CWD) : process.cwd()
10
+ const targetGithubDir = resolve(consumerRoot, '.github')
11
+ const manifestPath = resolve(consumerRoot, '.github-sync-manifest.json')
12
+ const args = new Set(process.argv.slice(2))
13
+ const forceOverwrite = args.has('--force')
14
+ const dryRun = args.has('--dry-run')
15
+
16
+ function hashFile(filePath) {
17
+ const contents = readFileSync(filePath)
18
+ return createHash('sha256').update(contents).digest('hex')
19
+ }
20
+
21
+ function collectFiles(directory) {
22
+ const entries = readdirSync(directory, { withFileTypes: true })
23
+ const files = []
24
+
25
+ for (const entry of entries) {
26
+ const entryPath = join(directory, entry.name)
27
+ if (entry.isDirectory()) {
28
+ files.push(...collectFiles(entryPath))
29
+ continue
30
+ }
31
+
32
+ if (entry.isFile()) {
33
+ files.push(entryPath)
34
+ }
35
+ }
36
+
37
+ return files
38
+ }
39
+
40
+ function readManifest() {
41
+ if (!existsSync(manifestPath)) {
42
+ return { version: 1, files: {} }
43
+ }
44
+
45
+ try {
46
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
47
+ if (!manifest || typeof manifest !== 'object') {
48
+ return { version: 1, files: {} }
49
+ }
50
+
51
+ if (!manifest.files || typeof manifest.files !== 'object') {
52
+ manifest.files = {}
53
+ }
54
+
55
+ return manifest
56
+ } catch {
57
+ return { version: 1, files: {} }
58
+ }
59
+ }
60
+
61
+ function writeManifest(manifest) {
62
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
63
+ }
64
+
65
+ function ensureParentDirectory(filePath) {
66
+ mkdirSync(dirname(filePath), { recursive: true })
67
+ }
68
+
69
+ function syncFile(sourceFile, targetFile) {
70
+ if (dryRun) {
71
+ return
72
+ }
73
+
74
+ ensureParentDirectory(targetFile)
75
+ copyFileSync(sourceFile, targetFile)
76
+ }
77
+
78
+ if (!existsSync(sourceGithubDir)) {
79
+ console.warn('[ai-workflow-template] No .github directory found to sync.')
80
+ process.exit(0)
81
+ }
82
+
83
+ const manifest = readManifest()
84
+ const sourceFiles = collectFiles(sourceGithubDir)
85
+ let copied = 0
86
+ let skipped = 0
87
+ let added = 0
88
+
89
+ for (const sourceFile of sourceFiles) {
90
+ const relativePath = relative(sourceGithubDir, sourceFile)
91
+ const targetFile = resolve(targetGithubDir, relativePath)
92
+ const sourceHash = hashFile(sourceFile)
93
+ const existingHash = existsSync(targetFile) ? hashFile(targetFile) : null
94
+ const recordedHash = manifest.files[relativePath] ?? null
95
+
96
+ if (!existsSync(targetFile)) {
97
+ syncFile(sourceFile, targetFile)
98
+ manifest.files[relativePath] = sourceHash
99
+ copied += 1
100
+ added += 1
101
+ continue
102
+ }
103
+
104
+ const isUntouched = recordedHash !== null && existingHash === recordedHash
105
+
106
+ if (forceOverwrite || isUntouched) {
107
+ syncFile(sourceFile, targetFile)
108
+ manifest.files[relativePath] = sourceHash
109
+ copied += 1
110
+ continue
111
+ }
112
+
113
+ skipped += 1
114
+ console.warn(`[ai-workflow-template] Skipped locally modified file: ${relativePath}`)
115
+ }
116
+
117
+ if (!dryRun) {
118
+ writeManifest(manifest)
119
+ }
120
+
121
+ const modeLabel = forceOverwrite ? 'force' : dryRun ? 'dry-run' : 'safe'
122
+ console.log(`[ai-workflow-template] Synced ${copied} files (${added} new), skipped ${skipped} modified files. Mode: ${modeLabel}.`)