opencode-conductor-cdd-plugin 1.0.0-beta.13

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.
Files changed (91) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +163 -0
  3. package/README.test.md +51 -0
  4. package/dist/commands/implement.d.ts +1 -0
  5. package/dist/commands/implement.js +30 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +108 -0
  8. package/dist/index.test.d.ts +1 -0
  9. package/dist/index.test.js +122 -0
  10. package/dist/prompts/agent/cdd.md +41 -0
  11. package/dist/prompts/agent/implementer.md +22 -0
  12. package/dist/prompts/agent.md +23 -0
  13. package/dist/prompts/cdd/implement.json +4 -0
  14. package/dist/prompts/cdd/newTrack.json +4 -0
  15. package/dist/prompts/cdd/revert.json +4 -0
  16. package/dist/prompts/cdd/setup.json +4 -0
  17. package/dist/prompts/cdd/setup.test.d.ts +1 -0
  18. package/dist/prompts/cdd/setup.test.js +132 -0
  19. package/dist/prompts/cdd/setup.test.ts +168 -0
  20. package/dist/prompts/cdd/status.json +4 -0
  21. package/dist/prompts/strategies/delegate.md +11 -0
  22. package/dist/prompts/strategies/manual.md +9 -0
  23. package/dist/templates/code_styleguides/c.md +28 -0
  24. package/dist/templates/code_styleguides/cpp.md +46 -0
  25. package/dist/templates/code_styleguides/csharp.md +115 -0
  26. package/dist/templates/code_styleguides/dart.md +238 -0
  27. package/dist/templates/code_styleguides/general.md +23 -0
  28. package/dist/templates/code_styleguides/go.md +48 -0
  29. package/dist/templates/code_styleguides/html-css.md +49 -0
  30. package/dist/templates/code_styleguides/java.md +39 -0
  31. package/dist/templates/code_styleguides/javascript.md +51 -0
  32. package/dist/templates/code_styleguides/julia.md +27 -0
  33. package/dist/templates/code_styleguides/kotlin.md +41 -0
  34. package/dist/templates/code_styleguides/php.md +37 -0
  35. package/dist/templates/code_styleguides/python.md +37 -0
  36. package/dist/templates/code_styleguides/react.md +37 -0
  37. package/dist/templates/code_styleguides/ruby.md +39 -0
  38. package/dist/templates/code_styleguides/rust.md +44 -0
  39. package/dist/templates/code_styleguides/shell.md +35 -0
  40. package/dist/templates/code_styleguides/solidity.md +60 -0
  41. package/dist/templates/code_styleguides/sql.md +39 -0
  42. package/dist/templates/code_styleguides/swift.md +36 -0
  43. package/dist/templates/code_styleguides/typescript.md +43 -0
  44. package/dist/templates/code_styleguides/vue.md +38 -0
  45. package/dist/templates/code_styleguides/zig.md +27 -0
  46. package/dist/templates/workflow.md +336 -0
  47. package/dist/tools/background.d.ts +54 -0
  48. package/dist/tools/background.js +198 -0
  49. package/dist/tools/commands.d.ts +11 -0
  50. package/dist/tools/commands.js +80 -0
  51. package/dist/tools/commands.test.d.ts +1 -0
  52. package/dist/tools/commands.test.js +142 -0
  53. package/dist/tools/delegate.d.ts +3 -0
  54. package/dist/tools/delegate.js +45 -0
  55. package/dist/utils/autogenerateFlow.d.ts +65 -0
  56. package/dist/utils/autogenerateFlow.js +391 -0
  57. package/dist/utils/autogenerateFlow.test.d.ts +1 -0
  58. package/dist/utils/autogenerateFlow.test.js +610 -0
  59. package/dist/utils/bootstrap.d.ts +1 -0
  60. package/dist/utils/bootstrap.js +46 -0
  61. package/dist/utils/commandFactory.d.ts +11 -0
  62. package/dist/utils/commandFactory.js +69 -0
  63. package/dist/utils/commitMessages.d.ts +35 -0
  64. package/dist/utils/commitMessages.js +33 -0
  65. package/dist/utils/commitMessages.test.d.ts +1 -0
  66. package/dist/utils/commitMessages.test.js +79 -0
  67. package/dist/utils/configDetection.d.ts +7 -0
  68. package/dist/utils/configDetection.js +49 -0
  69. package/dist/utils/configDetection.test.d.ts +1 -0
  70. package/dist/utils/configDetection.test.js +119 -0
  71. package/dist/utils/contentGeneration.d.ts +10 -0
  72. package/dist/utils/contentGeneration.js +141 -0
  73. package/dist/utils/contentGeneration.test.d.ts +1 -0
  74. package/dist/utils/contentGeneration.test.js +147 -0
  75. package/dist/utils/contextAnalysis.d.ts +100 -0
  76. package/dist/utils/contextAnalysis.js +308 -0
  77. package/dist/utils/contextAnalysis.test.d.ts +1 -0
  78. package/dist/utils/contextAnalysis.test.js +307 -0
  79. package/dist/utils/gitNotes.d.ts +23 -0
  80. package/dist/utils/gitNotes.js +53 -0
  81. package/dist/utils/gitNotes.test.d.ts +1 -0
  82. package/dist/utils/gitNotes.test.js +105 -0
  83. package/dist/utils/ignoreMatcher.d.ts +9 -0
  84. package/dist/utils/ignoreMatcher.js +77 -0
  85. package/dist/utils/ignoreMatcher.test.d.ts +1 -0
  86. package/dist/utils/ignoreMatcher.test.js +126 -0
  87. package/dist/utils/stateManager.d.ts +10 -0
  88. package/dist/utils/stateManager.js +30 -0
  89. package/package.json +90 -0
  90. package/scripts/convert-legacy.cjs +17 -0
  91. package/scripts/postinstall.cjs +38 -0
