opencode-plugin-team-agreements 0.2.0 → 0.2.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/CHANGELOG.md +7 -0
- package/README.md +93 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +389 -12
- package/dist/index.test.js.map +1 -1
- package/dist/utils.d.ts +93 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1175 -134
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.1](https://github.com/jwilger/opencode-plugin-team-agreements/compare/opencode-plugin-team-agreements-v0.2.0...opencode-plugin-team-agreements-v0.2.1) (2026-01-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Add comprehensive team agreements with project analysis and split document approach ([#16](https://github.com/jwilger/opencode-plugin-team-agreements/issues/16)) ([084edaa](https://github.com/jwilger/opencode-plugin-team-agreements/commit/084edaad210c23d6f25eaa64b09e730ba474d970))
|
|
9
|
+
|
|
3
10
|
## [0.2.0](https://github.com/jwilger/opencode-plugin-team-agreements/compare/opencode-plugin-team-agreements-v0.1.4...opencode-plugin-team-agreements-v0.2.0) (2026-01-23)
|
|
4
11
|
|
|
5
12
|
|
package/README.md
CHANGED
|
@@ -4,18 +4,57 @@ An [OpenCode](https://opencode.ai) plugin that helps teams of humans and LLM age
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
- **Comprehensive interview** - Covers 7 categories with ~22 topics for thorough team alignment
|
|
8
|
+
- **Smart project analysis** - Detects languages, frameworks, CI, testing, AI tools to tailor questions
|
|
9
|
+
- **Split document approach**:
|
|
10
|
+
- `docs/TEAM_AGREEMENTS.md` - Full reference documentation for humans
|
|
11
|
+
- `AGENTS.md` - Concise rules that LLMs need in context constantly
|
|
12
|
+
- **Interactive facilitation** - Guides teams through one question at a time, allowing skips and pauses
|
|
13
|
+
- **Enforcement setup** - Detects existing tooling and offers to set up automatic enforcement
|
|
14
|
+
- **Context injection** - Automatically injects LLM-relevant rules after compaction
|
|
15
|
+
- **Topic suggestions** - Suggest new standard topics via GitHub issues
|
|
16
|
+
|
|
17
|
+
## Topics Covered
|
|
18
|
+
|
|
19
|
+
### 1. Code & Quality
|
|
20
|
+
- Programming Languages & Tech Stack
|
|
21
|
+
- Code Quality Standards
|
|
22
|
+
- Code Review Process
|
|
23
|
+
- Testing Requirements
|
|
24
|
+
|
|
25
|
+
### 2. Integration & Delivery
|
|
26
|
+
- Version Control & Branching
|
|
27
|
+
- Continuous Integration
|
|
28
|
+
- Deployment & Release
|
|
29
|
+
- Database & Schema Changes
|
|
30
|
+
|
|
31
|
+
### 3. Operations & QA
|
|
32
|
+
- Security Practices
|
|
33
|
+
- Monitoring & Observability
|
|
34
|
+
- Performance Standards
|
|
35
|
+
- Accessibility & Internationalization
|
|
36
|
+
|
|
37
|
+
### 4. Documentation & Knowledge
|
|
38
|
+
- Documentation Standards
|
|
39
|
+
- Architecture Decision Records (ADRs)
|
|
40
|
+
- Dependency Management
|
|
41
|
+
|
|
42
|
+
### 5. AI/LLM Collaboration
|
|
43
|
+
- AI Tools & Policies
|
|
44
|
+
- Autonomy Boundaries
|
|
45
|
+
- AI Code Generation Standards
|
|
46
|
+
- Context & Session Management
|
|
47
|
+
- Human Oversight & Escalation
|
|
48
|
+
- Learning & Improvement
|
|
49
|
+
|
|
50
|
+
### 6. Team Process
|
|
51
|
+
- Development Methodology
|
|
52
|
+
- Planning & Work Breakdown
|
|
53
|
+
- Communication & Collaboration
|
|
54
|
+
|
|
55
|
+
### 7. Governance
|
|
56
|
+
- Amendment Process
|
|
57
|
+
- Open-Ended Topics
|
|
19
58
|
|
|
20
59
|
## Installation
|
|
21
60
|
|
|
@@ -36,26 +75,56 @@ Run the `/team-agreements` command in OpenCode:
|
|
|
36
75
|
/team-agreements
|
|
37
76
|
```
|
|
38
77
|
|
|
39
|
-
The plugin will guide you through establishing agreements
|
|
78
|
+
The plugin will first analyze your project and then guide you through establishing agreements. You can also provide context:
|
|
40
79
|
|
|
41
80
|
```
|
|
42
|
-
/team-agreements I want to update our
|
|
81
|
+
/team-agreements I want to update our AI collaboration policies
|
|
43
82
|
```
|
|
44
83
|
|
|
45
84
|
### Options when agreements exist
|
|
46
85
|
|
|
47
86
|
If `docs/TEAM_AGREEMENTS.md` already exists, you'll be presented with options to:
|
|
48
87
|
- **Review** - Display current agreements
|
|
49
|
-
- **Amend** - Modify
|
|
50
|
-
- **
|
|
88
|
+
- **Amend** - Modify specific sections
|
|
89
|
+
- **Regenerate AGENTS.md** - Re-extract LLM-relevant rules
|
|
90
|
+
|
|
91
|
+
### The split document approach
|
|
92
|
+
|
|
93
|
+
This plugin creates two files with different purposes:
|
|
94
|
+
|
|
95
|
+
**`docs/TEAM_AGREEMENTS.md`** - Comprehensive documentation including:
|
|
96
|
+
- Complete code standards with examples
|
|
97
|
+
- Full deployment and release procedures
|
|
98
|
+
- On-call and incident processes
|
|
99
|
+
- Meeting cadences and team ceremonies
|
|
100
|
+
- Everything humans need for reference
|
|
101
|
+
|
|
102
|
+
**`AGENTS.md`** - Only rules that affect day-to-day coding:
|
|
103
|
+
- Code quality standards and patterns
|
|
104
|
+
- Testing requirements
|
|
105
|
+
- Commit message format
|
|
106
|
+
- AI autonomy boundaries
|
|
107
|
+
- Escalation triggers
|
|
108
|
+
|
|
109
|
+
This split ensures LLM context isn't bloated with procedures they don't need constantly (deployment steps, post-mortem templates, etc.) while still giving humans complete documentation.
|
|
51
110
|
|
|
52
111
|
## How it works
|
|
53
112
|
|
|
54
|
-
1. **
|
|
55
|
-
2. **
|
|
56
|
-
3. **
|
|
57
|
-
4. **
|
|
58
|
-
5. **
|
|
113
|
+
1. **Project analysis** - Detects your tech stack, frameworks, CI/CD, and AI tools
|
|
114
|
+
2. **Tailored interview** - Highlights relevant topics and suggests skippable ones
|
|
115
|
+
3. **Interactive conversation** - One question at a time with trade-off discussions
|
|
116
|
+
4. **Document generation** - Creates both `docs/TEAM_AGREEMENTS.md` and `AGENTS.md`
|
|
117
|
+
5. **Enforcement detection** - Identifies existing tooling (ESLint, Prettier, Husky, etc.)
|
|
118
|
+
6. **Enforcement setup** - Offers to configure automatic enforcement where possible
|
|
119
|
+
7. **Compaction handling** - Re-injects AGENTS.md after context compaction
|
|
120
|
+
|
|
121
|
+
## Tools provided
|
|
122
|
+
|
|
123
|
+
The plugin registers these tools for LLM use:
|
|
124
|
+
|
|
125
|
+
- `analyze_project` - Detects languages, frameworks, CI, testing, AI tools, and project characteristics
|
|
126
|
+
- `detect_enforcement_mechanisms` - Finds existing linters, formatters, and CI workflows
|
|
127
|
+
- `suggest_team_agreement_topic` - Files GitHub issues for new topic suggestions
|
|
59
128
|
|
|
60
129
|
## Suggesting new topics
|
|
61
130
|
|
|
@@ -78,6 +147,9 @@ npm install
|
|
|
78
147
|
# Build
|
|
79
148
|
npm run build
|
|
80
149
|
|
|
150
|
+
# Run tests
|
|
151
|
+
npm test
|
|
152
|
+
|
|
81
153
|
# Watch mode for development
|
|
82
154
|
npm run dev
|
|
83
155
|
```
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,qBAAqB,CAAA;AAevD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAwHlC,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @packageDocumentation
|
|
12
12
|
*/
|
|
13
13
|
import { tool } from "@opencode-ai/plugin";
|
|
14
|
-
import { COMMAND_TEMPLATE, PLUGIN_REPO, isGhAvailable, loadTeamAgreements, buildTopicIssueBody, detectEnforcementMechanisms, formatEnforcementResults, execAsync, } from "./utils.js";
|
|
14
|
+
import { COMMAND_TEMPLATE, PLUGIN_REPO, isGhAvailable, loadTeamAgreements, buildTopicIssueBody, detectEnforcementMechanisms, formatEnforcementResults, analyzeProject, formatProjectAnalysis, execAsync, } from "./utils.js";
|
|
15
15
|
/**
|
|
16
16
|
* TeamAgreementsPlugin - Helps teams establish and maintain shared agreements
|
|
17
17
|
* for human-LLM collaboration on a codebase.
|
|
@@ -42,6 +42,20 @@ export const TeamAgreementsPlugin = async (ctx) => {
|
|
|
42
42
|
* Tools for team agreements management
|
|
43
43
|
*/
|
|
44
44
|
tool: {
|
|
45
|
+
/**
|
|
46
|
+
* Analyze the project to detect languages, frameworks, tools, etc.
|
|
47
|
+
*/
|
|
48
|
+
analyze_project: tool({
|
|
49
|
+
description: "Analyze the project to detect languages, frameworks, CI/CD, testing, AI tools, " +
|
|
50
|
+
"database, monitoring, and other characteristics. Use this at the start of the " +
|
|
51
|
+
"team agreements interview to tailor questions to the specific project. Returns " +
|
|
52
|
+
"recommendations for which categories to prioritize and which topics may be skippable.",
|
|
53
|
+
args: {},
|
|
54
|
+
async execute() {
|
|
55
|
+
const analysis = await analyzeProject(directory);
|
|
56
|
+
return formatProjectAnalysis(analysis);
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
45
59
|
/**
|
|
46
60
|
* Detect existing enforcement mechanisms in the project
|
|
47
61
|
*/
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.test.js
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdir, writeFile, rm } from "fs/promises";
|
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { tmpdir } from "os";
|
|
5
5
|
import { TeamAgreementsPlugin } from "./index.js";
|
|
6
|
-
import { fileExists, loadTeamAgreements, formatQuestionsAsMarkdown, buildTopicIssueBody, detectEnforcementMechanisms, formatEnforcementResults, COMMAND_TEMPLATE, PLUGIN_REPO, } from "./utils.js";
|
|
6
|
+
import { fileExists, loadTeamAgreements, formatQuestionsAsMarkdown, buildTopicIssueBody, detectEnforcementMechanisms, formatEnforcementResults, analyzeProject, formatProjectAnalysis, COMMAND_TEMPLATE, PLUGIN_REPO, } from "./utils.js";
|
|
7
7
|
describe("fileExists", () => {
|
|
8
8
|
let testDir;
|
|
9
9
|
beforeEach(async () => {
|
|
@@ -119,37 +119,65 @@ describe("COMMAND_TEMPLATE", () => {
|
|
|
119
119
|
expect(COMMAND_TEMPLATE).toContain("$ARGUMENTS");
|
|
120
120
|
expect(COMMAND_TEMPLATE).toContain("## Overview");
|
|
121
121
|
expect(COMMAND_TEMPLATE).toContain("AGENTS.md");
|
|
122
|
-
expect(COMMAND_TEMPLATE).toContain("## Step 1: Analyze Existing Files");
|
|
122
|
+
expect(COMMAND_TEMPLATE).toContain("## Step 1: Analyze Project & Existing Files");
|
|
123
123
|
expect(COMMAND_TEMPLATE).toContain("## Step 2: Determine the Scenario");
|
|
124
|
-
expect(COMMAND_TEMPLATE).toContain("## Step 3:
|
|
124
|
+
expect(COMMAND_TEMPLATE).toContain("## Step 3: Present Categories Based on Analysis");
|
|
125
|
+
expect(COMMAND_TEMPLATE).toContain("## Step 4: Gather Team Agreements");
|
|
126
|
+
// Categories
|
|
127
|
+
expect(COMMAND_TEMPLATE).toContain("CATEGORY 1: CODE & QUALITY");
|
|
128
|
+
expect(COMMAND_TEMPLATE).toContain("CATEGORY 2: INTEGRATION & DELIVERY");
|
|
129
|
+
expect(COMMAND_TEMPLATE).toContain("CATEGORY 3: OPERATIONS & QA");
|
|
130
|
+
expect(COMMAND_TEMPLATE).toContain("CATEGORY 4: DOCUMENTATION & KNOWLEDGE");
|
|
131
|
+
expect(COMMAND_TEMPLATE).toContain("CATEGORY 5: AI/LLM COLLABORATION");
|
|
132
|
+
expect(COMMAND_TEMPLATE).toContain("CATEGORY 6: TEAM PROCESS");
|
|
133
|
+
expect(COMMAND_TEMPLATE).toContain("CATEGORY 7: GOVERNANCE");
|
|
134
|
+
// Topics
|
|
125
135
|
expect(COMMAND_TEMPLATE).toContain("Programming Languages");
|
|
126
136
|
expect(COMMAND_TEMPLATE).toContain("Code Quality Standards");
|
|
127
|
-
expect(COMMAND_TEMPLATE).toContain("
|
|
128
|
-
expect(COMMAND_TEMPLATE).toContain("Integration Workflow");
|
|
137
|
+
expect(COMMAND_TEMPLATE).toContain("Code Review Process");
|
|
129
138
|
expect(COMMAND_TEMPLATE).toContain("Testing Requirements");
|
|
139
|
+
expect(COMMAND_TEMPLATE).toContain("Version Control & Branching");
|
|
140
|
+
expect(COMMAND_TEMPLATE).toContain("Security Practices");
|
|
141
|
+
expect(COMMAND_TEMPLATE).toContain("AI Tools & Policies");
|
|
142
|
+
expect(COMMAND_TEMPLATE).toContain("Autonomy Boundaries");
|
|
130
143
|
expect(COMMAND_TEMPLATE).toContain("Amendment Process");
|
|
131
144
|
});
|
|
132
145
|
it("mentions the suggestion tool", () => {
|
|
133
146
|
expect(COMMAND_TEMPLATE).toContain("suggest_team_agreement_topic");
|
|
134
147
|
});
|
|
148
|
+
it("mentions the analyze_project tool", () => {
|
|
149
|
+
expect(COMMAND_TEMPLATE).toContain("analyze_project");
|
|
150
|
+
});
|
|
135
151
|
it("contains enforcement section", () => {
|
|
136
152
|
expect(COMMAND_TEMPLATE).toContain("detect_enforcement_mechanisms");
|
|
137
153
|
expect(COMMAND_TEMPLATE).toContain("Enforcement Mechanisms");
|
|
138
|
-
expect(COMMAND_TEMPLATE).toContain("
|
|
139
|
-
expect(COMMAND_TEMPLATE).toContain("CI
|
|
140
|
-
expect(COMMAND_TEMPLATE).toContain("
|
|
141
|
-
expect(COMMAND_TEMPLATE).toContain("Linting Rules");
|
|
154
|
+
expect(COMMAND_TEMPLATE).toContain("commitlint");
|
|
155
|
+
expect(COMMAND_TEMPLATE).toContain("CI workflows");
|
|
156
|
+
expect(COMMAND_TEMPLATE).toContain("branch protection");
|
|
142
157
|
});
|
|
143
|
-
it("contains
|
|
144
|
-
expect(COMMAND_TEMPLATE).toContain("## Step
|
|
158
|
+
it("contains merging guidelines section", () => {
|
|
159
|
+
expect(COMMAND_TEMPLATE).toContain("## Step 5: Generate Documents");
|
|
160
|
+
expect(COMMAND_TEMPLATE).toContain("### Merging Guidelines");
|
|
145
161
|
expect(COMMAND_TEMPLATE).toContain("Preserve existing structure");
|
|
146
162
|
expect(COMMAND_TEMPLATE).toContain("Avoid duplication");
|
|
147
163
|
});
|
|
148
164
|
it("contains CLAUDE.md coordination section", () => {
|
|
149
|
-
expect(COMMAND_TEMPLATE).toContain("## Step
|
|
165
|
+
expect(COMMAND_TEMPLATE).toContain("## Step 6: Handle CLAUDE.md Coordination");
|
|
150
166
|
expect(COMMAND_TEMPLATE).toContain("@AGENTS.md");
|
|
151
167
|
expect(COMMAND_TEMPLATE).toContain("Claude-specific");
|
|
152
168
|
});
|
|
169
|
+
it("contains AI/LLM collaboration topics", () => {
|
|
170
|
+
expect(COMMAND_TEMPLATE).toContain("AI Tools & Policies");
|
|
171
|
+
expect(COMMAND_TEMPLATE).toContain("Autonomy Boundaries");
|
|
172
|
+
expect(COMMAND_TEMPLATE).toContain("AI Code Generation Standards");
|
|
173
|
+
expect(COMMAND_TEMPLATE).toContain("Context & Session Management");
|
|
174
|
+
expect(COMMAND_TEMPLATE).toContain("Human Oversight & Escalation");
|
|
175
|
+
expect(COMMAND_TEMPLATE).toContain("Learning & Improvement");
|
|
176
|
+
});
|
|
177
|
+
it("contains progress tracking guidance", () => {
|
|
178
|
+
expect(COMMAND_TEMPLATE).toContain("Category X of 7");
|
|
179
|
+
expect(COMMAND_TEMPLATE).toContain("25-40 minutes");
|
|
180
|
+
});
|
|
153
181
|
});
|
|
154
182
|
describe("detectEnforcementMechanisms", () => {
|
|
155
183
|
let testDir;
|
|
@@ -422,5 +450,354 @@ describe("TeamAgreementsPlugin", () => {
|
|
|
422
450
|
expect(result).toContain("Detected Enforcement Mechanisms");
|
|
423
451
|
expect(result).toContain("husky");
|
|
424
452
|
});
|
|
453
|
+
it("registers the analyze_project tool", async () => {
|
|
454
|
+
const mockCtx = {
|
|
455
|
+
directory: testDir,
|
|
456
|
+
client: {},
|
|
457
|
+
project: {},
|
|
458
|
+
worktree: testDir,
|
|
459
|
+
serverUrl: new URL("http://localhost"),
|
|
460
|
+
$: {},
|
|
461
|
+
};
|
|
462
|
+
const hooks = await TeamAgreementsPlugin(mockCtx);
|
|
463
|
+
expect(hooks.tool).toBeDefined();
|
|
464
|
+
expect(hooks.tool.analyze_project).toBeDefined();
|
|
465
|
+
expect(hooks.tool.analyze_project.description).toContain("Analyze the project");
|
|
466
|
+
});
|
|
467
|
+
it("analyze_project tool returns formatted results", async () => {
|
|
468
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
469
|
+
dependencies: { react: "^18.0.0", express: "^4.0.0" },
|
|
470
|
+
devDependencies: { typescript: "^5.0.0", vitest: "^1.0.0" }
|
|
471
|
+
}));
|
|
472
|
+
const mockCtx = {
|
|
473
|
+
directory: testDir,
|
|
474
|
+
client: {},
|
|
475
|
+
project: {},
|
|
476
|
+
worktree: testDir,
|
|
477
|
+
serverUrl: new URL("http://localhost"),
|
|
478
|
+
$: {},
|
|
479
|
+
};
|
|
480
|
+
const mockToolContext = {
|
|
481
|
+
sessionID: "test-session",
|
|
482
|
+
messageID: "test-message",
|
|
483
|
+
agent: "test-agent",
|
|
484
|
+
abort: new AbortController().signal,
|
|
485
|
+
metadata: () => { },
|
|
486
|
+
ask: async () => { },
|
|
487
|
+
};
|
|
488
|
+
const hooks = await TeamAgreementsPlugin(mockCtx);
|
|
489
|
+
const result = await hooks.tool.analyze_project.execute({}, mockToolContext);
|
|
490
|
+
expect(result).toContain("Project Analysis Results");
|
|
491
|
+
expect(result).toContain("Languages");
|
|
492
|
+
expect(result).toContain("Typescript");
|
|
493
|
+
expect(result).toContain("Frameworks");
|
|
494
|
+
expect(result).toContain("React");
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
describe("analyzeProject", () => {
|
|
498
|
+
let testDir;
|
|
499
|
+
beforeEach(async () => {
|
|
500
|
+
testDir = join(tmpdir(), "analyze-project-test-" + Date.now() + "-" + Math.random().toString(36).slice(2));
|
|
501
|
+
await mkdir(testDir, { recursive: true });
|
|
502
|
+
});
|
|
503
|
+
afterEach(async () => {
|
|
504
|
+
await rm(testDir, { recursive: true, force: true });
|
|
505
|
+
});
|
|
506
|
+
it("returns default analysis for empty project", async () => {
|
|
507
|
+
const result = await analyzeProject(testDir);
|
|
508
|
+
expect(result.languages.typescript).toBe(false);
|
|
509
|
+
expect(result.languages.javascript).toBe(false);
|
|
510
|
+
expect(result.frameworks.react).toBe(false);
|
|
511
|
+
expect(result.ci.githubActions).toBe(false);
|
|
512
|
+
expect(result.aiTools.agentsMd).toBe(false);
|
|
513
|
+
expect(result.recommendations.suggestedCategories).toContain("Code & Quality");
|
|
514
|
+
});
|
|
515
|
+
it("detects TypeScript from package.json", async () => {
|
|
516
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
517
|
+
devDependencies: { typescript: "^5.0.0" }
|
|
518
|
+
}));
|
|
519
|
+
const result = await analyzeProject(testDir);
|
|
520
|
+
expect(result.languages.typescript).toBe(true);
|
|
521
|
+
expect(result.languages.javascript).toBe(true);
|
|
522
|
+
});
|
|
523
|
+
it("detects TypeScript from tsconfig.json", async () => {
|
|
524
|
+
await writeFile(join(testDir, "tsconfig.json"), JSON.stringify({
|
|
525
|
+
compilerOptions: { target: "ES2022" }
|
|
526
|
+
}));
|
|
527
|
+
const result = await analyzeProject(testDir);
|
|
528
|
+
expect(result.languages.typescript).toBe(true);
|
|
529
|
+
});
|
|
530
|
+
it("detects Python from pyproject.toml", async () => {
|
|
531
|
+
await writeFile(join(testDir, "pyproject.toml"), "[project]\nname = 'test'");
|
|
532
|
+
const result = await analyzeProject(testDir);
|
|
533
|
+
expect(result.languages.python).toBe(true);
|
|
534
|
+
});
|
|
535
|
+
it("detects Rust from Cargo.toml", async () => {
|
|
536
|
+
await writeFile(join(testDir, "Cargo.toml"), "[package]\nname = 'test'");
|
|
537
|
+
const result = await analyzeProject(testDir);
|
|
538
|
+
expect(result.languages.rust).toBe(true);
|
|
539
|
+
});
|
|
540
|
+
it("detects Go from go.mod", async () => {
|
|
541
|
+
await writeFile(join(testDir, "go.mod"), "module example.com/test");
|
|
542
|
+
const result = await analyzeProject(testDir);
|
|
543
|
+
expect(result.languages.go).toBe(true);
|
|
544
|
+
});
|
|
545
|
+
it("detects React from package.json", async () => {
|
|
546
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
547
|
+
dependencies: { react: "^18.0.0" }
|
|
548
|
+
}));
|
|
549
|
+
const result = await analyzeProject(testDir);
|
|
550
|
+
expect(result.frameworks.react).toBe(true);
|
|
551
|
+
expect(result.characteristics.hasFrontend).toBe(true);
|
|
552
|
+
});
|
|
553
|
+
it("detects Express from package.json", async () => {
|
|
554
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
555
|
+
dependencies: { express: "^4.0.0" }
|
|
556
|
+
}));
|
|
557
|
+
const result = await analyzeProject(testDir);
|
|
558
|
+
expect(result.frameworks.express).toBe(true);
|
|
559
|
+
expect(result.characteristics.hasBackend).toBe(true);
|
|
560
|
+
expect(result.characteristics.hasApi).toBe(true);
|
|
561
|
+
});
|
|
562
|
+
it("detects Next.js from package.json", async () => {
|
|
563
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
564
|
+
dependencies: { next: "^14.0.0" }
|
|
565
|
+
}));
|
|
566
|
+
const result = await analyzeProject(testDir);
|
|
567
|
+
expect(result.frameworks.nextjs).toBe(true);
|
|
568
|
+
expect(result.characteristics.hasFrontend).toBe(true);
|
|
569
|
+
expect(result.characteristics.hasBackend).toBe(true);
|
|
570
|
+
});
|
|
571
|
+
it("detects GitHub Actions", async () => {
|
|
572
|
+
await mkdir(join(testDir, ".github", "workflows"), { recursive: true });
|
|
573
|
+
const result = await analyzeProject(testDir);
|
|
574
|
+
expect(result.ci.githubActions).toBe(true);
|
|
575
|
+
});
|
|
576
|
+
it("detects GitLab CI", async () => {
|
|
577
|
+
await writeFile(join(testDir, ".gitlab-ci.yml"), "stages:\n - build");
|
|
578
|
+
const result = await analyzeProject(testDir);
|
|
579
|
+
expect(result.ci.gitlabCi).toBe(true);
|
|
580
|
+
});
|
|
581
|
+
it("detects Jest from package.json", async () => {
|
|
582
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
583
|
+
devDependencies: { jest: "^29.0.0" }
|
|
584
|
+
}));
|
|
585
|
+
const result = await analyzeProject(testDir);
|
|
586
|
+
expect(result.testing.jest).toBe(true);
|
|
587
|
+
});
|
|
588
|
+
it("detects Vitest from package.json", async () => {
|
|
589
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
590
|
+
devDependencies: { vitest: "^1.0.0" }
|
|
591
|
+
}));
|
|
592
|
+
const result = await analyzeProject(testDir);
|
|
593
|
+
expect(result.testing.vitest).toBe(true);
|
|
594
|
+
});
|
|
595
|
+
it("detects pytest from conftest.py", async () => {
|
|
596
|
+
await writeFile(join(testDir, "conftest.py"), "# pytest config");
|
|
597
|
+
const result = await analyzeProject(testDir);
|
|
598
|
+
expect(result.testing.pytest).toBe(true);
|
|
599
|
+
});
|
|
600
|
+
it("detects test directory", async () => {
|
|
601
|
+
await mkdir(join(testDir, "tests"), { recursive: true });
|
|
602
|
+
const result = await analyzeProject(testDir);
|
|
603
|
+
expect(result.testing.hasTestDirectory).toBe(true);
|
|
604
|
+
});
|
|
605
|
+
it("detects AGENTS.md", async () => {
|
|
606
|
+
await writeFile(join(testDir, "AGENTS.md"), "# Agent Instructions");
|
|
607
|
+
const result = await analyzeProject(testDir);
|
|
608
|
+
expect(result.aiTools.agentsMd).toBe(true);
|
|
609
|
+
});
|
|
610
|
+
it("detects CLAUDE.md", async () => {
|
|
611
|
+
await writeFile(join(testDir, "CLAUDE.md"), "# Claude Instructions");
|
|
612
|
+
const result = await analyzeProject(testDir);
|
|
613
|
+
expect(result.aiTools.claudeMd).toBe(true);
|
|
614
|
+
});
|
|
615
|
+
it("detects GitHub Copilot instructions", async () => {
|
|
616
|
+
await mkdir(join(testDir, ".github"), { recursive: true });
|
|
617
|
+
await writeFile(join(testDir, ".github", "copilot-instructions.md"), "# Instructions");
|
|
618
|
+
const result = await analyzeProject(testDir);
|
|
619
|
+
expect(result.aiTools.copilotInstructions).toBe(true);
|
|
620
|
+
});
|
|
621
|
+
it("detects Cursor rules", async () => {
|
|
622
|
+
await writeFile(join(testDir, ".cursorrules"), "# Rules");
|
|
623
|
+
const result = await analyzeProject(testDir);
|
|
624
|
+
expect(result.aiTools.cursorRules).toBe(true);
|
|
625
|
+
});
|
|
626
|
+
it("detects OpenCode config", async () => {
|
|
627
|
+
await writeFile(join(testDir, "opencode.json"), '{}');
|
|
628
|
+
const result = await analyzeProject(testDir);
|
|
629
|
+
expect(result.aiTools.openCodeConfig).toBe(true);
|
|
630
|
+
});
|
|
631
|
+
it("detects Prisma", async () => {
|
|
632
|
+
await mkdir(join(testDir, "prisma"), { recursive: true });
|
|
633
|
+
const result = await analyzeProject(testDir);
|
|
634
|
+
expect(result.database.prisma).toBe(true);
|
|
635
|
+
});
|
|
636
|
+
it("detects migrations directory", async () => {
|
|
637
|
+
await mkdir(join(testDir, "migrations"), { recursive: true });
|
|
638
|
+
const result = await analyzeProject(testDir);
|
|
639
|
+
expect(result.database.hasMigrations).toBe(true);
|
|
640
|
+
});
|
|
641
|
+
it("detects Sentry from package.json", async () => {
|
|
642
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
643
|
+
dependencies: { "@sentry/node": "^7.0.0" }
|
|
644
|
+
}));
|
|
645
|
+
const result = await analyzeProject(testDir);
|
|
646
|
+
expect(result.monitoring.sentry).toBe(true);
|
|
647
|
+
});
|
|
648
|
+
it("detects Docker", async () => {
|
|
649
|
+
await writeFile(join(testDir, "Dockerfile"), "FROM node:20");
|
|
650
|
+
const result = await analyzeProject(testDir);
|
|
651
|
+
expect(result.characteristics.hasDocker).toBe(true);
|
|
652
|
+
});
|
|
653
|
+
it("detects monorepo from workspaces", async () => {
|
|
654
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
655
|
+
workspaces: ["packages/*"]
|
|
656
|
+
}));
|
|
657
|
+
const result = await analyzeProject(testDir);
|
|
658
|
+
expect(result.characteristics.isMonorepo).toBe(true);
|
|
659
|
+
});
|
|
660
|
+
it("detects library from package.json exports", async () => {
|
|
661
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
662
|
+
main: "dist/index.js",
|
|
663
|
+
exports: { ".": "./dist/index.js" }
|
|
664
|
+
}));
|
|
665
|
+
const result = await analyzeProject(testDir);
|
|
666
|
+
expect(result.characteristics.isLibrary).toBe(true);
|
|
667
|
+
});
|
|
668
|
+
it("highlights AI collaboration when AI tools detected", async () => {
|
|
669
|
+
await writeFile(join(testDir, "AGENTS.md"), "# Instructions");
|
|
670
|
+
const result = await analyzeProject(testDir);
|
|
671
|
+
expect(result.recommendations.highlightedTopics).toContain("AI/LLM Collaboration");
|
|
672
|
+
});
|
|
673
|
+
it("marks database topics as skippable when no database", async () => {
|
|
674
|
+
const result = await analyzeProject(testDir);
|
|
675
|
+
expect(result.recommendations.skippableTopics).toContain("Database & Schema Changes");
|
|
676
|
+
});
|
|
677
|
+
it("marks a11y as skippable when no frontend", async () => {
|
|
678
|
+
await writeFile(join(testDir, "package.json"), JSON.stringify({
|
|
679
|
+
dependencies: { express: "^4.0.0" }
|
|
680
|
+
}));
|
|
681
|
+
const result = await analyzeProject(testDir);
|
|
682
|
+
expect(result.recommendations.skippableTopics).toContain("Accessibility & Internationalization");
|
|
683
|
+
});
|
|
684
|
+
});
|
|
685
|
+
describe("formatProjectAnalysis", () => {
|
|
686
|
+
it("formats empty analysis", () => {
|
|
687
|
+
const analysis = {
|
|
688
|
+
languages: { typescript: false, javascript: false, python: false, rust: false, go: false, ruby: false, java: false, csharp: false, other: [] },
|
|
689
|
+
frameworks: { react: false, vue: false, angular: false, nextjs: false, express: false, fastapi: false, django: false, rails: false, springBoot: false, other: [] },
|
|
690
|
+
ci: { githubActions: false, gitlabCi: false, circleCi: false, jenkins: false, other: [] },
|
|
691
|
+
testing: { jest: false, vitest: false, mocha: false, pytest: false, rspec: false, goTest: false, hasTestDirectory: false, other: [] },
|
|
692
|
+
aiTools: { agentsMd: false, claudeMd: false, copilotInstructions: false, cursorRules: false, continueConfig: false, openCodeConfig: false },
|
|
693
|
+
database: { prisma: false, sequelize: false, typeorm: false, drizzle: false, sqlalchemy: false, activeRecord: false, hasMigrations: false, other: [] },
|
|
694
|
+
monitoring: { sentry: false, datadog: false, newRelic: false, prometheus: false, other: [] },
|
|
695
|
+
characteristics: { isMonorepo: false, isLibrary: false, hasDocker: false, hasFrontend: false, hasBackend: false, hasApi: false, hasDocs: false },
|
|
696
|
+
recommendations: { suggestedCategories: ["Code & Quality"], highlightedTopics: [], skippableTopics: [] }
|
|
697
|
+
};
|
|
698
|
+
const result = formatProjectAnalysis(analysis);
|
|
699
|
+
expect(result).toContain("Project Analysis Results");
|
|
700
|
+
expect(result).toContain("Recommendations");
|
|
701
|
+
expect(result).toContain("Code & Quality");
|
|
702
|
+
});
|
|
703
|
+
it("formats languages section", () => {
|
|
704
|
+
const analysis = {
|
|
705
|
+
languages: { typescript: true, javascript: true, python: false, rust: false, go: false, ruby: false, java: false, csharp: false, other: [] },
|
|
706
|
+
frameworks: { react: false, vue: false, angular: false, nextjs: false, express: false, fastapi: false, django: false, rails: false, springBoot: false, other: [] },
|
|
707
|
+
ci: { githubActions: false, gitlabCi: false, circleCi: false, jenkins: false, other: [] },
|
|
708
|
+
testing: { jest: false, vitest: false, mocha: false, pytest: false, rspec: false, goTest: false, hasTestDirectory: false, other: [] },
|
|
709
|
+
aiTools: { agentsMd: false, claudeMd: false, copilotInstructions: false, cursorRules: false, continueConfig: false, openCodeConfig: false },
|
|
710
|
+
database: { prisma: false, sequelize: false, typeorm: false, drizzle: false, sqlalchemy: false, activeRecord: false, hasMigrations: false, other: [] },
|
|
711
|
+
monitoring: { sentry: false, datadog: false, newRelic: false, prometheus: false, other: [] },
|
|
712
|
+
characteristics: { isMonorepo: false, isLibrary: false, hasDocker: false, hasFrontend: false, hasBackend: false, hasApi: false, hasDocs: false },
|
|
713
|
+
recommendations: { suggestedCategories: [], highlightedTopics: [], skippableTopics: [] }
|
|
714
|
+
};
|
|
715
|
+
const result = formatProjectAnalysis(analysis);
|
|
716
|
+
expect(result).toContain("### Languages");
|
|
717
|
+
expect(result).toContain("Typescript");
|
|
718
|
+
expect(result).toContain("Javascript");
|
|
719
|
+
});
|
|
720
|
+
it("formats frameworks section", () => {
|
|
721
|
+
const analysis = {
|
|
722
|
+
languages: { typescript: false, javascript: false, python: false, rust: false, go: false, ruby: false, java: false, csharp: false, other: [] },
|
|
723
|
+
frameworks: { react: true, vue: false, angular: false, nextjs: false, express: true, fastapi: false, django: false, rails: false, springBoot: false, other: [] },
|
|
724
|
+
ci: { githubActions: false, gitlabCi: false, circleCi: false, jenkins: false, other: [] },
|
|
725
|
+
testing: { jest: false, vitest: false, mocha: false, pytest: false, rspec: false, goTest: false, hasTestDirectory: false, other: [] },
|
|
726
|
+
aiTools: { agentsMd: false, claudeMd: false, copilotInstructions: false, cursorRules: false, continueConfig: false, openCodeConfig: false },
|
|
727
|
+
database: { prisma: false, sequelize: false, typeorm: false, drizzle: false, sqlalchemy: false, activeRecord: false, hasMigrations: false, other: [] },
|
|
728
|
+
monitoring: { sentry: false, datadog: false, newRelic: false, prometheus: false, other: [] },
|
|
729
|
+
characteristics: { isMonorepo: false, isLibrary: false, hasDocker: false, hasFrontend: false, hasBackend: false, hasApi: false, hasDocs: false },
|
|
730
|
+
recommendations: { suggestedCategories: [], highlightedTopics: [], skippableTopics: [] }
|
|
731
|
+
};
|
|
732
|
+
const result = formatProjectAnalysis(analysis);
|
|
733
|
+
expect(result).toContain("### Frameworks");
|
|
734
|
+
expect(result).toContain("React");
|
|
735
|
+
expect(result).toContain("Express");
|
|
736
|
+
});
|
|
737
|
+
it("formats AI tools section", () => {
|
|
738
|
+
const analysis = {
|
|
739
|
+
languages: { typescript: false, javascript: false, python: false, rust: false, go: false, ruby: false, java: false, csharp: false, other: [] },
|
|
740
|
+
frameworks: { react: false, vue: false, angular: false, nextjs: false, express: false, fastapi: false, django: false, rails: false, springBoot: false, other: [] },
|
|
741
|
+
ci: { githubActions: false, gitlabCi: false, circleCi: false, jenkins: false, other: [] },
|
|
742
|
+
testing: { jest: false, vitest: false, mocha: false, pytest: false, rspec: false, goTest: false, hasTestDirectory: false, other: [] },
|
|
743
|
+
aiTools: { agentsMd: true, claudeMd: false, copilotInstructions: true, cursorRules: false, continueConfig: false, openCodeConfig: false },
|
|
744
|
+
database: { prisma: false, sequelize: false, typeorm: false, drizzle: false, sqlalchemy: false, activeRecord: false, hasMigrations: false, other: [] },
|
|
745
|
+
monitoring: { sentry: false, datadog: false, newRelic: false, prometheus: false, other: [] },
|
|
746
|
+
characteristics: { isMonorepo: false, isLibrary: false, hasDocker: false, hasFrontend: false, hasBackend: false, hasApi: false, hasDocs: false },
|
|
747
|
+
recommendations: { suggestedCategories: [], highlightedTopics: [], skippableTopics: [] }
|
|
748
|
+
};
|
|
749
|
+
const result = formatProjectAnalysis(analysis);
|
|
750
|
+
expect(result).toContain("### AI Tools Configuration");
|
|
751
|
+
expect(result).toContain("AGENTS.md");
|
|
752
|
+
expect(result).toContain("GitHub Copilot instructions");
|
|
753
|
+
});
|
|
754
|
+
it("shows no CI message when not detected", () => {
|
|
755
|
+
const analysis = {
|
|
756
|
+
languages: { typescript: false, javascript: false, python: false, rust: false, go: false, ruby: false, java: false, csharp: false, other: [] },
|
|
757
|
+
frameworks: { react: false, vue: false, angular: false, nextjs: false, express: false, fastapi: false, django: false, rails: false, springBoot: false, other: [] },
|
|
758
|
+
ci: { githubActions: false, gitlabCi: false, circleCi: false, jenkins: false, other: [] },
|
|
759
|
+
testing: { jest: false, vitest: false, mocha: false, pytest: false, rspec: false, goTest: false, hasTestDirectory: false, other: [] },
|
|
760
|
+
aiTools: { agentsMd: false, claudeMd: false, copilotInstructions: false, cursorRules: false, continueConfig: false, openCodeConfig: false },
|
|
761
|
+
database: { prisma: false, sequelize: false, typeorm: false, drizzle: false, sqlalchemy: false, activeRecord: false, hasMigrations: false, other: [] },
|
|
762
|
+
monitoring: { sentry: false, datadog: false, newRelic: false, prometheus: false, other: [] },
|
|
763
|
+
characteristics: { isMonorepo: false, isLibrary: false, hasDocker: false, hasFrontend: false, hasBackend: false, hasApi: false, hasDocs: false },
|
|
764
|
+
recommendations: { suggestedCategories: [], highlightedTopics: [], skippableTopics: [] }
|
|
765
|
+
};
|
|
766
|
+
const result = formatProjectAnalysis(analysis);
|
|
767
|
+
expect(result).toContain("No CI/CD detected");
|
|
768
|
+
});
|
|
769
|
+
it("formats highlighted topics", () => {
|
|
770
|
+
const analysis = {
|
|
771
|
+
languages: { typescript: false, javascript: false, python: false, rust: false, go: false, ruby: false, java: false, csharp: false, other: [] },
|
|
772
|
+
frameworks: { react: false, vue: false, angular: false, nextjs: false, express: false, fastapi: false, django: false, rails: false, springBoot: false, other: [] },
|
|
773
|
+
ci: { githubActions: false, gitlabCi: false, circleCi: false, jenkins: false, other: [] },
|
|
774
|
+
testing: { jest: false, vitest: false, mocha: false, pytest: false, rspec: false, goTest: false, hasTestDirectory: false, other: [] },
|
|
775
|
+
aiTools: { agentsMd: false, claudeMd: false, copilotInstructions: false, cursorRules: false, continueConfig: false, openCodeConfig: false },
|
|
776
|
+
database: { prisma: false, sequelize: false, typeorm: false, drizzle: false, sqlalchemy: false, activeRecord: false, hasMigrations: false, other: [] },
|
|
777
|
+
monitoring: { sentry: false, datadog: false, newRelic: false, prometheus: false, other: [] },
|
|
778
|
+
characteristics: { isMonorepo: false, isLibrary: false, hasDocker: false, hasFrontend: false, hasBackend: false, hasApi: false, hasDocs: false },
|
|
779
|
+
recommendations: { suggestedCategories: [], highlightedTopics: ["AI/LLM Collaboration", "Security"], skippableTopics: [] }
|
|
780
|
+
};
|
|
781
|
+
const result = formatProjectAnalysis(analysis);
|
|
782
|
+
expect(result).toContain("Topics to highlight");
|
|
783
|
+
expect(result).toContain("AI/LLM Collaboration");
|
|
784
|
+
expect(result).toContain("Security");
|
|
785
|
+
});
|
|
786
|
+
it("formats skippable topics", () => {
|
|
787
|
+
const analysis = {
|
|
788
|
+
languages: { typescript: false, javascript: false, python: false, rust: false, go: false, ruby: false, java: false, csharp: false, other: [] },
|
|
789
|
+
frameworks: { react: false, vue: false, angular: false, nextjs: false, express: false, fastapi: false, django: false, rails: false, springBoot: false, other: [] },
|
|
790
|
+
ci: { githubActions: false, gitlabCi: false, circleCi: false, jenkins: false, other: [] },
|
|
791
|
+
testing: { jest: false, vitest: false, mocha: false, pytest: false, rspec: false, goTest: false, hasTestDirectory: false, other: [] },
|
|
792
|
+
aiTools: { agentsMd: false, claudeMd: false, copilotInstructions: false, cursorRules: false, continueConfig: false, openCodeConfig: false },
|
|
793
|
+
database: { prisma: false, sequelize: false, typeorm: false, drizzle: false, sqlalchemy: false, activeRecord: false, hasMigrations: false, other: [] },
|
|
794
|
+
monitoring: { sentry: false, datadog: false, newRelic: false, prometheus: false, other: [] },
|
|
795
|
+
characteristics: { isMonorepo: false, isLibrary: false, hasDocker: false, hasFrontend: false, hasBackend: false, hasApi: false, hasDocs: false },
|
|
796
|
+
recommendations: { suggestedCategories: [], highlightedTopics: [], skippableTopics: ["Database & Schema Changes"] }
|
|
797
|
+
};
|
|
798
|
+
const result = formatProjectAnalysis(analysis);
|
|
799
|
+
expect(result).toContain("Topics that may be skippable");
|
|
800
|
+
expect(result).toContain("Database & Schema Changes");
|
|
801
|
+
});
|
|
425
802
|
});
|
|
426
803
|
//# sourceMappingURL=index.test.js.map
|