@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.
- package/.github/agents/implementation-plan.agent.md +192 -0
- package/.github/agents/plan.agent.md +135 -0
- package/.github/agents/research-spike.agent.md +204 -0
- package/.github/instructions/agent-safety.instructions.md +98 -0
- package/.github/instructions/agent-skill.instructions.md +272 -0
- package/.github/instructions/agent.instructions.md +1068 -0
- package/.github/instructions/ai-prompt-engineering-safety.instructions.md +991 -0
- package/.github/instructions/angular.instructions.md +116 -0
- package/.github/instructions/context7.instructions.md +109 -0
- package/.github/instructions/go.instructions.md +374 -0
- package/.github/instructions/html-to-css-guide.instructions.md +104 -0
- package/.github/instructions/instructions.instructions.md +264 -0
- package/.github/instructions/markdown.instructions.md +51 -0
- package/.github/instructions/memory-bank.instructions.md +322 -0
- package/.github/instructions/nodejs-vitest.instructions.md +34 -0
- package/.github/instructions/playwright-typescript.instructions.md +88 -0
- package/.github/instructions/prompt.instructions.md +99 -0
- package/.github/instructions/security-owasp.instructions.md +59 -0
- package/.github/instructions/shell.instructions.md +132 -0
- package/.github/instructions/task-implementation.instructions.md +203 -0
- package/.github/instructions/typescript.instructions.md +114 -0
- package/.github/prompts/copilot-instructions-blueprint-generator.prompt.md +317 -0
- package/.github/prompts/documentation-writer.prompt.md +46 -0
- package/.github/prompts/editconfig.prompt.md +64 -0
- package/.github/prompts/playwright-explore.prompt.md +39 -0
- package/.github/prompts/playwright-generate-test.prompt.md +39 -0
- package/.github/skills/agent-governance/SKILL.md +572 -0
- package/.github/skills/boost-prompt/SKILL.md +25 -0
- package/.github/skills/chrome-devtools/SKILL.md +97 -0
- package/.github/skills/context-map/SKILL.md +57 -0
- package/.github/skills/conventional-commit/SKILL.md +72 -0
- package/.github/skills/create-readme/SKILL.md +21 -0
- package/.github/skills/editorconfig/SKILL.md +63 -0
- package/.github/skills/gh-cli/SKILL.md +2188 -0
- package/.github/skills/git-commit/SKILL.md +124 -0
- package/.github/skills/github-issues/SKILL.md +134 -0
- package/.github/skills/github-issues/references/templates.md +110 -0
- package/.github/skills/microsoft-docs/SKILL.md +114 -0
- package/.github/skills/playwright-explore-website/SKILL.md +17 -0
- package/.github/skills/playwright-generate-test/SKILL.md +17 -0
- package/.github/skills/polygot-test-agent/SKILL.md +171 -0
- package/.github/skills/polygot-test-agent/unit-test-genearation.prompt.md +155 -0
- package/.github/skills/prompt-builder/SKILL.md +159 -0
- package/.github/workflows/npm-publish.yml +25 -0
- package/README.md +111 -0
- package/package.json +32 -0
- package/scripts/bump-version.js +29 -0
- 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}`)
|
package/scripts/sync.js
ADDED
|
@@ -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}.`)
|