@@ -0,0 +1,126 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildIgnoreMatcher } from "./ignoreMatcher.js";
3
+ describe("ignoreMatcher", () => {
4
+ it("should always ignore .git directory", () => {
5
+ const matcher = buildIgnoreMatcher("/root", { gitignore: [], ignore: [], geminiignore: [] });
6
+ expect(matcher.ignores(".git")).toBe(true);
7
+ expect(matcher.ignores(".git/config")).toBe(true);
8
+ expect(matcher.ignores("src/.git")).toBe(true);
9
+ });
10
+ it("should always ignore node_modules directory", () => {
11
+ const matcher = buildIgnoreMatcher("/root", { gitignore: [], ignore: [], geminiignore: [] });
12
+ expect(matcher.ignores("node_modules")).toBe(true);
13
+ expect(matcher.ignores("node_modules/package/index.js")).toBe(true);
14
+ expect(matcher.ignores("src/node_modules")).toBe(true);
15
+ });
16
+ it("should always ignore .DS_Store", () => {
17
+ const matcher = buildIgnoreMatcher("/root", { gitignore: [], ignore: [], geminiignore: [] });
18
+ expect(matcher.ignores(".DS_Store")).toBe(true);
19
+ expect(matcher.ignores("src/.DS_Store")).toBe(true);
20
+ });
21
+ it("should ignore patterns from gitignore", () => {
22
+ const matcher = buildIgnoreMatcher("/root", {
23
+ gitignore: ["dist", "*.log"],
24
+ ignore: [],
25
+ geminiignore: []
26
+ });
27
+ expect(matcher.ignores("dist")).toBe(true);
28
+ expect(matcher.ignores("dist/index.js")).toBe(true);
29
+ expect(matcher.ignores("error.log")).toBe(true);
30
+ expect(matcher.ignores("src/app.ts")).toBe(false);
31
+ });
32
+ it("should support negation patterns with !", () => {
33
+ const matcher = buildIgnoreMatcher("/root", {
34
+ gitignore: ["conductor-cdd/"],
35
+ ignore: ["!conductor-cdd/tracks/"],
36
+ geminiignore: []
37
+ });
38
+ // conductor-cdd/ is ignored by gitignore
39
+ expect(matcher.ignores("conductor-cdd")).toBe(true);
40
+ expect(matcher.ignores("conductor-cdd/guidelines.md")).toBe(true);
41
+ // But conductor-cdd/tracks/ is allowed by negation in .ignore
42
+ expect(matcher.ignores("conductor-cdd/tracks")).toBe(false);
43
+ expect(matcher.ignores("conductor-cdd/tracks/plan.md")).toBe(false);
44
+ });
45
+ it("should allow traversal when a descendant is allowlisted", () => {
46
+ const matcher = buildIgnoreMatcher("/root", {
47
+ gitignore: ["conductor-cdd/"],
48
+ ignore: ["!conductor-cdd/tracks/"],
49
+ geminiignore: []
50
+ });
51
+ expect(matcher.shouldTraverse("conductor-cdd")).toBe(true);
52
+ expect(matcher.shouldTraverse("conductor-cdd/tracks")).toBe(true);
53
+ expect(matcher.shouldTraverse("conductor-cdd/docs")).toBe(false);
54
+ });
55
+ it("should handle directory-specific patterns", () => {
56
+ const matcher = buildIgnoreMatcher("/root", {
57
+ gitignore: ["logs/"],
58
+ ignore: [],
59
+ geminiignore: []
60
+ });
61
+ expect(matcher.ignores("logs")).toBe(true);
62
+ expect(matcher.ignores("logs/test.log")).toBe(true);
63
+ expect(matcher.ignores("catalogs/item.txt")).toBe(false);
64
+ });
65
+ it("should prioritize negation over ignore", () => {
66
+ const matcher = buildIgnoreMatcher("/root", {
67
+ gitignore: ["*"],
68
+ ignore: ["!src/"],
69
+ geminiignore: []
70
+ });
71
+ expect(matcher.ignores("README.md")).toBe(true);
72
+ expect(matcher.ignores("src")).toBe(false);
73
+ expect(matcher.ignores("src/index.ts")).toBe(false);
74
+ });
75
+ it("should handle comments and empty lines in ignore files", () => {
76
+ const matcher = buildIgnoreMatcher("/root", {
77
+ gitignore: ["# This is a comment", "", " ", "dist"],
78
+ ignore: [],
79
+ geminiignore: []
80
+ });
81
+ expect(matcher.ignores("dist")).toBe(true);
82
+ expect(matcher.ignores("src")).toBe(false);
83
+ });
84
+ it("should support **/ prefix for any depth matching", () => {
85
+ const matcher = buildIgnoreMatcher("/root", {
86
+ gitignore: ["**/temp"],
87
+ ignore: [],
88
+ geminiignore: []
89
+ });
90
+ expect(matcher.ignores("temp")).toBe(true);
91
+ expect(matcher.ignores("src/temp")).toBe(true);
92
+ expect(matcher.ignores("src/nested/temp")).toBe(true);
93
+ expect(matcher.ignores("src/temporary")).toBe(false);
94
+ });
95
+ it("should support **/* suffix for recursive file matching", () => {
96
+ const matcher = buildIgnoreMatcher("/root", {
97
+ gitignore: ["logs/**/*"],
98
+ ignore: [],
99
+ geminiignore: []
100
+ });
101
+ expect(matcher.ignores("logs/error.log")).toBe(true);
102
+ expect(matcher.ignores("logs/nested/debug.log")).toBe(true);
103
+ expect(matcher.ignores("logs")).toBe(false);
104
+ expect(matcher.ignores("other/error.log")).toBe(false);
105
+ });
106
+ it("should support middle ** for any depth matching", () => {
107
+ const matcher = buildIgnoreMatcher("/root", {
108
+ gitignore: ["src/**/test"],
109
+ ignore: [],
110
+ geminiignore: []
111
+ });
112
+ expect(matcher.ignores("src/test")).toBe(true);
113
+ expect(matcher.ignores("src/nested/test")).toBe(true);
114
+ expect(matcher.ignores("src/very/deeply/nested/test")).toBe(true);
115
+ expect(matcher.ignores("other/test")).toBe(false);
116
+ });
117
+ it("should differentiate trailing slash for directories only", () => {
118
+ const matcher = buildIgnoreMatcher("/root", {
119
+ gitignore: ["build/"],
120
+ ignore: [],
121
+ geminiignore: []
122
+ });
123
+ expect(matcher.ignores("build")).toBe(true);
124
+ expect(matcher.ignores("build/output.js")).toBe(true);
125
+ });
126
+ });
@@ -0,0 +1,10 @@
1
+ export interface SetupState {
2
+ last_successful_step: string;
3
+ }
4
+ export declare class StateManager {
5
+ private statePath;
6
+ constructor(workDir: string);
7
+ ensureCDDDir(): void;
8
+ readState(): SetupState;
9
+ writeState(step: string): void;
10
+ }
@@ -0,0 +1,30 @@
1
+ import { join } from "path";
2
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
3
+ export class StateManager {
4
+ statePath;
5
+ constructor(workDir) {
6
+ this.statePath = join(workDir, "conductor-cdd", "setup_state.json");
7
+ }
8
+ ensureCDDDir() {
9
+ const dir = join(this.statePath, "..");
10
+ if (!existsSync(dir)) {
11
+ mkdirSync(dir, { recursive: true });
12
+ }
13
+ }
14
+ readState() {
15
+ if (!existsSync(this.statePath)) {
16
+ return { last_successful_step: "" };
17
+ }
18
+ try {
19
+ return JSON.parse(readFileSync(this.statePath, "utf-8"));
20
+ }
21
+ catch (e) {
22
+ return { last_successful_step: "" };
23
+ }
24
+ }
25
+ writeState(step) {
26
+ this.ensureCDDDir();
27
+ const state = { last_successful_step: step };
28
+ writeFileSync(this.statePath, JSON.stringify(state, null, 2));
29
+ }
30
+ }
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "opencode-conductor-cdd-plugin",
3
+ "version": "1.0.0-beta.13",
4
+ "description": "Context-Driven Development (CDD) plugin for OpenCode - Transform your AI coding workflow with structured specifications, plans, and implementation tracking",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/fparrav/opencode-conductor-cdd.git"
9
+ },
10
+ "keywords": [
11
+ "opencode",
12
+ "plugin",
13
+ "conductor",
14
+ "cdd",
15
+ "context-driven-development",
16
+ "agent",
17
+ "ai-workflow"
18
+ ],
19
+ "author": "Derek Barrera",
20
+ "license": "Apache-2.0",
21
+ "bugs": {
22
+ "url": "https://github.com/fparrav/opencode-conductor-cdd/issues"
23
+ },
24
+ "homepage": "https://github.com/fparrav/opencode-conductor-cdd#readme",
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "registry": "https://registry.npmjs.org/",
28
+ "provenance": false
29
+ },
30
+ "main": "dist/index.js",
31
+ "types": "dist/index.d.ts",
32
+ "files": [
33
+ "dist",
34
+ "scripts"
35
+ ],
36
+ "scripts": {
37
+ "test": "vitest run",
38
+ "postinstall": "node scripts/postinstall.cjs",
39
+ "build": "rm -rf dist && npm run verify-prompts && tsc && npm run copy-assets",
40
+ "verify-prompts": "node scripts/convert-legacy.cjs",
41
+ "copy-assets": "mkdir -p dist/templates && cp -r src/templates/* dist/templates/ && mkdir -p dist/prompts && cp -r src/prompts/* dist/prompts/",
42
+ "prepublishOnly": "npm run build"
43
+ },
44
+ "dependencies": {
45
+ "@opencode-ai/plugin": "1.0.223",
46
+ "smol-toml": "^1.6.0"
47
+ },
48
+ "devDependencies": {
49
+ "@semantic-release/changelog": "^6.0.3",
50
+ "@semantic-release/commit-analyzer": "^13.0.0",
51
+ "@semantic-release/git": "^10.0.1",
52
+ "@semantic-release/github": "^11.0.1",
53
+ "@semantic-release/npm": "^12.0.1",
54
+ "@semantic-release/release-notes-generator": "^14.0.0",
55
+ "@types/node": "^20.0.0",
56
+ "semantic-release": "^24.2.1",
57
+ "typescript": "^5.0.0",
58
+ "vitest": "^4.0.16"
59
+ },
60
+ "release": {
61
+ "branches": [
62
+ "main"
63
+ ],
64
+ "repositoryUrl": "https://github.com/fparrav/opencode-conductor-cdd",
65
+ "plugins": [
66
+ "@semantic-release/commit-analyzer",
67
+ "@semantic-release/release-notes-generator",
68
+ "@semantic-release/changelog",
69
+ [
70
+ "@semantic-release/npm",
71
+ {
72
+ "npmPublish": false,
73
+ "tarballDir": "dist-npm"
74
+ }
75
+ ],
76
+ [
77
+ "@semantic-release/git",
78
+ {
79
+ "assets": [
80
+ "package.json",
81
+ "package-lock.json",
82
+ "CHANGELOG.md"
83
+ ],
84
+ "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
85
+ }
86
+ ],
87
+ "@semantic-release/github"
88
+ ]
89
+ }
90
+ }
@@ -0,0 +1,17 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const destDir = path.join(__dirname, '../src/prompts/cdd');
5
+
6
+ if (!fs.existsSync(destDir)) {
7
+ console.error('Missing cdd prompts directory.');
8
+ process.exit(1);
9
+ }
10
+
11
+ const files = fs.readdirSync(destDir).filter(file => file.endsWith('.json'));
12
+ if (files.length === 0) {
13
+ console.error('No cdd prompt JSON files found.');
14
+ process.exit(1);
15
+ }
16
+
17
+ console.log(`Found ${files.length} cdd prompt JSON files.`);
@@ -0,0 +1,38 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ const home = os.homedir();
6
+ const opencodeConfigDir = path.join(home, '.config', 'opencode');
7
+ const targetAgentDir = path.join(opencodeConfigDir, 'agent');
8
+ const targetCommandDir = path.join(opencodeConfigDir, 'command');
9
+
10
+ const sourcePromptsDir = path.join(__dirname, '..', 'dist', 'prompts');
11
+ const sourceAgentFile = path.join(sourcePromptsDir, 'agent', 'orchestrator.md');
12
+ const sourceCommandsDir = path.join(sourcePromptsDir, 'commands');
13
+
14
+ function ensureDir(dir) {
15
+ if (!fs.existsSync(dir)) {
16
+ fs.mkdirSync(dir, { recursive: true });
17
+ }
18
+ }
19
+
20
+ try {
21
+ ensureDir(targetAgentDir);
22
+ ensureDir(targetCommandDir);
23
+
24
+ if (fs.existsSync(sourceAgentFile)) {
25
+ fs.copyFileSync(sourceAgentFile, path.join(targetAgentDir, 'orchestrator.md'));
26
+ console.log('[Orchestrator] Installed agent definition.');
27
+ }
28
+
29
+ if (fs.existsSync(sourceCommandsDir)) {
30
+ const commands = fs.readdirSync(sourceCommandsDir);
31
+ for (const cmdFile of commands) {
32
+ fs.copyFileSync(path.join(sourceCommandsDir, cmdFile), path.join(targetCommandDir, cmdFile));
33
+ }
34
+ console.log('[Orchestrator] Installed slash commands.');
35
+ }
36
+ } catch (err) {
37
+ console.error('[Orchestrator] Setup failed:', err.message);
38
+ }