@torus-engineering/tas-kit 1.9.0 → 1.11.1
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/.claude/commands/ado-create.md +17 -17
- package/.claude/commands/ado-delete.md +11 -11
- package/.claude/commands/ado-get.md +12 -12
- package/.claude/commands/ado-status.md +12 -12
- package/.claude/commands/ado-update.md +15 -15
- package/.claude/commands/tas-adr.md +33 -33
- package/.claude/commands/tas-apitest-plan.md +173 -173
- package/.claude/commands/tas-apitest.md +143 -143
- package/.claude/commands/tas-brainstorm.md +14 -14
- package/.claude/commands/tas-bug.md +113 -113
- package/.claude/commands/tas-design.md +37 -37
- package/.claude/commands/tas-dev.md +128 -128
- package/.claude/commands/tas-e2e-mobile.md +155 -155
- package/.claude/commands/tas-e2e-web.md +163 -163
- package/.claude/commands/tas-e2e.md +102 -102
- package/.claude/commands/tas-epic.md +35 -35
- package/.claude/commands/tas-feature.md +47 -47
- package/.claude/commands/tas-fix.md +51 -51
- package/.claude/commands/tas-functest-mobile.md +144 -144
- package/.claude/commands/tas-functest-web.md +192 -192
- package/.claude/commands/tas-functest.md +76 -76
- package/.claude/commands/tas-init.md +14 -14
- package/.claude/commands/tas-plan.md +198 -200
- package/.claude/commands/tas-prd.md +37 -37
- package/.claude/commands/tas-review.md +111 -111
- package/.claude/commands/tas-sad.md +43 -43
- package/.claude/commands/tas-security.md +87 -81
- package/.claude/commands/tas-spec.md +20 -20
- package/.claude/commands/tas-status.md +13 -13
- package/.claude/commands/tas-story.md +91 -91
- package/.claude/commands/tas-verify.md +51 -51
- package/.claude/rules/common/post-review-agent.md +49 -49
- package/.claude/rules/common/project-status.md +14 -14
- package/.claude/rules/common/stack-detection.md +6 -6
- package/.claude/rules/common/token-logging.md +27 -27
- package/.claude/rules/csharp/api-testing.md +171 -171
- package/.claude/skills/ado-integration/SKILL.md +36 -36
- package/.claude/skills/tas-conventions/SKILL.md +32 -32
- package/.claude/skills/tas-implementation-complete/SKILL.md +100 -99
- package/.claude/skills/tas-tdd/SKILL.md +123 -123
- package/.claude/skills/token-logger/SKILL.md +19 -19
- package/.tas/README.md +266 -1520
- package/.tas/checklists/code-review.md +13 -13
- package/.tas/checklists/security.md +3 -3
- package/.tas/checklists/story-done.md +11 -11
- package/.tas/hooks/README.md +138 -0
- package/.tas/hooks/pre-commit +26 -0
- package/.tas/hooks/security-scan.js +599 -0
- package/.tas/project-status-example.yaml +3 -3
- package/.tas/tas-example.yaml +25 -8
- package/.tas/templates/ADR.md +16 -16
- package/.tas/templates/API-Test-Spec.md +3 -3
- package/.tas/templates/Bug.md +12 -12
- package/.tas/templates/Design-Spec.md +8 -8
- package/.tas/templates/E2E-Execution-Report.md +1 -1
- package/.tas/templates/Epic.md +1 -1
- package/.tas/templates/Feature.md +10 -10
- package/.tas/templates/Func-Test-Spec.md +3 -3
- package/.tas/templates/SAD.md +106 -106
- package/.tas/templates/Security-Report.md +3 -3
- package/.tas/templates/Story.md +9 -9
- package/.tas/tools/tas-ado-readme.md +169 -169
- package/.tas/tools/tas-ado.py +1 -1
- package/CLAUDE-Example.md +37 -58
- package/README.md +294 -42
- package/bin/cli.js +24 -7
- package/lib/install.js +161 -47
- package/package.json +1 -1
|
@@ -1,171 +1,171 @@
|
|
|
1
|
-
---
|
|
2
|
-
paths:
|
|
3
|
-
- "**/*.cs"
|
|
4
|
-
- "**/ApiTests/**"
|
|
5
|
-
- "**/Api.Tests/**"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# C# API Automation Testing
|
|
9
|
-
|
|
10
|
-
>
|
|
11
|
-
|
|
12
|
-
## Tech Stack
|
|
13
|
-
|
|
14
|
-
|
|
|
15
|
-
|---|---|
|
|
16
|
-
| Framework | xUnit (default) — match project
|
|
17
|
-
| Assertions | FluentAssertions |
|
|
18
|
-
| HTTP | System.Net.Http.HttpClient |
|
|
19
|
-
| Config | Microsoft.Extensions.Configuration + JSON/EnvVars |
|
|
20
|
-
|
|
21
|
-
```xml
|
|
22
|
-
<!-- ApiTests.csproj packages -->
|
|
23
|
-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
|
|
24
|
-
<PackageReference Include="xunit" Version="2.*" />
|
|
25
|
-
<PackageReference Include="xunit.runner.visualstudio" Version="2.*" />
|
|
26
|
-
<PackageReference Include="FluentAssertions" Version="6.*" />
|
|
27
|
-
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.*" />
|
|
28
|
-
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.*" />
|
|
29
|
-
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.*" />
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Project Structure
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
tests/ApiTests/
|
|
36
|
-
appsettings.json # base (
|
|
37
|
-
appsettings.Test.json # Test env override
|
|
38
|
-
appsettings.Staging.json # Staging env override
|
|
39
|
-
.gitignore # appsettings.*.local.json
|
|
40
|
-
Shared/
|
|
41
|
-
ApiTestSettings.cs
|
|
42
|
-
TestBase.cs
|
|
43
|
-
v1/
|
|
44
|
-
UsersApiTests.cs
|
|
45
|
-
v2/ # APPEND-ONLY:
|
|
46
|
-
UsersApiTests.cs
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Config
|
|
50
|
-
|
|
51
|
-
```json
|
|
52
|
-
// appsettings.json
|
|
53
|
-
{
|
|
54
|
-
"ApiTest": {
|
|
55
|
-
"BaseUrl": "https://localhost:5001",
|
|
56
|
-
"TimeoutSeconds": 30,
|
|
57
|
-
"Auth": { "Type": "Bearer", "TokenEndpoint": "/api/auth/token", "Username": "", "Password": "" }
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
```csharp
|
|
63
|
-
// ApiTestSettings.cs
|
|
64
|
-
public sealed class ApiTestSettings
|
|
65
|
-
{
|
|
66
|
-
public required string BaseUrl { get; init; }
|
|
67
|
-
public int TimeoutSeconds { get; init; } = 30;
|
|
68
|
-
public required AuthSettings Auth { get; init; }
|
|
69
|
-
}
|
|
70
|
-
public sealed class AuthSettings
|
|
71
|
-
{
|
|
72
|
-
public string Type { get; init; } = "Bearer";
|
|
73
|
-
public string TokenEndpoint { get; init; } = "/api/auth/token";
|
|
74
|
-
public string Username { get; init; } = "";
|
|
75
|
-
public string Password { get; init; } = "";
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
```csharp
|
|
80
|
-
// TestBase.cs
|
|
81
|
-
public abstract class TestBase : IAsyncLifetime
|
|
82
|
-
{
|
|
83
|
-
protected HttpClient Client { get; private set; } = null!;
|
|
84
|
-
protected ApiTestSettings Settings { get; private set; } = null!;
|
|
85
|
-
|
|
86
|
-
public async Task InitializeAsync()
|
|
87
|
-
{
|
|
88
|
-
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Test";
|
|
89
|
-
Settings = new ConfigurationBuilder()
|
|
90
|
-
.AddJsonFile("appsettings.json")
|
|
91
|
-
.AddJsonFile($"appsettings.{env}.json", optional: true)
|
|
92
|
-
.AddEnvironmentVariables("APITEST_")
|
|
93
|
-
.Build()
|
|
94
|
-
.GetRequiredSection("ApiTest").Get<ApiTestSettings>()!;
|
|
95
|
-
|
|
96
|
-
Client = new HttpClient { BaseAddress = new Uri(Settings.BaseUrl),
|
|
97
|
-
Timeout = TimeSpan.FromSeconds(Settings.TimeoutSeconds) };
|
|
98
|
-
|
|
99
|
-
if (!string.IsNullOrEmpty(Settings.Auth.Username))
|
|
100
|
-
await AuthenticateAsync();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public Task DisposeAsync() { Client.Dispose(); return Task.CompletedTask; }
|
|
104
|
-
|
|
105
|
-
protected async Task AuthenticateAsync(string? username = null, string? password = null)
|
|
106
|
-
{
|
|
107
|
-
var res = await Client.PostAsJsonAsync(Settings.Auth.TokenEndpoint,
|
|
108
|
-
new { username = username ?? Settings.Auth.Username, password = password ?? Settings.Auth.Password });
|
|
109
|
-
res.EnsureSuccessStatusCode();
|
|
110
|
-
var token = (await res.Content.ReadFromJsonAsync<TokenResponse>())!.AccessToken;
|
|
111
|
-
Client.DefaultRequestHeaders.Authorization =
|
|
112
|
-
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
private sealed record TokenResponse(string AccessToken);
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Test Class Header (
|
|
120
|
-
|
|
121
|
-
```csharp
|
|
122
|
-
// ============================================================
|
|
123
|
-
// {Resource} API Tests — v{N}
|
|
124
|
-
// Spec: {spec-file} | Generated: {YYYY-MM-DD} | Story: {ID}
|
|
125
|
-
// APPEND-ONLY:
|
|
126
|
-
// ============================================================
|
|
127
|
-
namespace ApiTests.V{N};
|
|
128
|
-
public sealed class {Resource}ApiTests : TestBase
|
|
129
|
-
{
|
|
130
|
-
// Inline DTOs —
|
|
131
|
-
private sealed record {Resource}Dto(Guid Id, string Name);
|
|
132
|
-
private sealed record ListResponse<T>(IReadOnlyList<T> Data, int Total);
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## Test Naming
|
|
137
|
-
|
|
138
|
-
```
|
|
139
|
-
{HttpMethod}_{Resource}_Returns{Status}_When{Condition}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
AC test: comment `// AC: {text}`
|
|
145
|
-
|
|
146
|
-
## XML Doc (
|
|
147
|
-
|
|
148
|
-
```csharp
|
|
149
|
-
/// <summary>Verify {METHOD} {path} → {status}
|
|
150
|
-
[Fact]
|
|
151
|
-
public async Task ...
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Coverage Matrix
|
|
155
|
-
|
|
156
|
-
|
|
|
157
|
-
|---|---|---|
|
|
158
|
-
| Valid, authenticated | 2xx |
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
| `{id}`
|
|
162
|
-
| Required field
|
|
163
|
-
| Business rule (
|
|
164
|
-
|
|
165
|
-
## CI/CD Env Vars
|
|
166
|
-
|
|
167
|
-
```
|
|
168
|
-
ASPNETCORE_ENVIRONMENT=Test
|
|
169
|
-
APITEST__AUTH__USERNAME=... # double __
|
|
170
|
-
APITEST__AUTH__PASSWORD=...
|
|
171
|
-
```
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.cs"
|
|
4
|
+
- "**/ApiTests/**"
|
|
5
|
+
- "**/Api.Tests/**"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# C# API Automation Testing
|
|
9
|
+
|
|
10
|
+
> Used by `/tas-api-test`. Extends [csharp/testing.md](./testing.md).
|
|
11
|
+
|
|
12
|
+
## Tech Stack
|
|
13
|
+
|
|
14
|
+
| Component | Choice |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Framework | xUnit (default) — match project if already using MSTest/NUnit |
|
|
17
|
+
| Assertions | FluentAssertions |
|
|
18
|
+
| HTTP | System.Net.Http.HttpClient |
|
|
19
|
+
| Config | Microsoft.Extensions.Configuration + JSON/EnvVars |
|
|
20
|
+
|
|
21
|
+
```xml
|
|
22
|
+
<!-- ApiTests.csproj packages -->
|
|
23
|
+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
|
|
24
|
+
<PackageReference Include="xunit" Version="2.*" />
|
|
25
|
+
<PackageReference Include="xunit.runner.visualstudio" Version="2.*" />
|
|
26
|
+
<PackageReference Include="FluentAssertions" Version="6.*" />
|
|
27
|
+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.*" />
|
|
28
|
+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.*" />
|
|
29
|
+
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.*" />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Project Structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
tests/ApiTests/
|
|
36
|
+
appsettings.json # base (no real secrets)
|
|
37
|
+
appsettings.Test.json # Test env override
|
|
38
|
+
appsettings.Staging.json # Staging env override
|
|
39
|
+
.gitignore # appsettings.*.local.json
|
|
40
|
+
Shared/
|
|
41
|
+
ApiTestSettings.cs
|
|
42
|
+
TestBase.cs
|
|
43
|
+
v1/
|
|
44
|
+
UsersApiTests.cs
|
|
45
|
+
v2/ # APPEND-ONLY: don't modify v1
|
|
46
|
+
UsersApiTests.cs
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Config
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
// appsettings.json
|
|
53
|
+
{
|
|
54
|
+
"ApiTest": {
|
|
55
|
+
"BaseUrl": "https://localhost:5001",
|
|
56
|
+
"TimeoutSeconds": 30,
|
|
57
|
+
"Auth": { "Type": "Bearer", "TokenEndpoint": "/api/auth/token", "Username": "", "Password": "" }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```csharp
|
|
63
|
+
// ApiTestSettings.cs
|
|
64
|
+
public sealed class ApiTestSettings
|
|
65
|
+
{
|
|
66
|
+
public required string BaseUrl { get; init; }
|
|
67
|
+
public int TimeoutSeconds { get; init; } = 30;
|
|
68
|
+
public required AuthSettings Auth { get; init; }
|
|
69
|
+
}
|
|
70
|
+
public sealed class AuthSettings
|
|
71
|
+
{
|
|
72
|
+
public string Type { get; init; } = "Bearer";
|
|
73
|
+
public string TokenEndpoint { get; init; } = "/api/auth/token";
|
|
74
|
+
public string Username { get; init; } = "";
|
|
75
|
+
public string Password { get; init; } = "";
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```csharp
|
|
80
|
+
// TestBase.cs
|
|
81
|
+
public abstract class TestBase : IAsyncLifetime
|
|
82
|
+
{
|
|
83
|
+
protected HttpClient Client { get; private set; } = null!;
|
|
84
|
+
protected ApiTestSettings Settings { get; private set; } = null!;
|
|
85
|
+
|
|
86
|
+
public async Task InitializeAsync()
|
|
87
|
+
{
|
|
88
|
+
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Test";
|
|
89
|
+
Settings = new ConfigurationBuilder()
|
|
90
|
+
.AddJsonFile("appsettings.json")
|
|
91
|
+
.AddJsonFile($"appsettings.{env}.json", optional: true)
|
|
92
|
+
.AddEnvironmentVariables("APITEST_")
|
|
93
|
+
.Build()
|
|
94
|
+
.GetRequiredSection("ApiTest").Get<ApiTestSettings>()!;
|
|
95
|
+
|
|
96
|
+
Client = new HttpClient { BaseAddress = new Uri(Settings.BaseUrl),
|
|
97
|
+
Timeout = TimeSpan.FromSeconds(Settings.TimeoutSeconds) };
|
|
98
|
+
|
|
99
|
+
if (!string.IsNullOrEmpty(Settings.Auth.Username))
|
|
100
|
+
await AuthenticateAsync();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public Task DisposeAsync() { Client.Dispose(); return Task.CompletedTask; }
|
|
104
|
+
|
|
105
|
+
protected async Task AuthenticateAsync(string? username = null, string? password = null)
|
|
106
|
+
{
|
|
107
|
+
var res = await Client.PostAsJsonAsync(Settings.Auth.TokenEndpoint,
|
|
108
|
+
new { username = username ?? Settings.Auth.Username, password = password ?? Settings.Auth.Password });
|
|
109
|
+
res.EnsureSuccessStatusCode();
|
|
110
|
+
var token = (await res.Content.ReadFromJsonAsync<TokenResponse>())!.AccessToken;
|
|
111
|
+
Client.DefaultRequestHeaders.Authorization =
|
|
112
|
+
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private sealed record TokenResponse(string AccessToken);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Test Class Header (required)
|
|
120
|
+
|
|
121
|
+
```csharp
|
|
122
|
+
// ============================================================
|
|
123
|
+
// {Resource} API Tests — v{N}
|
|
124
|
+
// Spec: {spec-file} | Generated: {YYYY-MM-DD} | Story: {ID}
|
|
125
|
+
// APPEND-ONLY: don't modify existing methods.
|
|
126
|
+
// ============================================================
|
|
127
|
+
namespace ApiTests.V{N};
|
|
128
|
+
public sealed class {Resource}ApiTests : TestBase
|
|
129
|
+
{
|
|
130
|
+
// Inline DTOs — don't import from production code
|
|
131
|
+
private sealed record {Resource}Dto(Guid Id, string Name);
|
|
132
|
+
private sealed record ListResponse<T>(IReadOnlyList<T> Data, int Total);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Test Naming
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
{HttpMethod}_{Resource}_Returns{Status}_When{Condition}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Example: `GetById_User_Returns200_WhenExists`, `Create_Order_Returns422_WhenEmailInvalid`
|
|
143
|
+
|
|
144
|
+
AC test: comment `// AC: {text}` right below XML doc.
|
|
145
|
+
|
|
146
|
+
## XML Doc (required on each test)
|
|
147
|
+
|
|
148
|
+
```csharp
|
|
149
|
+
/// <summary>Verify {METHOD} {path} → {status} when {condition}. Spec: {ref}</summary>
|
|
150
|
+
[Fact]
|
|
151
|
+
public async Task ...
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Coverage Matrix
|
|
155
|
+
|
|
156
|
+
| Condition | Status | When |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| Valid, authenticated | 2xx | Always |
|
|
159
|
+
| No token | 401 | Endpoint requires auth |
|
|
160
|
+
| Insufficient permission | 403 | RBAC / ownership |
|
|
161
|
+
| `{id}` doesn't exist | 404 | Has path param |
|
|
162
|
+
| Required field missing/invalid | 400/422 | Has request body |
|
|
163
|
+
| Business rule (from AC) | 4xx | Story has corresponding AC |
|
|
164
|
+
|
|
165
|
+
## CI/CD Env Vars
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
ASPNETCORE_ENVIRONMENT=Test
|
|
169
|
+
APITEST__AUTH__USERNAME=... # double __ for nested key
|
|
170
|
+
APITEST__AUTH__PASSWORD=...
|
|
171
|
+
```
|
|
@@ -1,54 +1,54 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ado-integration
|
|
3
3
|
description: |
|
|
4
|
-
Azure DevOps integration. Auto-invoke
|
|
4
|
+
Azure DevOps integration. Auto-invoke when user mentions:
|
|
5
5
|
sync ADO, push to board, pull work item, update status on ADO,
|
|
6
|
-
create work item on ADO,
|
|
6
|
+
create work item on ADO, or any Azure DevOps related operation.
|
|
7
7
|
allowed-tools: Read, Write, Edit, Bash, Grep
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# ADO Integration Skill
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
ADO sync
|
|
12
|
+
Enables bidirectional sync between .md files in repo and work items on Azure DevOps.
|
|
13
|
+
ADO sync is **intentional operation** — not automatic after each file edit.
|
|
14
14
|
|
|
15
15
|
## When to Use
|
|
16
16
|
|
|
17
|
-
- User
|
|
18
|
-
- User
|
|
19
|
-
-
|
|
17
|
+
- User requests sync, push, pull work item to/from ADO
|
|
18
|
+
- User runs `/ado-create`, `/ado-update`, `/ado-status`, `/ado-get`, `/ado-delete`
|
|
19
|
+
- DO NOT invoke when: user only edits .md file normally without mentioning ADO
|
|
20
20
|
|
|
21
21
|
## Always / Ask / Never
|
|
22
22
|
|
|
23
|
-
| |
|
|
23
|
+
| | Action |
|
|
24
24
|
|---|---|
|
|
25
|
-
| **Always** |
|
|
26
|
-
| **Always** |
|
|
27
|
-
| **Always** |
|
|
28
|
-
| **Ask** |
|
|
29
|
-
| **Ask** |
|
|
30
|
-
| **Ask** |
|
|
31
|
-
| **Never** | Auto-sync
|
|
32
|
-
| **Never** |
|
|
33
|
-
| **Never** |
|
|
34
|
-
|
|
35
|
-
##
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
25
|
+
| **Always** | Read `tas.yaml` and check `ado.enabled` before any operation |
|
|
26
|
+
| **Always** | Display ADO ID and URL after each successful create/update |
|
|
27
|
+
| **Always** | Update frontmatter `ado_id`, `ado_state`, `last_ado_sync` in .md file after sync |
|
|
28
|
+
| **Ask** | When syncing multiple items at once — confirm list before running |
|
|
29
|
+
| **Ask** | When detecting conflict between .md file and ADO item (which is source of truth?) |
|
|
30
|
+
| **Ask** | When deleting work item — this is irreversible operation |
|
|
31
|
+
| **Never** | Auto-sync whenever .md file is edited (too aggressive, creates noise) |
|
|
32
|
+
| **Never** | Delete ADO item without clear user confirmation |
|
|
33
|
+
| **Never** | Create duplicate work item if `ado_id` already exists in frontmatter |
|
|
34
|
+
|
|
35
|
+
## First Step — Check ADO Enabled
|
|
36
|
+
|
|
37
|
+
Before performing any operation, read `tas.yaml` at root and check `ado.enabled`:
|
|
38
|
+
- If `ado.enabled: false` or field doesn't exist: notify "ADO integration is disabled in tas.yaml (`ado.enabled: false`). Enable if project uses ADO." then stop.
|
|
39
|
+
- If `ado.enabled: true`: continue normally.
|
|
40
40
|
|
|
41
41
|
## Prerequisites
|
|
42
42
|
|
|
43
|
-
- Azure CLI +
|
|
44
|
-
- Python 3.8+
|
|
45
|
-
- PAT
|
|
43
|
+
- Azure CLI + azure-devops extension: `az extension add --name azure-devops --upgrade`
|
|
44
|
+
- Python 3.8+ with pyyaml: `pip install pyyaml`
|
|
45
|
+
- PAT in .env file: `AzureDevops_Personal_AccessToken=your-pat-here`
|
|
46
46
|
|
|
47
47
|
## Commands
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
All ADO commands run via: `python .tas/tools/tas-ado.py <command> [args]`
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
Or use slash commands:
|
|
52
52
|
- `/ado-create <type> <temp-id> [--parent-id <id>]`
|
|
53
53
|
- `/ado-get <ado-id>`
|
|
54
54
|
- `/ado-update <type> <ado-id> [--assign <name>] [--status <state>]`
|
|
@@ -57,19 +57,19 @@ Hoặc dùng slash commands:
|
|
|
57
57
|
|
|
58
58
|
## File Convention
|
|
59
59
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
60
|
+
- Filename: `{type}-{ado_id}-{slug-title}.md`
|
|
61
|
+
- Each file has YAML frontmatter: `ado_id`, `ado_type`, `ado_state`, `last_ado_sync`
|
|
62
|
+
- .md file is single source of truth, sync to ADO when needed
|
|
63
63
|
|
|
64
64
|
## Red Flags
|
|
65
65
|
|
|
66
|
-
- File
|
|
67
|
-
- PAT
|
|
68
|
-
- `ado.enabled: true`
|
|
66
|
+
- File has `ado_id` but state in file differs from ADO → confirm with user before overwriting
|
|
67
|
+
- PAT expired → guide to rotate, don't log token to stdout
|
|
68
|
+
- `ado.enabled: true` but project hasn't set up Azure CLI → check prerequisites first
|
|
69
69
|
|
|
70
70
|
## Anti-Rationalization
|
|
71
71
|
|
|
72
72
|
| Rationalization | Counter |
|
|
73
73
|
|---|---|
|
|
74
|
-
| "Auto-sync
|
|
75
|
-
| "Delete
|
|
74
|
+
| "Auto-sync is more convenient, no need to remember" | Hook auto-sync causes unintended pushes when editing draft — sync must be intentional |
|
|
75
|
+
| "Delete is OK, I know what I'm doing" | ADO delete has no undo — always confirm, even if user seems confident |
|
|
@@ -1,65 +1,65 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tas-conventions
|
|
3
3
|
description: |
|
|
4
|
-
Coding conventions
|
|
5
|
-
Auto-invoke
|
|
6
|
-
|
|
4
|
+
Coding conventions and naming rules for Torus projects.
|
|
5
|
+
Auto-invoke when writing new code, reviewing code, refactoring,
|
|
6
|
+
or when user asks about coding standards.
|
|
7
7
|
allowed-tools: Read, Grep, Glob
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# TAS Conventions
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
When generating or reviewing code, MUST follow conventions defined in project's `CLAUDE.md`.
|
|
13
13
|
|
|
14
14
|
## When to Use
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
16
|
+
- Before generating new code (check conventions)
|
|
17
|
+
- When reviewing user's code (verify compliance)
|
|
18
|
+
- When user asks "what to name?", "what format?"
|
|
19
|
+
- DO NOT invoke when: reading files only, not related to code output
|
|
20
20
|
|
|
21
21
|
## Always / Ask / Never
|
|
22
22
|
|
|
23
|
-
| |
|
|
23
|
+
| | Action |
|
|
24
24
|
|---|---|
|
|
25
|
-
| **Always** |
|
|
26
|
-
| **Always** |
|
|
27
|
-
| **Ask** |
|
|
28
|
-
| **Never** | Hardcode convention (naming, format)
|
|
29
|
-
| **Never** |
|
|
25
|
+
| **Always** | Read `CLAUDE.md` before applying convention |
|
|
26
|
+
| **Always** | Point to specific file:line when detecting violation |
|
|
27
|
+
| **Ask** | When convention in CLAUDE.md is vague or has conflict |
|
|
28
|
+
| **Never** | Hardcode convention (naming, format) without reading CLAUDE.md first |
|
|
29
|
+
| **Never** | Apply convention from other project to current project |
|
|
30
30
|
|
|
31
31
|
## Checklist
|
|
32
32
|
|
|
33
|
-
-
|
|
34
|
-
- Enforce
|
|
35
|
-
-
|
|
33
|
+
- Read `CLAUDE.md` to get naming conventions, branching, commit format, stack rules
|
|
34
|
+
- Enforce those conventions in code output
|
|
35
|
+
- If code violates conventions, point specifically: file:line + violated convention + how to fix
|
|
36
36
|
|
|
37
|
-
## Common Conventions (Default — override
|
|
37
|
+
## Common Conventions (Default — override by CLAUDE.md)
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
These default conventions only apply when `CLAUDE.md` doesn't define otherwise:
|
|
40
40
|
|
|
41
41
|
- Variables/functions: `camelCase`
|
|
42
42
|
- Types/Interfaces/Components: `PascalCase`
|
|
43
43
|
- Constants: `UPPER_SNAKE_CASE`
|
|
44
44
|
- Boolean vars: prefix `is`, `has`, `should`, `can`
|
|
45
|
-
- File naming: kebab-case
|
|
45
|
+
- File naming: kebab-case for files, PascalCase for components
|
|
46
46
|
- Commit format: `<type>: <description>` (feat, fix, refactor, docs, test, chore)
|
|
47
47
|
|
|
48
48
|
## Red Flags
|
|
49
49
|
|
|
50
|
-
- Magic numbers
|
|
51
|
-
- Deep nesting >4 levels →
|
|
52
|
-
- Function >50 lines → extract
|
|
53
|
-
- File >800 lines → extract
|
|
54
|
-
- Variable
|
|
55
|
-
- `any` type
|
|
56
|
-
-
|
|
50
|
+
- Magic numbers in code (e.g., `if (count > 50)`) → must use named constant
|
|
51
|
+
- Deep nesting >4 levels → use early return or extract method
|
|
52
|
+
- Function >50 lines → extract to smaller functions
|
|
53
|
+
- File >800 lines → extract to modules
|
|
54
|
+
- Variable with 1-2 char name (`x`, `t`, `d`) in production code → use descriptive name
|
|
55
|
+
- `any` type in TypeScript → use specific type or generic
|
|
56
|
+
- Large commented-out code block → delete if not needed, use git history instead
|
|
57
57
|
|
|
58
58
|
## Verification
|
|
59
59
|
|
|
60
|
-
- [ ] CLAUDE.md
|
|
61
|
-
- [ ] Naming
|
|
62
|
-
- [ ]
|
|
63
|
-
- [ ]
|
|
60
|
+
- [ ] CLAUDE.md has been read before reviewing/generating code
|
|
61
|
+
- [ ] Naming follows conventions in CLAUDE.md
|
|
62
|
+
- [ ] No magic numbers
|
|
63
|
+
- [ ] No deep nesting (>4 levels)
|
|
64
64
|
- [ ] Functions < 50 lines, files < 800 lines
|
|
65
|
-
- [ ] Commit message
|
|
65
|
+
- [ ] Commit message follows defined format
|