opencode-plugin-team-agreements 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # opencode-plugin-team-agreements
2
+
3
+ An [OpenCode](https://opencode.ai) plugin that helps teams of humans and LLM agents establish, document, and maintain shared agreements for collaborating on a codebase.
4
+
5
+ ## Features
6
+
7
+ - **Interactive facilitation** - Guides teams through establishing agreements one topic at a time
8
+ - **Core topics covered**:
9
+ - Storage location for agreements
10
+ - Programming languages and their purposes
11
+ - Code quality standards
12
+ - Commit message conventions
13
+ - Integration workflow (branching, PRs, CI)
14
+ - Testing requirements
15
+ - Amendment process for updating agreements
16
+ - **Extensible** - Add custom topics beyond the core set
17
+ - **Context injection** - Automatically injects agreements into LLM context at session start and after compaction
18
+ - **Topic suggestions** - Users can suggest new standard topics via GitHub issues (using `gh` CLI)
19
+
20
+ ## Installation
21
+
22
+ Add the plugin to your `opencode.json`:
23
+
24
+ ```json
25
+ {
26
+ "$schema": "https://opencode.ai/config.json",
27
+ "plugin": ["opencode-plugin-team-agreements"]
28
+ }
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ Run the `/team-agreements` command in OpenCode:
34
+
35
+ ```
36
+ /team-agreements
37
+ ```
38
+
39
+ The plugin will guide you through establishing agreements for your project. You can also provide context:
40
+
41
+ ```
42
+ /team-agreements I want to update our commit message conventions
43
+ ```
44
+
45
+ ### Options when agreements exist
46
+
47
+ If `docs/TEAM_AGREEMENTS.md` already exists, you'll be presented with options to:
48
+ - **Review** - Display current agreements
49
+ - **Amend** - Modify a specific section
50
+ - **Start Over** - Begin fresh (with confirmation)
51
+
52
+ ## How it works
53
+
54
+ 1. **Command registration** - The plugin registers the `/team-agreements` command via OpenCode's config hook
55
+ 2. **Interactive conversation** - An LLM guides you through each topic, asking one question at a time
56
+ 3. **Document generation** - Creates `docs/TEAM_AGREEMENTS.md` with your agreements
57
+ 4. **Auto-injection** - Adds agreements to the `instructions` config so all agents see them
58
+ 5. **Compaction handling** - Re-injects agreements after context compaction in long sessions
59
+
60
+ ## Suggesting new topics
61
+
62
+ If you think of a topic that should be standard in team agreements, you can suggest it:
63
+
64
+ 1. During the `/team-agreements` conversation, ask to suggest a topic
65
+ 2. The plugin will file a GitHub issue for you (requires `gh` CLI)
66
+ 3. Or manually create an issue at: [Topic Suggestion](https://github.com/jwilger/opencode-plugin-team-agreements/issues/new?template=topic-suggestion.md)
67
+
68
+ ## Development
69
+
70
+ ```bash
71
+ # Clone the repository
72
+ git clone https://github.com/jwilger/opencode-plugin-team-agreements.git
73
+ cd opencode-plugin-team-agreements
74
+
75
+ # Install dependencies
76
+ npm install
77
+
78
+ # Build
79
+ npm run build
80
+
81
+ # Watch mode for development
82
+ npm run dev
83
+ ```
84
+
85
+ ### Local testing
86
+
87
+ Reference the local plugin in your project's `opencode.json`:
88
+
89
+ ```json
90
+ {
91
+ "plugin": ["/path/to/opencode-plugin-team-agreements"]
92
+ }
93
+ ```
94
+
95
+ ## License
96
+
97
+ MIT
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ export type ToolContext = {
3
+ sessionID: string;
4
+ messageID: string;
5
+ agent: string;
6
+ abort: AbortSignal;
7
+ metadata(input: {
8
+ title?: string;
9
+ metadata?: {
10
+ [key: string]: any;
11
+ };
12
+ }): void;
13
+ ask(input: {
14
+ permission: string;
15
+ patterns: string[];
16
+ always: string[];
17
+ metadata: {
18
+ [key: string]: any;
19
+ };
20
+ }): Promise<void>;
21
+ };
22
+ export declare function tool<Args extends z.ZodRawShape>(input: {
23
+ description: string;
24
+ args: Args;
25
+ execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<string>;
26
+ }): {
27
+ description: string;
28
+ args: Args;
29
+ execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<string>;
30
+ };
31
+ export declare namespace tool {
32
+ var schema: typeof z;
33
+ }
34
+ export type ToolDefinition = ReturnType<typeof tool>;
35
+ export type PluginInput = {
36
+ client: any;
37
+ project: any;
38
+ directory: string;
39
+ worktree: string;
40
+ serverUrl: URL;
41
+ $: any;
42
+ };
43
+ export type Plugin = (input: PluginInput) => Promise<Hooks>;
44
+ export interface Hooks {
45
+ event?: (input: {
46
+ event: any;
47
+ }) => Promise<void>;
48
+ config?: (input: any) => Promise<void>;
49
+ tool?: {
50
+ [key: string]: ToolDefinition;
51
+ };
52
+ auth?: any;
53
+ "chat.message"?: (input: any, output: any) => Promise<void>;
54
+ "chat.params"?: (input: any, output: any) => Promise<void>;
55
+ "chat.headers"?: (input: any, output: any) => Promise<void>;
56
+ "permission.ask"?: (input: any, output: any) => Promise<void>;
57
+ "command.execute.before"?: (input: any, output: any) => Promise<void>;
58
+ "tool.execute.before"?: (input: any, output: any) => Promise<void>;
59
+ "tool.execute.after"?: (input: any, output: any) => Promise<void>;
60
+ "experimental.chat.messages.transform"?: (input: any, output: any) => Promise<void>;
61
+ "experimental.chat.system.transform"?: (input: any, output: any) => Promise<void>;
62
+ "experimental.session.compacting"?: (input: {
63
+ sessionID: string;
64
+ }, output: {
65
+ context: string[];
66
+ prompt?: string;
67
+ }) => Promise<void>;
68
+ "experimental.text.complete"?: (input: any, output: any) => Promise<void>;
69
+ }
70
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/__mocks__/@opencode-ai/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5E,GAAG,CAAC,KAAK,EAAE;QACT,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,EAAE,CAAA;QAClB,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,QAAQ,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAA;KACjC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClB,CAAA;AAED,wBAAgB,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE;IACtD,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACjF;iBAHc,MAAM;UACb,IAAI;kBACI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,WAAW,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;EAGjF;yBANe,IAAI;;;AAUpB,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAA;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,GAAG,CAAA;IACX,OAAO,EAAE,GAAG,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,GAAG,CAAA;IACd,CAAC,EAAE,GAAG,CAAA;CACP,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,KAAK,CAAC,CAAA;AAE3D,MAAM,WAAW,KAAK;IACpB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACtC,IAAI,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAA;KAAE,CAAA;IACxC,IAAI,CAAC,EAAE,GAAG,CAAA;IACV,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7D,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjE,sCAAsC,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnF,oCAAoC,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjF,iCAAiC,CAAC,EAAE,CAClC,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,EAC5B,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAC3C,OAAO,CAAC,IAAI,CAAC,CAAA;IAClB,4BAA4B,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1E"}
@@ -0,0 +1,8 @@
1
+ // Mock for @opencode-ai/plugin to avoid ESM resolution issues in tests
2
+ // The real package has a bug where index.js exports from "./tool" without .js extension
3
+ import { z } from "zod";
4
+ export function tool(input) {
5
+ return input;
6
+ }
7
+ tool.schema = z;
8
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/__mocks__/@opencode-ai/plugin.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,wFAAwF;AAExF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAgBvB,MAAM,UAAU,IAAI,CAA6B,KAIhD;IACC,OAAO,KAAK,CAAA;AACd,CAAC;AAED,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA"}
@@ -0,0 +1,37 @@
1
+ import { type Plugin } from "@opencode-ai/plugin";
2
+ declare const PLUGIN_REPO = "jwilger/opencode-plugin-team-agreements";
3
+ declare const COMMAND_TEMPLATE = "You are helping establish or review team agreements for this project. Team agreements define how humans and LLM agents collaborate on the codebase.\n\nUser's request: $ARGUMENTS\n\n## Instructions\n\n1. First, check if team agreements already exist at `docs/TEAM_AGREEMENTS.md`\n\n2. If agreements exist, present the user with options:\n - **Review**: Display the current agreements\n - **Amend**: Modify a specific section \n - **Start Over**: Begin fresh (with confirmation)\n\n3. If no agreements exist (or starting over), guide the user through establishing agreements one topic at a time. Start with these core topics:\n\n### Core Topics\n\n#### a. Storage Location\nAsk where team agreements should be stored. Suggest defaults:\n- Main file: `docs/TEAM_AGREEMENTS.md`\n- Supporting details: `docs/team_agreements/*.md`\n\n#### b. Programming Languages\n- What programming language(s) will be used in this project?\n- What is each language used for? (e.g., TypeScript for frontend, Rust for backend)\n- Are there specific versions or language-specific style guides to follow?\n\n#### c. Code Quality Standards\n- What does \"great code\" look like for this team?\n- How should we prioritize: readability vs. performance vs. simplicity?\n- Are there required patterns or anti-patterns to follow/avoid?\n- What about error handling conventions?\n- Naming conventions for files, functions, variables, types?\n\n#### d. Commit Message Conventions\n- What format should commit messages follow? (Conventional Commits, custom, freeform)\n- Are there required elements? (ticket numbers, scope, breaking change indicators)\n- Any rules on length, tense, capitalization?\n- Should commits be atomic (one logical change per commit)?\n\n#### e. Integration Workflow\n- Trunk-based development or feature branches?\n- Pull request requirements? (reviews, approvals, CI checks)\n- Who can merge to main/trunk?\n- What CI checks must pass before integration?\n- Any branch naming conventions?\n\n#### f. Testing Requirements\n- What testing is required before code is considered \"done\"?\n- Are there coverage thresholds?\n- What types of tests? (unit, integration, e2e, property-based)\n- When should tests be written? (TDD, after implementation, etc.)\n\n#### g. Amendment Process\n- How can these agreements be changed?\n- Who has authority to propose/approve changes?\n- What's the review/approval process for amendments?\n- How should changes be communicated to the team?\n\n4. For each topic:\n - Ask ONE question at a time\n - Discuss trade-offs when relevant\n - Confirm understanding before moving on\n - Record the team's decision clearly\n\n5. **After the core topics**, ask:\n \"Are there any additional topics you'd like to establish agreements for?\"\n \n Suggest potential additional topics if helpful:\n - **Architecture decisions** - How to document and track ADRs\n - **Dependency management** - How to evaluate and approve new dependencies\n - **Documentation standards** - What must be documented, where, in what format\n - **LLM autonomy boundaries** - What can LLMs do without asking? What requires human approval?\n - **Session handoff protocols** - How to summarize work for the next session/agent\n - **Code review process** - What reviewers should look for, turnaround expectations\n - **Planning and work breakdown** - How to break down work into tasks\n - **Information sharing** - How to share context across sessions and team members\n \n Continue asking about each additional topic the user wants to cover.\n \n After discussing additional topics, ask: \"Would you like to suggest any of these additional topics\n (or others you thought of) to be included as standard topics in the team-agreements plugin?\n I can file a GitHub issue for you if you'd like.\"\n \n If the user wants to suggest a topic, use the `suggest_team_agreement_topic` tool to file an issue.\n\n6. After ALL topics (core + additional) are covered:\n - Generate `docs/TEAM_AGREEMENTS.md` with all agreements organized by topic\n - If any topic needs detailed documentation, create supporting files in `docs/team_agreements/`\n - Update `opencode.json` to include `docs/TEAM_AGREEMENTS.md` in the `instructions` array\n - Summarize what was established\n\n## Output Format\n\nWhen generating the TEAM_AGREEMENTS.md file, use this structure:\n\n```markdown\n# Team Agreements\n\nThis document defines how our team (humans and LLM agents) collaborates on this codebase.\n\n## Table of Contents\n[Generate based on topics covered]\n\n## 1. Storage Location\n[Agreements about where documentation lives]\n\n## 2. Programming Languages\n[Agreements about languages and their usage]\n\n## 3. Code Quality Standards\n[Agreements about what makes good code]\n\n## 4. Commit Message Conventions\n[Agreements about commit message format]\n\n## 5. Integration Workflow\n[Agreements about how code gets integrated]\n\n## 6. Testing Requirements\n[Agreements about testing]\n\n## 7. Amendment Process\n[Agreements about changing these agreements]\n\n## Additional Topics\n[Any additional topics the team added]\n\n---\n*Last updated: [date]*\n*To amend these agreements, [process from amendment section]*\n```\n\n## Important\n\n- Be conversational and collaborative\n- ONE question at a time - don't overwhelm\n- Respect the user's expertise and preferences\n- If the user provides a specific request in their message, address that first\n- The core topics are a starting point, not an exhaustive list\n- Capture the \"why\" behind decisions, not just the \"what\"";
4
+ /**
5
+ * Check if a file exists at the given path.
6
+ */
7
+ export declare function fileExists(path: string): Promise<boolean>;
8
+ /**
9
+ * Check if the gh CLI is installed and authenticated.
10
+ */
11
+ export declare function isGhAvailable(): Promise<boolean>;
12
+ /**
13
+ * Load team agreements from the project directory.
14
+ * Returns the content if found, null otherwise.
15
+ */
16
+ export declare function loadTeamAgreements(directory: string): Promise<string | null>;
17
+ /**
18
+ * Format suggested questions as a markdown list.
19
+ */
20
+ export declare function formatQuestionsAsMarkdown(questions: string[]): string;
21
+ /**
22
+ * Build the issue body for a topic suggestion.
23
+ */
24
+ export declare function buildTopicIssueBody(args: {
25
+ topic_name: string;
26
+ description: string;
27
+ suggested_questions: string[];
28
+ example_agreement?: string;
29
+ }): string;
30
+ export { COMMAND_TEMPLATE, PLUGIN_REPO };
31
+ /**
32
+ * TeamAgreementsPlugin - Helps teams establish and maintain shared agreements
33
+ * for human-LLM collaboration on a codebase.
34
+ */
35
+ export declare const TeamAgreementsPlugin: Plugin;
36
+ export default TeamAgreementsPlugin;
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,qBAAqB,CAAA;AAQvD,QAAA,MAAM,WAAW,4CAA4C,CAAA;AAE7D,QAAA,MAAM,gBAAgB,0+KA4IoC,CAAA;AAE1D;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAOtD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASlF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAErE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,GAAG,MAAM,CAiBT;AAGD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAiGlC,CAAA;AAED,eAAe,oBAAoB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,304 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+ import { readFile, access } from "fs/promises";
3
+ import { join } from "path";
4
+ import { exec } from "child_process";
5
+ import { promisify } from "util";
6
+ const execAsync = promisify(exec);
7
+ const PLUGIN_REPO = "jwilger/opencode-plugin-team-agreements";
8
+ const COMMAND_TEMPLATE = `You are helping establish or review team agreements for this project. Team agreements define how humans and LLM agents collaborate on the codebase.
9
+
10
+ User's request: $ARGUMENTS
11
+
12
+ ## Instructions
13
+
14
+ 1. First, check if team agreements already exist at \`docs/TEAM_AGREEMENTS.md\`
15
+
16
+ 2. If agreements exist, present the user with options:
17
+ - **Review**: Display the current agreements
18
+ - **Amend**: Modify a specific section
19
+ - **Start Over**: Begin fresh (with confirmation)
20
+
21
+ 3. If no agreements exist (or starting over), guide the user through establishing agreements one topic at a time. Start with these core topics:
22
+
23
+ ### Core Topics
24
+
25
+ #### a. Storage Location
26
+ Ask where team agreements should be stored. Suggest defaults:
27
+ - Main file: \`docs/TEAM_AGREEMENTS.md\`
28
+ - Supporting details: \`docs/team_agreements/*.md\`
29
+
30
+ #### b. Programming Languages
31
+ - What programming language(s) will be used in this project?
32
+ - What is each language used for? (e.g., TypeScript for frontend, Rust for backend)
33
+ - Are there specific versions or language-specific style guides to follow?
34
+
35
+ #### c. Code Quality Standards
36
+ - What does "great code" look like for this team?
37
+ - How should we prioritize: readability vs. performance vs. simplicity?
38
+ - Are there required patterns or anti-patterns to follow/avoid?
39
+ - What about error handling conventions?
40
+ - Naming conventions for files, functions, variables, types?
41
+
42
+ #### d. Commit Message Conventions
43
+ - What format should commit messages follow? (Conventional Commits, custom, freeform)
44
+ - Are there required elements? (ticket numbers, scope, breaking change indicators)
45
+ - Any rules on length, tense, capitalization?
46
+ - Should commits be atomic (one logical change per commit)?
47
+
48
+ #### e. Integration Workflow
49
+ - Trunk-based development or feature branches?
50
+ - Pull request requirements? (reviews, approvals, CI checks)
51
+ - Who can merge to main/trunk?
52
+ - What CI checks must pass before integration?
53
+ - Any branch naming conventions?
54
+
55
+ #### f. Testing Requirements
56
+ - What testing is required before code is considered "done"?
57
+ - Are there coverage thresholds?
58
+ - What types of tests? (unit, integration, e2e, property-based)
59
+ - When should tests be written? (TDD, after implementation, etc.)
60
+
61
+ #### g. Amendment Process
62
+ - How can these agreements be changed?
63
+ - Who has authority to propose/approve changes?
64
+ - What's the review/approval process for amendments?
65
+ - How should changes be communicated to the team?
66
+
67
+ 4. For each topic:
68
+ - Ask ONE question at a time
69
+ - Discuss trade-offs when relevant
70
+ - Confirm understanding before moving on
71
+ - Record the team's decision clearly
72
+
73
+ 5. **After the core topics**, ask:
74
+ "Are there any additional topics you'd like to establish agreements for?"
75
+
76
+ Suggest potential additional topics if helpful:
77
+ - **Architecture decisions** - How to document and track ADRs
78
+ - **Dependency management** - How to evaluate and approve new dependencies
79
+ - **Documentation standards** - What must be documented, where, in what format
80
+ - **LLM autonomy boundaries** - What can LLMs do without asking? What requires human approval?
81
+ - **Session handoff protocols** - How to summarize work for the next session/agent
82
+ - **Code review process** - What reviewers should look for, turnaround expectations
83
+ - **Planning and work breakdown** - How to break down work into tasks
84
+ - **Information sharing** - How to share context across sessions and team members
85
+
86
+ Continue asking about each additional topic the user wants to cover.
87
+
88
+ After discussing additional topics, ask: "Would you like to suggest any of these additional topics
89
+ (or others you thought of) to be included as standard topics in the team-agreements plugin?
90
+ I can file a GitHub issue for you if you'd like."
91
+
92
+ If the user wants to suggest a topic, use the \`suggest_team_agreement_topic\` tool to file an issue.
93
+
94
+ 6. After ALL topics (core + additional) are covered:
95
+ - Generate \`docs/TEAM_AGREEMENTS.md\` with all agreements organized by topic
96
+ - If any topic needs detailed documentation, create supporting files in \`docs/team_agreements/\`
97
+ - Update \`opencode.json\` to include \`docs/TEAM_AGREEMENTS.md\` in the \`instructions\` array
98
+ - Summarize what was established
99
+
100
+ ## Output Format
101
+
102
+ When generating the TEAM_AGREEMENTS.md file, use this structure:
103
+
104
+ \`\`\`markdown
105
+ # Team Agreements
106
+
107
+ This document defines how our team (humans and LLM agents) collaborates on this codebase.
108
+
109
+ ## Table of Contents
110
+ [Generate based on topics covered]
111
+
112
+ ## 1. Storage Location
113
+ [Agreements about where documentation lives]
114
+
115
+ ## 2. Programming Languages
116
+ [Agreements about languages and their usage]
117
+
118
+ ## 3. Code Quality Standards
119
+ [Agreements about what makes good code]
120
+
121
+ ## 4. Commit Message Conventions
122
+ [Agreements about commit message format]
123
+
124
+ ## 5. Integration Workflow
125
+ [Agreements about how code gets integrated]
126
+
127
+ ## 6. Testing Requirements
128
+ [Agreements about testing]
129
+
130
+ ## 7. Amendment Process
131
+ [Agreements about changing these agreements]
132
+
133
+ ## Additional Topics
134
+ [Any additional topics the team added]
135
+
136
+ ---
137
+ *Last updated: [date]*
138
+ *To amend these agreements, [process from amendment section]*
139
+ \`\`\`
140
+
141
+ ## Important
142
+
143
+ - Be conversational and collaborative
144
+ - ONE question at a time - don't overwhelm
145
+ - Respect the user's expertise and preferences
146
+ - If the user provides a specific request in their message, address that first
147
+ - The core topics are a starting point, not an exhaustive list
148
+ - Capture the "why" behind decisions, not just the "what"`;
149
+ /**
150
+ * Check if a file exists at the given path.
151
+ */
152
+ export async function fileExists(path) {
153
+ try {
154
+ await access(path);
155
+ return true;
156
+ }
157
+ catch {
158
+ return false;
159
+ }
160
+ }
161
+ /**
162
+ * Check if the gh CLI is installed and authenticated.
163
+ */
164
+ export async function isGhAvailable() {
165
+ try {
166
+ await execAsync("gh auth status");
167
+ return true;
168
+ }
169
+ catch {
170
+ return false;
171
+ }
172
+ }
173
+ /**
174
+ * Load team agreements from the project directory.
175
+ * Returns the content if found, null otherwise.
176
+ */
177
+ export async function loadTeamAgreements(directory) {
178
+ const defaultPath = join(directory, "docs", "TEAM_AGREEMENTS.md");
179
+ try {
180
+ const content = await readFile(defaultPath, "utf-8");
181
+ return `## Team Agreements\n\nThe following team agreements are in effect for this project:\n\n${content}`;
182
+ }
183
+ catch {
184
+ return null;
185
+ }
186
+ }
187
+ /**
188
+ * Format suggested questions as a markdown list.
189
+ */
190
+ export function formatQuestionsAsMarkdown(questions) {
191
+ return questions.map((q) => `- ${q}`).join("\n");
192
+ }
193
+ /**
194
+ * Build the issue body for a topic suggestion.
195
+ */
196
+ export function buildTopicIssueBody(args) {
197
+ const questionsFormatted = formatQuestionsAsMarkdown(args.suggested_questions);
198
+ return `## Topic Name
199
+ ${args.topic_name}
200
+
201
+ ## Description
202
+ ${args.description}
203
+
204
+ ## Suggested Questions
205
+ ${questionsFormatted}
206
+
207
+ ## Example Agreement
208
+ ${args.example_agreement || "_No example provided_"}
209
+
210
+ ## Additional Context
211
+ _This issue was automatically created via the team-agreements plugin._`;
212
+ }
213
+ // Export constants for testing
214
+ export { COMMAND_TEMPLATE, PLUGIN_REPO };
215
+ /**
216
+ * TeamAgreementsPlugin - Helps teams establish and maintain shared agreements
217
+ * for human-LLM collaboration on a codebase.
218
+ */
219
+ export const TeamAgreementsPlugin = async (ctx) => {
220
+ const { directory } = ctx;
221
+ const agreementsPath = "docs/TEAM_AGREEMENTS.md";
222
+ const fullAgreementsPath = join(directory, agreementsPath);
223
+ return {
224
+ /**
225
+ * Inject command definition and ensure agreements are in instructions
226
+ */
227
+ config: async (config) => {
228
+ // Add the /team-agreements command
229
+ if (!config.command) {
230
+ config.command = {};
231
+ }
232
+ config.command["team-agreements"] = {
233
+ description: "Establish or review team agreements for human-LLM collaboration",
234
+ template: COMMAND_TEMPLATE,
235
+ };
236
+ // If agreements file exists, ensure it's in instructions
237
+ if (await fileExists(fullAgreementsPath)) {
238
+ if (!config.instructions) {
239
+ config.instructions = [];
240
+ }
241
+ const instructions = config.instructions;
242
+ if (!instructions.includes(agreementsPath)) {
243
+ instructions.unshift(agreementsPath); // Add at beginning for priority
244
+ }
245
+ }
246
+ },
247
+ /**
248
+ * Custom tool to suggest a topic for the team-agreements plugin
249
+ */
250
+ tool: {
251
+ suggest_team_agreement_topic: tool({
252
+ description: "Suggest a new topic to be added to the team-agreements plugin. " +
253
+ "This will file a GitHub issue on the plugin repository. " +
254
+ "Requires the gh CLI to be installed and authenticated.",
255
+ args: {
256
+ topic_name: tool.schema
257
+ .string()
258
+ .describe("A short, descriptive name for the suggested topic"),
259
+ description: tool.schema
260
+ .string()
261
+ .describe("Why this topic is important for human-LLM collaboration and what it should cover"),
262
+ suggested_questions: tool.schema
263
+ .array(tool.schema.string())
264
+ .describe("List of questions that should be asked when establishing agreements for this topic"),
265
+ example_agreement: tool.schema
266
+ .string()
267
+ .optional()
268
+ .describe("Optional example of what a good agreement for this topic might look like"),
269
+ },
270
+ async execute(args) {
271
+ // Check if gh is available
272
+ if (!(await isGhAvailable())) {
273
+ return ("The gh CLI is not installed or not authenticated. " +
274
+ "Please install it from https://cli.github.com and run 'gh auth login', " +
275
+ "or manually file an issue at: " +
276
+ `https://github.com/${PLUGIN_REPO}/issues/new?template=topic-suggestion.md`);
277
+ }
278
+ const body = buildTopicIssueBody(args);
279
+ try {
280
+ const title = `[Topic] ${args.topic_name}`;
281
+ const { stdout } = await execAsync(`gh issue create --repo "${PLUGIN_REPO}" --title "${title.replace(/"/g, '\\"')}" --body "${body.replace(/"/g, '\\"').replace(/\n/g, "\\n")}" --label "enhancement,topic-suggestion"`);
282
+ return `Successfully created issue: ${stdout.trim()}`;
283
+ }
284
+ catch (error) {
285
+ return `Failed to create issue: ${error}. You can manually file one at: https://github.com/${PLUGIN_REPO}/issues/new?template=topic-suggestion.md`;
286
+ }
287
+ },
288
+ }),
289
+ },
290
+ /**
291
+ * Re-inject team agreements after context compaction.
292
+ * This ensures LLM agents maintain awareness of agreements
293
+ * even in long-running sessions.
294
+ */
295
+ "experimental.session.compacting": async (_input, output) => {
296
+ const agreements = await loadTeamAgreements(directory);
297
+ if (agreements) {
298
+ output.context.push(agreements);
299
+ }
300
+ },
301
+ };
302
+ };
303
+ export default TeamAgreementsPlugin;
304
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,246 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir, writeFile, rm } from "fs/promises";
3
+ import { join } from "path";
4
+ import { tmpdir } from "os";
5
+ import { fileExists, loadTeamAgreements, formatQuestionsAsMarkdown, buildTopicIssueBody, COMMAND_TEMPLATE, PLUGIN_REPO, TeamAgreementsPlugin, } from "./index.js";
6
+ describe("fileExists", () => {
7
+ const testDir = join(tmpdir(), "team-agreements-test-" + Date.now());
8
+ beforeEach(async () => {
9
+ await mkdir(testDir, { recursive: true });
10
+ });
11
+ afterEach(async () => {
12
+ await rm(testDir, { recursive: true, force: true });
13
+ });
14
+ it("returns true for existing file", async () => {
15
+ const filePath = join(testDir, "test.txt");
16
+ await writeFile(filePath, "test content");
17
+ expect(await fileExists(filePath)).toBe(true);
18
+ });
19
+ it("returns false for non-existing file", async () => {
20
+ const filePath = join(testDir, "non-existent.txt");
21
+ expect(await fileExists(filePath)).toBe(false);
22
+ });
23
+ it("returns true for existing directory", async () => {
24
+ expect(await fileExists(testDir)).toBe(true);
25
+ });
26
+ });
27
+ describe("loadTeamAgreements", () => {
28
+ const testDir = join(tmpdir(), "team-agreements-test-" + Date.now());
29
+ beforeEach(async () => {
30
+ await mkdir(join(testDir, "docs"), { recursive: true });
31
+ });
32
+ afterEach(async () => {
33
+ await rm(testDir, { recursive: true, force: true });
34
+ });
35
+ it("returns formatted content when agreements file exists", async () => {
36
+ const agreementsContent = "# My Team Agreements\n\nWe agree to be awesome.";
37
+ await writeFile(join(testDir, "docs", "TEAM_AGREEMENTS.md"), agreementsContent);
38
+ const result = await loadTeamAgreements(testDir);
39
+ expect(result).not.toBeNull();
40
+ expect(result).toContain("## Team Agreements");
41
+ expect(result).toContain("The following team agreements are in effect");
42
+ expect(result).toContain(agreementsContent);
43
+ });
44
+ it("returns null when agreements file does not exist", async () => {
45
+ const result = await loadTeamAgreements(testDir);
46
+ expect(result).toBeNull();
47
+ });
48
+ it("returns null when docs directory does not exist", async () => {
49
+ const emptyDir = join(tmpdir(), "empty-test-" + Date.now());
50
+ await mkdir(emptyDir, { recursive: true });
51
+ try {
52
+ const result = await loadTeamAgreements(emptyDir);
53
+ expect(result).toBeNull();
54
+ }
55
+ finally {
56
+ await rm(emptyDir, { recursive: true, force: true });
57
+ }
58
+ });
59
+ });
60
+ describe("formatQuestionsAsMarkdown", () => {
61
+ it("formats single question", () => {
62
+ const result = formatQuestionsAsMarkdown(["What is your name?"]);
63
+ expect(result).toBe("- What is your name?");
64
+ });
65
+ it("formats multiple questions", () => {
66
+ const result = formatQuestionsAsMarkdown([
67
+ "What is your name?",
68
+ "What is your quest?",
69
+ "What is your favorite color?",
70
+ ]);
71
+ expect(result).toBe("- What is your name?\n- What is your quest?\n- What is your favorite color?");
72
+ });
73
+ it("handles empty array", () => {
74
+ const result = formatQuestionsAsMarkdown([]);
75
+ expect(result).toBe("");
76
+ });
77
+ });
78
+ describe("buildTopicIssueBody", () => {
79
+ it("builds complete issue body with all fields", () => {
80
+ const result = buildTopicIssueBody({
81
+ topic_name: "Security Practices",
82
+ description: "How to handle security concerns",
83
+ suggested_questions: ["Do we need code scanning?", "What about secrets management?"],
84
+ example_agreement: "All PRs must pass security scans",
85
+ });
86
+ expect(result).toContain("## Topic Name");
87
+ expect(result).toContain("Security Practices");
88
+ expect(result).toContain("## Description");
89
+ expect(result).toContain("How to handle security concerns");
90
+ expect(result).toContain("## Suggested Questions");
91
+ expect(result).toContain("- Do we need code scanning?");
92
+ expect(result).toContain("- What about secrets management?");
93
+ expect(result).toContain("## Example Agreement");
94
+ expect(result).toContain("All PRs must pass security scans");
95
+ expect(result).toContain("automatically created via the team-agreements plugin");
96
+ });
97
+ it("handles missing example_agreement", () => {
98
+ const result = buildTopicIssueBody({
99
+ topic_name: "Test Topic",
100
+ description: "Test description",
101
+ suggested_questions: ["Question 1"],
102
+ });
103
+ expect(result).toContain("_No example provided_");
104
+ });
105
+ });
106
+ describe("COMMAND_TEMPLATE", () => {
107
+ it("contains required sections", () => {
108
+ expect(COMMAND_TEMPLATE).toContain("$ARGUMENTS");
109
+ expect(COMMAND_TEMPLATE).toContain("## Instructions");
110
+ expect(COMMAND_TEMPLATE).toContain("Storage Location");
111
+ expect(COMMAND_TEMPLATE).toContain("Programming Languages");
112
+ expect(COMMAND_TEMPLATE).toContain("Code Quality Standards");
113
+ expect(COMMAND_TEMPLATE).toContain("Commit Message Conventions");
114
+ expect(COMMAND_TEMPLATE).toContain("Integration Workflow");
115
+ expect(COMMAND_TEMPLATE).toContain("Testing Requirements");
116
+ expect(COMMAND_TEMPLATE).toContain("Amendment Process");
117
+ });
118
+ it("mentions the suggestion tool", () => {
119
+ expect(COMMAND_TEMPLATE).toContain("suggest_team_agreement_topic");
120
+ });
121
+ });
122
+ describe("PLUGIN_REPO", () => {
123
+ it("has correct value", () => {
124
+ expect(PLUGIN_REPO).toBe("jwilger/opencode-plugin-team-agreements");
125
+ });
126
+ });
127
+ describe("TeamAgreementsPlugin", () => {
128
+ const testDir = join(tmpdir(), "team-agreements-plugin-test-" + Date.now());
129
+ beforeEach(async () => {
130
+ await mkdir(join(testDir, "docs"), { recursive: true });
131
+ });
132
+ afterEach(async () => {
133
+ await rm(testDir, { recursive: true, force: true });
134
+ });
135
+ it("registers the team-agreements command via config hook", async () => {
136
+ const mockCtx = {
137
+ directory: testDir,
138
+ client: {},
139
+ project: {},
140
+ worktree: testDir,
141
+ serverUrl: new URL("http://localhost"),
142
+ $: {},
143
+ };
144
+ const hooks = await TeamAgreementsPlugin(mockCtx);
145
+ const config = {};
146
+ await hooks.config(config);
147
+ expect(config.command).toBeDefined();
148
+ expect(config.command["team-agreements"]).toBeDefined();
149
+ expect(config.command["team-agreements"].description).toContain("team agreements");
150
+ expect(config.command["team-agreements"].template).toBe(COMMAND_TEMPLATE);
151
+ });
152
+ it("adds agreements to instructions when file exists", async () => {
153
+ await writeFile(join(testDir, "docs", "TEAM_AGREEMENTS.md"), "# Agreements");
154
+ const mockCtx = {
155
+ directory: testDir,
156
+ client: {},
157
+ project: {},
158
+ worktree: testDir,
159
+ serverUrl: new URL("http://localhost"),
160
+ $: {},
161
+ };
162
+ const hooks = await TeamAgreementsPlugin(mockCtx);
163
+ const config = {};
164
+ await hooks.config(config);
165
+ expect(config.instructions).toBeDefined();
166
+ expect(config.instructions).toContain("docs/TEAM_AGREEMENTS.md");
167
+ });
168
+ it("does not add instructions when agreements file does not exist", async () => {
169
+ const mockCtx = {
170
+ directory: testDir,
171
+ client: {},
172
+ project: {},
173
+ worktree: testDir,
174
+ serverUrl: new URL("http://localhost"),
175
+ $: {},
176
+ };
177
+ const hooks = await TeamAgreementsPlugin(mockCtx);
178
+ const config = {};
179
+ await hooks.config(config);
180
+ expect(config.instructions).toBeUndefined();
181
+ });
182
+ it("does not duplicate instructions if already present", async () => {
183
+ await writeFile(join(testDir, "docs", "TEAM_AGREEMENTS.md"), "# Agreements");
184
+ const mockCtx = {
185
+ directory: testDir,
186
+ client: {},
187
+ project: {},
188
+ worktree: testDir,
189
+ serverUrl: new URL("http://localhost"),
190
+ $: {},
191
+ };
192
+ const hooks = await TeamAgreementsPlugin(mockCtx);
193
+ const config = {
194
+ instructions: ["docs/TEAM_AGREEMENTS.md", "other-file.md"],
195
+ };
196
+ await hooks.config(config);
197
+ const count = config.instructions.filter((i) => i === "docs/TEAM_AGREEMENTS.md").length;
198
+ expect(count).toBe(1);
199
+ });
200
+ it("provides compaction hook that injects agreements", async () => {
201
+ await writeFile(join(testDir, "docs", "TEAM_AGREEMENTS.md"), "# Test Agreements");
202
+ const mockCtx = {
203
+ directory: testDir,
204
+ client: {},
205
+ project: {},
206
+ worktree: testDir,
207
+ serverUrl: new URL("http://localhost"),
208
+ $: {},
209
+ };
210
+ const hooks = await TeamAgreementsPlugin(mockCtx);
211
+ const output = { context: [], prompt: undefined };
212
+ await hooks["experimental.session.compacting"]({ sessionID: "test" }, output);
213
+ expect(output.context.length).toBe(1);
214
+ expect(output.context[0]).toContain("Team Agreements");
215
+ expect(output.context[0]).toContain("# Test Agreements");
216
+ });
217
+ it("compaction hook does nothing when no agreements file", async () => {
218
+ const mockCtx = {
219
+ directory: testDir,
220
+ client: {},
221
+ project: {},
222
+ worktree: testDir,
223
+ serverUrl: new URL("http://localhost"),
224
+ $: {},
225
+ };
226
+ const hooks = await TeamAgreementsPlugin(mockCtx);
227
+ const output = { context: [], prompt: undefined };
228
+ await hooks["experimental.session.compacting"]({ sessionID: "test" }, output);
229
+ expect(output.context.length).toBe(0);
230
+ });
231
+ it("registers the suggest_team_agreement_topic tool", async () => {
232
+ const mockCtx = {
233
+ directory: testDir,
234
+ client: {},
235
+ project: {},
236
+ worktree: testDir,
237
+ serverUrl: new URL("http://localhost"),
238
+ $: {},
239
+ };
240
+ const hooks = await TeamAgreementsPlugin(mockCtx);
241
+ expect(hooks.tool).toBeDefined();
242
+ expect(hooks.tool.suggest_team_agreement_topic).toBeDefined();
243
+ expect(hooks.tool.suggest_team_agreement_topic.description).toContain("Suggest a new topic");
244
+ });
245
+ });
246
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAC3B,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,EACX,oBAAoB,GACrB,MAAM,YAAY,CAAA;AAEnB,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAEpE,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC1C,MAAM,SAAS,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAA;QAEzC,MAAM,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;QAElD,MAAM,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAChD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAEpE,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,iBAAiB,GAAG,iDAAiD,CAAA;QAC3E,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,iBAAiB,CAAC,CAAA;QAE/E,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAA;QAEhD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAA;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,6CAA6C,CAAC,CAAA;QACvE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAA;QAEhD,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC3B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QAC3D,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAE1C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAA;YACjD,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC3B,CAAC;gBAAS,CAAC;YACT,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACtD,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,MAAM,GAAG,yBAAyB,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAChE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,MAAM,GAAG,yBAAyB,CAAC;YACvC,oBAAoB;YACpB,qBAAqB;YACrB,8BAA8B;SAC/B,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CACjB,6EAA6E,CAC9E,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,MAAM,GAAG,yBAAyB,CAAC,EAAE,CAAC,CAAA;QAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,UAAU,EAAE,oBAAoB;YAChC,WAAW,EAAE,iCAAiC;YAC9C,mBAAmB,EAAE,CAAC,2BAA2B,EAAE,gCAAgC,CAAC;YACpF,iBAAiB,EAAE,kCAAkC;SACtD,CAAC,CAAA;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAA;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAA;QAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAA;QAC3D,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAA;QAClD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAA;QACvD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAA;QAC5D,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAA;QAC5D,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,sDAAsD,CAAC,CAAA;IAClF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,UAAU,EAAE,YAAY;YACxB,WAAW,EAAE,kBAAkB;YAC/B,mBAAmB,EAAE,CAAC,YAAY,CAAC;SACpC,CAAC,CAAA;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;QAChD,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;QACrD,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAA;QACtD,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAA;QAC3D,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAA;QAC5D,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAA;QAChE,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAA;QAC1D,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAA;QAC1D,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,8BAA8B,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAE3E,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,OAAO;YAClB,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,GAAG,CAAC,kBAAkB,CAAC;YACtC,CAAC,EAAE,EAAS;SACb,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAc,CAAC,CAAA;QACxD,MAAM,MAAM,GAAQ,EAAE,CAAA;QAEtB,MAAM,KAAK,CAAC,MAAO,CAAC,MAAM,CAAC,CAAA;QAE3B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;QACpC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;QACvD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;QAClF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,cAAc,CAAC,CAAA;QAE5E,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,OAAO;YAClB,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,GAAG,CAAC,kBAAkB,CAAC;YACtC,CAAC,EAAE,EAAS;SACb,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAc,CAAC,CAAA;QACxD,MAAM,MAAM,GAAQ,EAAE,CAAA;QAEtB,MAAM,KAAK,CAAC,MAAO,CAAC,MAAM,CAAC,CAAA;QAE3B,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAA;QACzC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAA;IAClE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,OAAO;YAClB,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,GAAG,CAAC,kBAAkB,CAAC;YACtC,CAAC,EAAE,EAAS;SACb,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAc,CAAC,CAAA;QACxD,MAAM,MAAM,GAAQ,EAAE,CAAA;QAEtB,MAAM,KAAK,CAAC,MAAO,CAAC,MAAM,CAAC,CAAA;QAE3B,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,aAAa,EAAE,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,cAAc,CAAC,CAAA;QAE5E,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,OAAO;YAClB,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,GAAG,CAAC,kBAAkB,CAAC;YACtC,CAAC,EAAE,EAAS;SACb,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAc,CAAC,CAAA;QACxD,MAAM,MAAM,GAAQ;YAClB,YAAY,EAAE,CAAC,yBAAyB,EAAE,eAAe,CAAC;SAC3D,CAAA;QAED,MAAM,KAAK,CAAC,MAAO,CAAC,MAAM,CAAC,CAAA;QAE3B,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CACtC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,yBAAyB,CAC/C,CAAC,MAAM,CAAA;QACR,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,mBAAmB,CAAC,CAAA;QAEjF,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,OAAO;YAClB,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,GAAG,CAAC,kBAAkB,CAAC;YACtC,CAAC,EAAE,EAAS;SACb,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAc,CAAC,CAAA;QACxD,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,EAAc,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QAE7D,MAAM,KAAK,CAAC,iCAAiC,CAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,CAAA;QAE9E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;QACtD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,OAAO;YAClB,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,GAAG,CAAC,kBAAkB,CAAC;YACtC,CAAC,EAAE,EAAS;SACb,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAc,CAAC,CAAA;QACxD,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,EAAc,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QAE7D,MAAM,KAAK,CAAC,iCAAiC,CAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,CAAA;QAE9E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,OAAO;YAClB,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,GAAG,CAAC,kBAAkB,CAAC;YACtC,CAAC,EAAE,EAAS;SACb,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAc,CAAC,CAAA;QAExD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;QAChC,MAAM,CAAC,KAAK,CAAC,IAAK,CAAC,4BAA4B,CAAC,CAAC,WAAW,EAAE,CAAA;QAC9D,MAAM,CAAC,KAAK,CAAC,IAAK,CAAC,4BAA4B,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAA;IAC/F,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "opencode-plugin-team-agreements",
3
+ "version": "0.1.0",
4
+ "description": "OpenCode plugin for establishing and maintaining team agreements for human-LLM collaboration",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "CHANGELOG.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "clean": "rm -rf dist",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "prepublishOnly": "npm run clean && npm run build"
20
+ },
21
+ "keywords": [
22
+ "opencode",
23
+ "plugin",
24
+ "team-agreements",
25
+ "collaboration",
26
+ "llm",
27
+ "ai",
28
+ "developer-tools"
29
+ ],
30
+ "author": "John Wilger",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/jwilger/opencode-plugin-team-agreements.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/jwilger/opencode-plugin-team-agreements/issues"
38
+ },
39
+ "homepage": "https://github.com/jwilger/opencode-plugin-team-agreements#readme",
40
+ "devDependencies": {
41
+ "@opencode-ai/plugin": "^1.0.0",
42
+ "@types/node": "^25.0.10",
43
+ "typescript": "^5.0.0",
44
+ "vitest": "^4.0.18"
45
+ },
46
+ "peerDependencies": {
47
+ "@opencode-ai/plugin": "^1.0.0"
48
+ }
49
+ }