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.
- package/LICENSE +202 -0
- package/README.md +163 -0
- package/README.test.md +51 -0
- package/dist/commands/implement.d.ts +1 -0
- package/dist/commands/implement.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +108 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +122 -0
- package/dist/prompts/agent/cdd.md +41 -0
- package/dist/prompts/agent/implementer.md +22 -0
- package/dist/prompts/agent.md +23 -0
- package/dist/prompts/cdd/implement.json +4 -0
- package/dist/prompts/cdd/newTrack.json +4 -0
- package/dist/prompts/cdd/revert.json +4 -0
- package/dist/prompts/cdd/setup.json +4 -0
- package/dist/prompts/cdd/setup.test.d.ts +1 -0
- package/dist/prompts/cdd/setup.test.js +132 -0
- package/dist/prompts/cdd/setup.test.ts +168 -0
- package/dist/prompts/cdd/status.json +4 -0
- package/dist/prompts/strategies/delegate.md +11 -0
- package/dist/prompts/strategies/manual.md +9 -0
- package/dist/templates/code_styleguides/c.md +28 -0
- package/dist/templates/code_styleguides/cpp.md +46 -0
- package/dist/templates/code_styleguides/csharp.md +115 -0
- package/dist/templates/code_styleguides/dart.md +238 -0
- package/dist/templates/code_styleguides/general.md +23 -0
- package/dist/templates/code_styleguides/go.md +48 -0
- package/dist/templates/code_styleguides/html-css.md +49 -0
- package/dist/templates/code_styleguides/java.md +39 -0
- package/dist/templates/code_styleguides/javascript.md +51 -0
- package/dist/templates/code_styleguides/julia.md +27 -0
- package/dist/templates/code_styleguides/kotlin.md +41 -0
- package/dist/templates/code_styleguides/php.md +37 -0
- package/dist/templates/code_styleguides/python.md +37 -0
- package/dist/templates/code_styleguides/react.md +37 -0
- package/dist/templates/code_styleguides/ruby.md +39 -0
- package/dist/templates/code_styleguides/rust.md +44 -0
- package/dist/templates/code_styleguides/shell.md +35 -0
- package/dist/templates/code_styleguides/solidity.md +60 -0
- package/dist/templates/code_styleguides/sql.md +39 -0
- package/dist/templates/code_styleguides/swift.md +36 -0
- package/dist/templates/code_styleguides/typescript.md +43 -0
- package/dist/templates/code_styleguides/vue.md +38 -0
- package/dist/templates/code_styleguides/zig.md +27 -0
- package/dist/templates/workflow.md +336 -0
- package/dist/tools/background.d.ts +54 -0
- package/dist/tools/background.js +198 -0
- package/dist/tools/commands.d.ts +11 -0
- package/dist/tools/commands.js +80 -0
- package/dist/tools/commands.test.d.ts +1 -0
- package/dist/tools/commands.test.js +142 -0
- package/dist/tools/delegate.d.ts +3 -0
- package/dist/tools/delegate.js +45 -0
- package/dist/utils/autogenerateFlow.d.ts +65 -0
- package/dist/utils/autogenerateFlow.js +391 -0
- package/dist/utils/autogenerateFlow.test.d.ts +1 -0
- package/dist/utils/autogenerateFlow.test.js +610 -0
- package/dist/utils/bootstrap.d.ts +1 -0
- package/dist/utils/bootstrap.js +46 -0
- package/dist/utils/commandFactory.d.ts +11 -0
- package/dist/utils/commandFactory.js +69 -0
- package/dist/utils/commitMessages.d.ts +35 -0
- package/dist/utils/commitMessages.js +33 -0
- package/dist/utils/commitMessages.test.d.ts +1 -0
- package/dist/utils/commitMessages.test.js +79 -0
- package/dist/utils/configDetection.d.ts +7 -0
- package/dist/utils/configDetection.js +49 -0
- package/dist/utils/configDetection.test.d.ts +1 -0
- package/dist/utils/configDetection.test.js +119 -0
- package/dist/utils/contentGeneration.d.ts +10 -0
- package/dist/utils/contentGeneration.js +141 -0
- package/dist/utils/contentGeneration.test.d.ts +1 -0
- package/dist/utils/contentGeneration.test.js +147 -0
- package/dist/utils/contextAnalysis.d.ts +100 -0
- package/dist/utils/contextAnalysis.js +308 -0
- package/dist/utils/contextAnalysis.test.d.ts +1 -0
- package/dist/utils/contextAnalysis.test.js +307 -0
- package/dist/utils/gitNotes.d.ts +23 -0
- package/dist/utils/gitNotes.js +53 -0
- package/dist/utils/gitNotes.test.d.ts +1 -0
- package/dist/utils/gitNotes.test.js +105 -0
- package/dist/utils/ignoreMatcher.d.ts +9 -0
- package/dist/utils/ignoreMatcher.js +77 -0
- package/dist/utils/ignoreMatcher.test.d.ts +1 -0
- package/dist/utils/ignoreMatcher.test.js +126 -0
- package/dist/utils/stateManager.d.ts +10 -0
- package/dist/utils/stateManager.js +30 -0
- package/package.json +90 -0
- package/scripts/convert-legacy.cjs +17 -0
- 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,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
|
+
}
|