ma-agents 2.20.3 → 2.22.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/.opencode/skills/.ma-agents.json +241 -0
- package/.opencode/skills/MANIFEST.yaml +254 -0
- package/.opencode/skills/ai-audit-trail/SKILL.md +23 -0
- package/.opencode/skills/auto-bug-detection/SKILL.md +169 -0
- package/.opencode/skills/cmake-best-practices/SKILL.md +64 -0
- package/.opencode/skills/cmake-best-practices/examples/cmake.md +59 -0
- package/.opencode/skills/code-documentation/SKILL.md +57 -0
- package/.opencode/skills/code-documentation/examples/cpp.md +29 -0
- package/.opencode/skills/code-documentation/examples/csharp.md +28 -0
- package/.opencode/skills/code-documentation/examples/javascript_typescript.md +28 -0
- package/.opencode/skills/code-documentation/examples/python.md +57 -0
- package/.opencode/skills/code-review/SKILL.md +43 -0
- package/.opencode/skills/commit-message/SKILL.md +79 -0
- package/.opencode/skills/cpp-best-practices/SKILL.md +234 -0
- package/.opencode/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
- package/.opencode/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
- package/.opencode/skills/cpp-concurrency-safety/SKILL.md +60 -0
- package/.opencode/skills/cpp-concurrency-safety/examples/concurrency.md +73 -0
- package/.opencode/skills/cpp-const-correctness/SKILL.md +63 -0
- package/.opencode/skills/cpp-const-correctness/examples/const_correctness.md +54 -0
- package/.opencode/skills/cpp-memory-handling/SKILL.md +42 -0
- package/.opencode/skills/cpp-memory-handling/examples/modern-cpp.md +49 -0
- package/.opencode/skills/cpp-memory-handling/examples/smart-pointers.md +46 -0
- package/.opencode/skills/cpp-modern-composition/SKILL.md +64 -0
- package/.opencode/skills/cpp-modern-composition/examples/composition.md +51 -0
- package/.opencode/skills/cpp-robust-interfaces/SKILL.md +55 -0
- package/.opencode/skills/cpp-robust-interfaces/examples/interfaces.md +56 -0
- package/.opencode/skills/create-hardened-docker-skill/SKILL.md +637 -0
- package/.opencode/skills/create-hardened-docker-skill/scripts/create-all.sh +489 -0
- package/.opencode/skills/csharp-best-practices/SKILL.md +278 -0
- package/.opencode/skills/docker-hardening-verification/SKILL.md +28 -0
- package/.opencode/skills/docker-hardening-verification/scripts/verify-hardening.sh +39 -0
- package/.opencode/skills/docker-image-signing/SKILL.md +28 -0
- package/.opencode/skills/docker-image-signing/scripts/sign-image.sh +33 -0
- package/.opencode/skills/document-revision-history/SKILL.md +104 -0
- package/.opencode/skills/git-workflow-skill/SKILL.md +194 -0
- package/.opencode/skills/git-workflow-skill/hooks/commit-msg +61 -0
- package/.opencode/skills/git-workflow-skill/hooks/pre-commit +38 -0
- package/.opencode/skills/git-workflow-skill/hooks/prepare-commit-msg +56 -0
- package/.opencode/skills/git-workflow-skill/scripts/finish-feature.sh +192 -0
- package/.opencode/skills/git-workflow-skill/scripts/install-hooks.sh +55 -0
- package/.opencode/skills/git-workflow-skill/scripts/start-feature.sh +110 -0
- package/.opencode/skills/git-workflow-skill/scripts/validate-workflow.sh +229 -0
- package/.opencode/skills/js-ts-dependency-mgmt/SKILL.md +49 -0
- package/.opencode/skills/js-ts-dependency-mgmt/examples/dependency_mgmt.md +60 -0
- package/.opencode/skills/js-ts-security-skill/SKILL.md +64 -0
- package/.opencode/skills/js-ts-security-skill/scripts/verify-security.sh +136 -0
- package/.opencode/skills/logging-best-practices/SKILL.md +50 -0
- package/.opencode/skills/logging-best-practices/examples/cpp.md +36 -0
- package/.opencode/skills/logging-best-practices/examples/csharp.md +49 -0
- package/.opencode/skills/logging-best-practices/examples/javascript.md +77 -0
- package/.opencode/skills/logging-best-practices/examples/python.md +57 -0
- package/.opencode/skills/logging-best-practices/references/logging-standards.md +29 -0
- package/.opencode/skills/open-presentation/SKILL.md +35 -0
- package/.opencode/skills/opentelemetry-best-practices/SKILL.md +34 -0
- package/.opencode/skills/opentelemetry-best-practices/examples/go.md +32 -0
- package/.opencode/skills/opentelemetry-best-practices/examples/javascript.md +58 -0
- package/.opencode/skills/opentelemetry-best-practices/examples/python.md +37 -0
- package/.opencode/skills/opentelemetry-best-practices/references/otel-standards.md +37 -0
- package/.opencode/skills/python-best-practices/SKILL.md +385 -0
- package/.opencode/skills/python-dependency-mgmt/SKILL.md +42 -0
- package/.opencode/skills/python-dependency-mgmt/examples/dependency_mgmt.md +67 -0
- package/.opencode/skills/python-security-skill/SKILL.md +56 -0
- package/.opencode/skills/python-security-skill/examples/security.md +56 -0
- package/.opencode/skills/self-signed-cert/SKILL.md +42 -0
- package/.opencode/skills/self-signed-cert/scripts/generate-cert.ps1 +45 -0
- package/.opencode/skills/self-signed-cert/scripts/generate-cert.sh +43 -0
- package/.opencode/skills/skill-creator/SKILL.md +196 -0
- package/.opencode/skills/skill-creator/references/output-patterns.md +82 -0
- package/.opencode/skills/skill-creator/references/workflows.md +28 -0
- package/.opencode/skills/skill-creator/scripts/init_skill.py +208 -0
- package/.opencode/skills/skill-creator/scripts/package_skill.py +99 -0
- package/.opencode/skills/skill-creator/scripts/quick_validate.py +113 -0
- package/.opencode/skills/story-status-lookup/SKILL.md +78 -0
- package/.opencode/skills/test-accompanied-development/SKILL.md +50 -0
- package/.opencode/skills/test-generator/SKILL.md +65 -0
- package/.opencode/skills/vercel-react-best-practices/SKILL.md +109 -0
- package/.opencode/skills/verify-hardened-docker-skill/SKILL.md +442 -0
- package/.opencode/skills/verify-hardened-docker-skill/scripts/verify-docker-hardening.sh +439 -0
- package/AiAudit.md +5 -0
- package/QUICK_START.md +11 -5
- package/README.md +52 -1
- package/bin/cli.js +31 -4
- package/docs/BMAD_AI_Development_Training.pptx +0 -0
- package/docs/technical-notes/context-persistence-research.md +434 -0
- package/docs/technical-notes/enforcement-hooks-research.md +415 -0
- package/lib/agents.js +34 -0
- package/lib/bmad-extension/agents/bmm-architect.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-bmad-master.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-cyber.customize.yaml +30 -0
- package/lib/bmad-extension/agents/bmm-dev.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-devops.customize.yaml +30 -0
- package/lib/bmad-extension/agents/bmm-mil498.customize.yaml +42 -0
- package/lib/bmad-extension/agents/bmm-pm.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-qa.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-sm.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-sre.customize.yaml +30 -0
- package/lib/bmad-extension/agents/bmm-tech-writer.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-ux-designer.customize.yaml +5 -0
- package/lib/bmad-extension/module-help.csv +7 -0
- package/lib/bmad-extension/module.yaml +3 -0
- package/lib/bmad-extension/workflows/add-sprint/workflow.md +112 -0
- package/lib/bmad-extension/workflows/add-to-sprint/workflow.md +206 -0
- package/lib/bmad-extension/workflows/create-bug-story/workflow.md +186 -0
- package/lib/bmad-extension/workflows/modify-sprint/workflow.md +250 -0
- package/lib/bmad-extension/workflows/project-context-expansion/workflow.md +229 -0
- package/lib/bmad-extension/workflows/sprint-status-view/workflow.md +193 -0
- package/lib/bmad.js +168 -36
- package/lib/hooks/claude-code/verify-manifest.js +56 -0
- package/lib/installer.js +282 -1
- package/lib/methodology/BMAD_AI_Development_Training.pptx +0 -0
- package/lib/methodology/version.json +7 -0
- package/lib/skill-authoring.js +732 -0
- package/lib/templates/project-context.template.md +47 -0
- package/opencode.json +8 -0
- package/package.json +2 -2
- package/skills/auto-bug-detection/SKILL.md +165 -0
- package/skills/auto-bug-detection/skill.json +8 -0
- package/skills/code-review/SKILL.md +40 -0
- package/skills/cpp-best-practices/SKILL.md +230 -0
- package/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
- package/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
- package/skills/cpp-best-practices/skill.json +25 -0
- package/skills/csharp-best-practices/SKILL.md +274 -0
- package/skills/csharp-best-practices/skill.json +23 -0
- package/skills/git-workflow-skill/skill.json +1 -1
- package/skills/open-presentation/SKILL.md +31 -0
- package/skills/open-presentation/skill.json +11 -0
- package/skills/python-best-practices/SKILL.md +381 -0
- package/skills/python-best-practices/skill.json +26 -0
- package/skills/story-status-lookup/SKILL.md +74 -0
- package/skills/story-status-lookup/skill.json +8 -0
- package/test/agent-injection-strategy.test.js +13 -7
- package/test/bmad-extension.test.js +237 -0
- package/test/bmad-output-policy.test.js +119 -0
- package/test/build-bmad-args.test.js +361 -0
- package/test/create-agent.test.js +232 -0
- package/test/enforcement-hooks.test.js +324 -0
- package/test/generate-project-context.test.js +337 -0
- package/test/integration-verification.test.js +402 -0
- package/test/opencode-agent.test.js +150 -0
- package/test/opencode-json-error.test.js +260 -0
- package/test/opencode-json-injection.test.js +256 -0
- package/test/opencode-json-merge.test.js +299 -0
- package/test/skill-authoring.test.js +272 -0
- package/test/skill-customize-agent.test.js +253 -0
- package/test/skill-mandatory.test.js +235 -0
- package/test/skill-validation.test.js +378 -0
- package/test/yes-flag.test.js +1 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Modern C++ Idioms Examples
|
|
2
|
+
|
|
3
|
+
## C++17: Structured Bindings and std::optional
|
|
4
|
+
|
|
5
|
+
```cpp
|
|
6
|
+
#include <map>
|
|
7
|
+
#include <optional>
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
// Structured bindings — prefer over .first/.second
|
|
11
|
+
std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
|
|
12
|
+
for (const auto& [name, score] : scores) {
|
|
13
|
+
// name and score are directly named — no .first/.second
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// std::optional — no more nullptr sentinels or bool out-parameters
|
|
17
|
+
std::optional<std::string> findUser(int id) {
|
|
18
|
+
if (id == 42) return "Alice";
|
|
19
|
+
return std::nullopt; // Not found — explicit, type-safe
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void example() {
|
|
23
|
+
if (const auto user = findUser(42); user.has_value()) {
|
|
24
|
+
// C++17 if-with-initializer keeps 'user' scoped tightly
|
|
25
|
+
doSomethingWith(*user);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## C++17: std::variant for Sum Types
|
|
31
|
+
|
|
32
|
+
```cpp
|
|
33
|
+
#include <variant>
|
|
34
|
+
#include <string>
|
|
35
|
+
|
|
36
|
+
struct Success { std::string message; };
|
|
37
|
+
struct NotFound { int id; };
|
|
38
|
+
struct PermissionDenied { std::string reason; };
|
|
39
|
+
|
|
40
|
+
using LookupResult = std::variant<Success, NotFound, PermissionDenied>;
|
|
41
|
+
|
|
42
|
+
LookupResult lookup(int id) {
|
|
43
|
+
if (id == 0) return NotFound{id};
|
|
44
|
+
if (id < 0) return PermissionDenied{"negative ids reserved"};
|
|
45
|
+
return Success{"found item " + std::to_string(id)};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void handle(const LookupResult& result) {
|
|
49
|
+
std::visit([](const auto& v) {
|
|
50
|
+
using T = std::decay_t<decltype(v)>;
|
|
51
|
+
if constexpr (std::is_same_v<T, Success>) {
|
|
52
|
+
log(v.message);
|
|
53
|
+
} else if constexpr (std::is_same_v<T, NotFound>) {
|
|
54
|
+
log("not found: " + std::to_string(v.id));
|
|
55
|
+
} else {
|
|
56
|
+
log("denied: " + v.reason);
|
|
57
|
+
}
|
|
58
|
+
}, result);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## C++20: Concepts
|
|
63
|
+
|
|
64
|
+
```cpp
|
|
65
|
+
#include <concepts>
|
|
66
|
+
#include <iostream>
|
|
67
|
+
#include <vector>
|
|
68
|
+
|
|
69
|
+
// Before concepts: SFINAE was required — hard to read and debug
|
|
70
|
+
// After concepts: clear, readable constraints
|
|
71
|
+
|
|
72
|
+
template<std::integral T>
|
|
73
|
+
T clamp(T value, T lo, T hi) {
|
|
74
|
+
return std::max(lo, std::min(value, hi));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Custom concept
|
|
78
|
+
template<typename T>
|
|
79
|
+
concept Printable = requires(T t) {
|
|
80
|
+
{ t.toString() } -> std::convertible_to<std::string>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
template<Printable T>
|
|
84
|
+
void printAll(const std::vector<T>& items) {
|
|
85
|
+
for (const auto& item : items) {
|
|
86
|
+
std::cout << item.toString() << '\n';
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## C++20: Ranges
|
|
92
|
+
|
|
93
|
+
```cpp
|
|
94
|
+
#include <algorithm>
|
|
95
|
+
#include <iostream>
|
|
96
|
+
#include <ranges>
|
|
97
|
+
#include <vector>
|
|
98
|
+
#include <string>
|
|
99
|
+
|
|
100
|
+
void modernRanges() {
|
|
101
|
+
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
102
|
+
|
|
103
|
+
// Chain range adaptors — lazy, composable, readable
|
|
104
|
+
auto evenSquares = numbers
|
|
105
|
+
| std::views::filter([](int n) { return n % 2 == 0; })
|
|
106
|
+
| std::views::transform([](int n) { return n * n; });
|
|
107
|
+
|
|
108
|
+
// Iterate result without materializing an intermediate container
|
|
109
|
+
for (int v : evenSquares) {
|
|
110
|
+
std::cout << v << '\n'; // 4 16 36 64 100
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Sorting with ranges — no begin/end iterator boilerplate
|
|
114
|
+
std::vector<std::string> names = {"Charlie", "Alice", "Bob"};
|
|
115
|
+
std::ranges::sort(names);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## C++23: std::expected for Error Handling
|
|
120
|
+
|
|
121
|
+
```cpp
|
|
122
|
+
#include <expected>
|
|
123
|
+
#include <string>
|
|
124
|
+
#include <fstream>
|
|
125
|
+
|
|
126
|
+
enum class ParseError { InvalidFormat, EmptyInput, Overflow };
|
|
127
|
+
|
|
128
|
+
// Return expected<T, E> instead of throwing for anticipated failures
|
|
129
|
+
std::expected<int, ParseError> parsePositiveInt(std::string_view input) {
|
|
130
|
+
if (input.empty()) return std::unexpected(ParseError::EmptyInput);
|
|
131
|
+
int result = 0;
|
|
132
|
+
for (char c : input) {
|
|
133
|
+
if (c < '0' || c > '9') return std::unexpected(ParseError::InvalidFormat);
|
|
134
|
+
result = result * 10 + (c - '0');
|
|
135
|
+
if (result < 0) return std::unexpected(ParseError::Overflow);
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void usage() {
|
|
141
|
+
const auto result = parsePositiveInt("123");
|
|
142
|
+
if (result) {
|
|
143
|
+
std::println("Parsed: {}", *result);
|
|
144
|
+
} else {
|
|
145
|
+
// Handle error without try/catch — expected path, not exceptional
|
|
146
|
+
switch (result.error()) {
|
|
147
|
+
case ParseError::InvalidFormat: std::println("invalid format"); break;
|
|
148
|
+
case ParseError::EmptyInput: std::println("empty input"); break;
|
|
149
|
+
case ParseError::Overflow: std::println("overflow"); break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Class Design: Rule of Zero
|
|
156
|
+
|
|
157
|
+
```cpp
|
|
158
|
+
#include <memory>
|
|
159
|
+
#include <string>
|
|
160
|
+
#include <vector>
|
|
161
|
+
|
|
162
|
+
// Good: Rule of Zero — all members manage themselves
|
|
163
|
+
class Document {
|
|
164
|
+
public:
|
|
165
|
+
explicit Document(std::string title) : title_(std::move(title)) {}
|
|
166
|
+
|
|
167
|
+
void addSection(std::string content) {
|
|
168
|
+
sections_.emplace_back(std::move(content));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private:
|
|
172
|
+
std::string title_; // manages its own lifetime
|
|
173
|
+
std::vector<std::string> sections_; // manages its own lifetime
|
|
174
|
+
// No destructor, no copy/move definitions needed — compiler generates correct ones
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Bad: unnecessary manual resource management
|
|
178
|
+
class BadDocument {
|
|
179
|
+
public:
|
|
180
|
+
BadDocument(const char* title) {
|
|
181
|
+
title_ = new char[strlen(title) + 1]; // raw new — avoid this
|
|
182
|
+
strcpy(title_, title);
|
|
183
|
+
}
|
|
184
|
+
~BadDocument() { delete[] title_; } // manual cleanup — fragile
|
|
185
|
+
// Must also define copy ctor, copy assign, move ctor, move assign correctly...
|
|
186
|
+
private:
|
|
187
|
+
char* title_;
|
|
188
|
+
};
|
|
189
|
+
```
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Naming and Organization Examples
|
|
2
|
+
|
|
3
|
+
## Naming Conventions
|
|
4
|
+
|
|
5
|
+
```cpp
|
|
6
|
+
// File: user_account.h
|
|
7
|
+
#pragma once
|
|
8
|
+
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <string_view>
|
|
11
|
+
#include <optional>
|
|
12
|
+
|
|
13
|
+
namespace myapp::domain {
|
|
14
|
+
|
|
15
|
+
// Types use PascalCase
|
|
16
|
+
class UserAccount {
|
|
17
|
+
public:
|
|
18
|
+
// Constants use UPPER_SNAKE_CASE
|
|
19
|
+
static constexpr int MAX_NAME_LENGTH = 128;
|
|
20
|
+
|
|
21
|
+
// Constructors and methods use camelCase
|
|
22
|
+
explicit UserAccount(std::string_view userName, int accountId);
|
|
23
|
+
|
|
24
|
+
// Const member function — does not modify the object
|
|
25
|
+
[[nodiscard]] std::string_view getUserName() const;
|
|
26
|
+
[[nodiscard]] int getAccountId() const;
|
|
27
|
+
|
|
28
|
+
// Mutating method
|
|
29
|
+
void setUserName(std::string_view newName);
|
|
30
|
+
|
|
31
|
+
private:
|
|
32
|
+
// Private members use camelCase with trailing underscore
|
|
33
|
+
std::string userName_;
|
|
34
|
+
int accountId_;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace myapp::domain
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Header Organization
|
|
41
|
+
|
|
42
|
+
```cpp
|
|
43
|
+
// File: connection_pool.cpp
|
|
44
|
+
|
|
45
|
+
// 1. Project headers first
|
|
46
|
+
#include "connection_pool.h"
|
|
47
|
+
#include "network/socket.h"
|
|
48
|
+
|
|
49
|
+
// 2. Third-party headers
|
|
50
|
+
#include <boost/asio.hpp>
|
|
51
|
+
|
|
52
|
+
// 3. Standard library
|
|
53
|
+
#include <algorithm>
|
|
54
|
+
#include <chrono>
|
|
55
|
+
#include <memory>
|
|
56
|
+
#include <vector>
|
|
57
|
+
|
|
58
|
+
namespace myapp::network {
|
|
59
|
+
// ...
|
|
60
|
+
} // namespace myapp::network
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Forward Declarations to Reduce Coupling
|
|
64
|
+
|
|
65
|
+
```cpp
|
|
66
|
+
// File: request_handler.h
|
|
67
|
+
#pragma once
|
|
68
|
+
|
|
69
|
+
// Forward declare instead of including the full header
|
|
70
|
+
namespace myapp::domain {
|
|
71
|
+
class UserAccount;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
namespace myapp::network {
|
|
75
|
+
|
|
76
|
+
class RequestHandler {
|
|
77
|
+
public:
|
|
78
|
+
// Only a reference/pointer is needed here — forward declaration is sufficient
|
|
79
|
+
void handle(const myapp::domain::UserAccount& user);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
} // namespace myapp::network
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Namespace Usage
|
|
86
|
+
|
|
87
|
+
```cpp
|
|
88
|
+
// Good: deeply nested namespace matching directory structure
|
|
89
|
+
namespace myapp::network::http {
|
|
90
|
+
|
|
91
|
+
class Client {
|
|
92
|
+
// ...
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
} // namespace myapp::network::http
|
|
96
|
+
|
|
97
|
+
// Avoid in headers — pollutes every translation unit that includes this header:
|
|
98
|
+
// using namespace std; // BAD in headers
|
|
99
|
+
|
|
100
|
+
// OK in .cpp files, restricted to file scope:
|
|
101
|
+
// using namespace myapp::network::http;
|
|
102
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "C++ Best Practices",
|
|
3
|
+
"description": "Comprehensive C++ coding standards covering naming conventions, modern C++ idioms (C++17/20/23), error handling, and build guidelines. Cross-references domain-specific C++ skills for deep-dives.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "Antigravity",
|
|
6
|
+
"tags": [
|
|
7
|
+
"c++",
|
|
8
|
+
"cpp",
|
|
9
|
+
"coding-standards",
|
|
10
|
+
"best-practices",
|
|
11
|
+
"modern-cpp",
|
|
12
|
+
"c++17",
|
|
13
|
+
"c++20",
|
|
14
|
+
"c++23"
|
|
15
|
+
],
|
|
16
|
+
"applies_when": [
|
|
17
|
+
"writing c++ code",
|
|
18
|
+
"modifying c++ code",
|
|
19
|
+
"creating new c++ files or classes",
|
|
20
|
+
"reviewing c++ code style or conventions",
|
|
21
|
+
"refactoring c++ code",
|
|
22
|
+
"setting up a c++ project"
|
|
23
|
+
],
|
|
24
|
+
"always_load": true
|
|
25
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# C# Best Practices
|
|
2
|
+
|
|
3
|
+
Coding standards for modern C# (C# 10+) across .NET 6 through .NET 8+. This skill covers language-level patterns. Framework-specific patterns (ASP.NET Core middleware, EF Core, Blazor) belong in future skills.
|
|
4
|
+
|
|
5
|
+
## 1. Naming Conventions
|
|
6
|
+
|
|
7
|
+
**Rule:** Use consistent naming to maximize code readability and tooling support.
|
|
8
|
+
|
|
9
|
+
| Element | Convention | Example |
|
|
10
|
+
|---------|-----------|---------|
|
|
11
|
+
| Namespace | PascalCase, match folder | `MyApp.Services` |
|
|
12
|
+
| Class / Struct / Record | PascalCase | `CustomerService` |
|
|
13
|
+
| Interface | `I` + PascalCase | `ICustomerService` |
|
|
14
|
+
| Method | PascalCase | `GetCustomerAsync` |
|
|
15
|
+
| Property | PascalCase | `FirstName` |
|
|
16
|
+
| Local variable | camelCase | `customerCount` |
|
|
17
|
+
| Parameter | camelCase | `customerId` |
|
|
18
|
+
| Private field | `_` + camelCase | `_logger` |
|
|
19
|
+
| Constant | PascalCase | `MaxRetryCount` |
|
|
20
|
+
| Enum type | PascalCase singular | `OrderStatus` |
|
|
21
|
+
| Enum member | PascalCase | `OrderStatus.Pending` |
|
|
22
|
+
| Async method | suffix `Async` | `SaveAsync` |
|
|
23
|
+
|
|
24
|
+
## 2. Code Organization
|
|
25
|
+
|
|
26
|
+
**Rule:** One type per file; namespace matches folder path.
|
|
27
|
+
|
|
28
|
+
- File-scoped namespace declaration (C# 10+): `namespace MyApp.Services;` — no extra indentation level.
|
|
29
|
+
- Organize types in the order: constants, fields, constructors, properties, methods (public first, then private).
|
|
30
|
+
- Use `global using` directives in a dedicated `GlobalUsings.cs` file to eliminate repetitive `using` statements project-wide.
|
|
31
|
+
- Prefer `record` types for immutable data containers; use `record struct` for small value-type data.
|
|
32
|
+
|
|
33
|
+
## 3. Nullable Reference Types
|
|
34
|
+
|
|
35
|
+
**Rule:** Enable NRT project-wide and treat warnings as errors.
|
|
36
|
+
|
|
37
|
+
```xml
|
|
38
|
+
<Nullable>enable</Nullable>
|
|
39
|
+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- Never use `!` (null-forgiving) to silence warnings without a documented reason.
|
|
43
|
+
- Use `string?` for intentionally nullable references; non-nullable types must be initialized before use.
|
|
44
|
+
- Initialize fields in the constructor or use `required` members (C# 11+) to enforce initialization at the call site.
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
public class Order
|
|
48
|
+
{
|
|
49
|
+
public required string CustomerId { get; init; }
|
|
50
|
+
public string? Notes { get; init; }
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 4. Modern C# Language Features
|
|
55
|
+
|
|
56
|
+
### 4.1 Primary Constructors (C# 12)
|
|
57
|
+
|
|
58
|
+
Use primary constructors for classes and structs that primarily capture injected dependencies.
|
|
59
|
+
|
|
60
|
+
```csharp
|
|
61
|
+
public class OrderService(IOrderRepository repository, ILogger<OrderService> logger)
|
|
62
|
+
{
|
|
63
|
+
public async Task<Order?> GetAsync(int id, CancellationToken ct)
|
|
64
|
+
{
|
|
65
|
+
logger.LogInformation("Getting order {Id}", id);
|
|
66
|
+
return await repository.FindAsync(id, ct);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 4.2 Collection Expressions (C# 12)
|
|
72
|
+
|
|
73
|
+
Prefer collection expressions over explicit constructors for collection initialization.
|
|
74
|
+
|
|
75
|
+
```csharp
|
|
76
|
+
// Preferred
|
|
77
|
+
int[] ids = [1, 2, 3];
|
|
78
|
+
List<string> names = ["Alice", "Bob"];
|
|
79
|
+
|
|
80
|
+
// Also valid for spread
|
|
81
|
+
int[] combined = [..ids, 4, 5];
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4.3 Raw String Literals (C# 11)
|
|
85
|
+
|
|
86
|
+
Use raw string literals for JSON, SQL, or multi-line strings to avoid escaping.
|
|
87
|
+
|
|
88
|
+
```csharp
|
|
89
|
+
var json = """
|
|
90
|
+
{
|
|
91
|
+
"name": "Alice",
|
|
92
|
+
"age": 30
|
|
93
|
+
}
|
|
94
|
+
""";
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 4.4 Pattern Matching
|
|
98
|
+
|
|
99
|
+
Use pattern matching to simplify type checks and conditional logic.
|
|
100
|
+
|
|
101
|
+
```csharp
|
|
102
|
+
// Type patterns
|
|
103
|
+
string Describe(object obj) => obj switch
|
|
104
|
+
{
|
|
105
|
+
int n when n > 0 => "positive integer",
|
|
106
|
+
int n => "non-positive integer",
|
|
107
|
+
string s => $"string: {s}",
|
|
108
|
+
null => "null",
|
|
109
|
+
_ => "other"
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// List patterns (C# 11)
|
|
113
|
+
bool IsFirstTwo(int[] arr) => arr is [var first, var second, ..];
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 4.5 Records and Record Structs
|
|
117
|
+
|
|
118
|
+
Use `record` for immutable reference-type DTOs and value objects. Use `readonly record struct` for small immutable value types that benefit from stack allocation.
|
|
119
|
+
|
|
120
|
+
```csharp
|
|
121
|
+
// Reference-type record (class semantics, heap allocated)
|
|
122
|
+
public record Address(string Street, string City, string PostalCode);
|
|
123
|
+
|
|
124
|
+
// with-expressions for non-destructive mutation
|
|
125
|
+
var updated = original with { City = "New York" };
|
|
126
|
+
|
|
127
|
+
// Value-type record (struct semantics, stack allocated)
|
|
128
|
+
public readonly record struct Point(double X, double Y);
|
|
129
|
+
|
|
130
|
+
// Mutable record struct — only when mutation is explicitly needed
|
|
131
|
+
public record struct Range(int Start, int End);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Choose `readonly record struct` over `record` when: the data is small (2-4 fields), frequently allocated in hot paths, and value semantics (equality by value, copied on assignment) are correct.
|
|
135
|
+
|
|
136
|
+
### 4.6 File-Scoped Types (C# 11)
|
|
137
|
+
|
|
138
|
+
Use the `file` access modifier to restrict a type's visibility to the single file where it is declared. This is useful for implementation detail types that should not leak into other files.
|
|
139
|
+
|
|
140
|
+
```csharp
|
|
141
|
+
// Only visible within this .cs file — cannot be used from any other file
|
|
142
|
+
file class OrderValidator
|
|
143
|
+
{
|
|
144
|
+
public bool IsValid(Order order) => order.CustomerId is not null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Also applies to records, structs, interfaces, delegates
|
|
148
|
+
file record struct ValidationResult(bool IsValid, string? Error);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Use `file`-scoped types for: helper classes private to a single implementation file, source generators' internal scaffolding, and avoiding name collisions across files without polluting `internal` scope.
|
|
152
|
+
|
|
153
|
+
## 5. Async/Await
|
|
154
|
+
|
|
155
|
+
**Rule:** Use async all the way up the call stack; never block on async code.
|
|
156
|
+
|
|
157
|
+
- Prefer `async Task` / `async Task<T>` over returning naked `Task`.
|
|
158
|
+
- Never use `async void` except for event handlers; use `async Task` instead.
|
|
159
|
+
- Always propagate `CancellationToken` from public API boundaries down to I/O calls.
|
|
160
|
+
- Prefer `ConfigureAwait(false)` in library code where the calling context does not matter.
|
|
161
|
+
- Use `ValueTask<T>` when a method frequently returns a synchronous result (hot-path optimization); default to `Task<T>` for simplicity.
|
|
162
|
+
|
|
163
|
+
```csharp
|
|
164
|
+
// Correct — async all the way, CancellationToken propagated, ConfigureAwait in library code
|
|
165
|
+
public async Task<Order?> FindOrderAsync(int id, CancellationToken ct = default)
|
|
166
|
+
{
|
|
167
|
+
return await _repository.GetByIdAsync(id, ct).ConfigureAwait(false);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Correct — multiple I/O operations with cancellation
|
|
171
|
+
public async Task<IReadOnlyList<Order>> GetActiveOrdersAsync(CancellationToken ct = default)
|
|
172
|
+
{
|
|
173
|
+
var orders = await _repository.ListAsync(ct).ConfigureAwait(false);
|
|
174
|
+
return orders.Where(o => o.IsActive).ToList();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Wrong — blocks the thread pool, risks deadlock
|
|
178
|
+
public Order? FindOrder(int id) => FindOrderAsync(id).Result;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 6. LINQ
|
|
182
|
+
|
|
183
|
+
**Rule:** Prefer method syntax; be aware of deferred execution.
|
|
184
|
+
|
|
185
|
+
- Use method syntax (`Where`, `Select`, `FirstOrDefault`) over query syntax for consistency with the rest of the codebase.
|
|
186
|
+
- LINQ queries execute lazily — materialize with `.ToList()`, `.ToArray()`, or `.ToDictionary()` when the result will be enumerated more than once or when you need a stable snapshot.
|
|
187
|
+
- Avoid LINQ inside tight loops on large collections; profile before assuming LINQ is a bottleneck.
|
|
188
|
+
- For in-memory filtering on large datasets, consider `AsSpan()` or `ArrayPool<T>` instead of repeated LINQ queries.
|
|
189
|
+
|
|
190
|
+
```csharp
|
|
191
|
+
// Materialize when enumerating multiple times
|
|
192
|
+
var activeOrders = orders.Where(o => o.IsActive).ToList();
|
|
193
|
+
|
|
194
|
+
// Avoid multiple enumeration of IEnumerable
|
|
195
|
+
foreach (var order in activeOrders) { /* ... */ }
|
|
196
|
+
int count = activeOrders.Count;
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 7. Error Handling
|
|
200
|
+
|
|
201
|
+
**Rule:** Use structured exception handling; reserve exceptions for truly exceptional conditions.
|
|
202
|
+
|
|
203
|
+
- Define a domain exception hierarchy derived from a base exception: `AppException : Exception`.
|
|
204
|
+
- Use the Result pattern for expected failure cases (validation, not-found) where exceptions are expensive overhead.
|
|
205
|
+
- For HTTP APIs, structure error responses using ProblemDetails (RFC 9457) — the language-level concern is ensuring your exceptions carry enough data to produce one; the middleware that converts them belongs in a future `csharp-aspnet-patterns` skill.
|
|
206
|
+
- Never swallow exceptions silently; always log or rethrow.
|
|
207
|
+
|
|
208
|
+
```csharp
|
|
209
|
+
// Result pattern for expected failures
|
|
210
|
+
public record Result<T>(T? Value, string? Error)
|
|
211
|
+
{
|
|
212
|
+
public bool IsSuccess => Error is null;
|
|
213
|
+
public static Result<T> Ok(T value) => new(value, null);
|
|
214
|
+
public static Result<T> Fail(string error) => new(default, error);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Exception hierarchy
|
|
218
|
+
public class AppException(string message) : Exception(message);
|
|
219
|
+
public class NotFoundException(string entity, object id)
|
|
220
|
+
: AppException($"{entity} with id '{id}' was not found.");
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 8. Dependency Injection
|
|
224
|
+
|
|
225
|
+
**Rule:** Favor constructor injection; choose service lifetimes deliberately.
|
|
226
|
+
|
|
227
|
+
- Constructor injection is the standard pattern — inject only what the type needs.
|
|
228
|
+
- **Singleton:** One instance for the application lifetime. Use for stateless services and configuration.
|
|
229
|
+
- **Scoped:** One instance per request (web) or operation scope. Use for database contexts and unit-of-work patterns.
|
|
230
|
+
- **Transient:** New instance per resolution. Use for lightweight, stateless utilities.
|
|
231
|
+
- Never inject a Scoped or Transient service into a Singleton — this causes captive dependency bugs.
|
|
232
|
+
|
|
233
|
+
```csharp
|
|
234
|
+
// Registration via IServiceCollection (Microsoft.Extensions.DependencyInjection)
|
|
235
|
+
// Works in console apps, workers, ASP.NET Core, and any .NET host
|
|
236
|
+
IServiceCollection services = new ServiceCollection();
|
|
237
|
+
services.AddSingleton<IConfigService, ConfigService>();
|
|
238
|
+
services.AddScoped<IOrderService, OrderService>();
|
|
239
|
+
services.AddTransient<IEmailFormatter, EmailFormatter>();
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## 9. Testing
|
|
243
|
+
|
|
244
|
+
**Rule:** Follow Arrange-Act-Assert; use framework-agnostic patterns.
|
|
245
|
+
|
|
246
|
+
- Name tests: `MethodName_StateUnderTest_ExpectedBehavior`.
|
|
247
|
+
- Arrange all preconditions, act on the system under test, assert the single observable outcome.
|
|
248
|
+
- Major test frameworks: xUnit (most popular for .NET), NUnit, MSTest — choose based on team preference.
|
|
249
|
+
- Popular assertion libraries: FluentAssertions, Shouldly. Popular mock libraries: NSubstitute, Moq.
|
|
250
|
+
- Avoid test logic that depends on execution order; each test must be independent.
|
|
251
|
+
|
|
252
|
+
```csharp
|
|
253
|
+
// xUnit example (patterns apply to NUnit/MSTest)
|
|
254
|
+
public class OrderServiceTests
|
|
255
|
+
{
|
|
256
|
+
[Fact]
|
|
257
|
+
public async Task GetAsync_ExistingId_ReturnsOrder()
|
|
258
|
+
{
|
|
259
|
+
// Arrange
|
|
260
|
+
var repository = Substitute.For<IOrderRepository>();
|
|
261
|
+
var logger = Substitute.For<ILogger<OrderService>>();
|
|
262
|
+
repository.FindAsync(1, Arg.Any<CancellationToken>())
|
|
263
|
+
.Returns(new Order { Id = 1 });
|
|
264
|
+
var sut = new OrderService(repository, logger);
|
|
265
|
+
|
|
266
|
+
// Act
|
|
267
|
+
var result = await sut.GetAsync(1, CancellationToken.None);
|
|
268
|
+
|
|
269
|
+
// Assert
|
|
270
|
+
result.Should().NotBeNull();
|
|
271
|
+
result!.Id.Should().Be(1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "C# Best Practices",
|
|
3
|
+
"description": "Comprehensive C# coding standards covering modern C# (C# 10-12), async/await, LINQ, dependency injection basics, nullable reference types, and testing conventions.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "ma-agents",
|
|
6
|
+
"tags": [
|
|
7
|
+
"csharp",
|
|
8
|
+
"c#",
|
|
9
|
+
"dotnet",
|
|
10
|
+
".net",
|
|
11
|
+
"coding-standards",
|
|
12
|
+
"best-practices",
|
|
13
|
+
"net8"
|
|
14
|
+
],
|
|
15
|
+
"applies_when": [
|
|
16
|
+
"writing c# code",
|
|
17
|
+
"creating new c# files or classes",
|
|
18
|
+
"reviewing c# code style or conventions",
|
|
19
|
+
"working with .net projects",
|
|
20
|
+
"setting up a c# project"
|
|
21
|
+
],
|
|
22
|
+
"always_load": true
|
|
23
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Open Presentation Skill
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
Opens the BMAD-METHOD AI Development Training presentation installed at `_bmad-output/methodology/`.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
Invoke this skill by typing `/open-presentation`.
|
|
8
|
+
|
|
9
|
+
## Instructions
|
|
10
|
+
|
|
11
|
+
When the user invokes `/open-presentation`:
|
|
12
|
+
|
|
13
|
+
1. **Locate the presentation** at `_bmad-output/methodology/BMAD_AI_Development_Training.pptx` relative to the project root.
|
|
14
|
+
|
|
15
|
+
2. **Open it** using the OS default viewer via the Bash tool:
|
|
16
|
+
- **Windows**: `start "" "_bmad-output/methodology/BMAD_AI_Development_Training.pptx"`
|
|
17
|
+
- **macOS**: `open "_bmad-output/methodology/BMAD_AI_Development_Training.pptx"`
|
|
18
|
+
- **Linux**: `xdg-open "_bmad-output/methodology/BMAD_AI_Development_Training.pptx"`
|
|
19
|
+
|
|
20
|
+
3. **If the file does not exist**, inform the user:
|
|
21
|
+
> "The methodology presentation has not been installed yet. Run `npx ma-agents install` with BMAD to deploy it to `_bmad-output/methodology/`."
|
|
22
|
+
|
|
23
|
+
4. **Detect the OS** using the Node.js `process.platform` convention or by checking which command is available, then run the appropriate open command.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
**User**: `/open-presentation`
|
|
28
|
+
**Assistant**: Opens `_bmad-output/methodology/BMAD_AI_Development_Training.pptx` in the system default PowerPoint viewer.
|
|
29
|
+
|
|
30
|
+
**User**: "open the methodology slides"
|
|
31
|
+
**Assistant**: [Treats this as /open-presentation and follows the instructions above]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Open Presentation",
|
|
3
|
+
"description": "Opens the BMAD-METHOD AI Development Training presentation from _bmad-output/methodology/",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "AI Agent Skills",
|
|
6
|
+
"tags": ["methodology", "presentation", "bmad", "training"],
|
|
7
|
+
"applies_when": [
|
|
8
|
+
"user types /open-presentation",
|
|
9
|
+
"user asks to open the methodology presentation or training slides"
|
|
10
|
+
]
|
|
11
|
+
}
|