@doingdev/opencode-claude-manager-plugin 0.1.21 → 0.1.25
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 +129 -40
- package/dist/claude/claude-agent-sdk-adapter.d.ts +27 -0
- package/dist/claude/claude-agent-sdk-adapter.js +520 -0
- package/dist/claude/claude-session.service.d.ts +15 -0
- package/dist/claude/claude-session.service.js +23 -0
- package/dist/claude/session-live-tailer.d.ts +51 -0
- package/dist/claude/session-live-tailer.js +269 -0
- package/dist/claude/tool-approval-manager.d.ts +27 -0
- package/dist/claude/tool-approval-manager.js +238 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -5
- package/dist/manager/context-tracker.d.ts +33 -0
- package/dist/manager/context-tracker.js +108 -0
- package/dist/manager/git-operations.d.ts +12 -0
- package/dist/manager/git-operations.js +76 -0
- package/dist/manager/persistent-manager.d.ts +74 -0
- package/dist/manager/persistent-manager.js +167 -0
- package/dist/manager/session-controller.d.ts +45 -0
- package/dist/manager/session-controller.js +147 -0
- package/dist/metadata/claude-metadata.service.d.ts +12 -0
- package/dist/metadata/claude-metadata.service.js +38 -0
- package/dist/metadata/repo-claude-config-reader.d.ts +7 -0
- package/dist/metadata/repo-claude-config-reader.js +154 -0
- package/dist/plugin/claude-manager.plugin.d.ts +2 -0
- package/dist/plugin/claude-manager.plugin.js +627 -0
- package/dist/plugin/orchestrator.plugin.d.ts +0 -12
- package/dist/plugin/orchestrator.plugin.js +12 -4
- package/dist/plugin/service-factory.d.ts +12 -0
- package/dist/plugin/service-factory.js +41 -0
- package/dist/prompts/registry.d.ts +2 -8
- package/dist/prompts/registry.js +159 -30
- package/dist/providers/claude-code-wrapper.d.ts +13 -0
- package/dist/providers/claude-code-wrapper.js +13 -0
- package/dist/state/file-run-state-store.d.ts +14 -0
- package/dist/state/file-run-state-store.js +87 -0
- package/dist/state/transcript-store.d.ts +15 -0
- package/dist/state/transcript-store.js +44 -0
- package/dist/types/contracts.d.ts +215 -0
- package/dist/types/contracts.js +1 -0
- package/dist/util/fs-helpers.d.ts +2 -0
- package/dist/util/fs-helpers.js +12 -0
- package/dist/util/transcript-append.d.ts +7 -0
- package/dist/util/transcript-append.js +29 -0
- package/package.json +6 -3
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import JSON5 from 'json5';
|
|
4
|
+
export class RepoClaudeConfigReader {
|
|
5
|
+
async read(cwd) {
|
|
6
|
+
const claudeDirectory = path.join(cwd, '.claude');
|
|
7
|
+
const skillsDirectory = path.join(claudeDirectory, 'skills');
|
|
8
|
+
const commandsDirectory = path.join(claudeDirectory, 'commands');
|
|
9
|
+
const claudeMdCandidates = [
|
|
10
|
+
path.join(cwd, 'CLAUDE.md'),
|
|
11
|
+
path.join(claudeDirectory, 'CLAUDE.md'),
|
|
12
|
+
];
|
|
13
|
+
const collectedAt = new Date().toISOString();
|
|
14
|
+
const [skills, commands, settingsResult, claudeMdPath] = await Promise.all([
|
|
15
|
+
this.readSkills(skillsDirectory),
|
|
16
|
+
this.readCommands(commandsDirectory),
|
|
17
|
+
this.readSettings(claudeDirectory),
|
|
18
|
+
findFirstExistingPath(claudeMdCandidates),
|
|
19
|
+
]);
|
|
20
|
+
return {
|
|
21
|
+
collectedAt,
|
|
22
|
+
cwd,
|
|
23
|
+
commands: [...skillsToCommands(skills), ...commands],
|
|
24
|
+
skills,
|
|
25
|
+
hooks: settingsResult.hooks,
|
|
26
|
+
agents: [],
|
|
27
|
+
claudeMdPath: claudeMdPath ?? undefined,
|
|
28
|
+
settingsPaths: settingsResult.settingsPaths,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async readSkills(directory) {
|
|
32
|
+
if (!(await pathExists(directory))) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
36
|
+
const skills = await Promise.all(entries
|
|
37
|
+
.filter((entry) => entry.isDirectory())
|
|
38
|
+
.map(async (entry) => {
|
|
39
|
+
const skillPath = path.join(directory, entry.name, 'SKILL.md');
|
|
40
|
+
if (!(await pathExists(skillPath))) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const content = await fs.readFile(skillPath, 'utf8');
|
|
44
|
+
return {
|
|
45
|
+
name: entry.name,
|
|
46
|
+
description: extractMarkdownDescription(content),
|
|
47
|
+
path: skillPath,
|
|
48
|
+
source: 'skill',
|
|
49
|
+
};
|
|
50
|
+
}));
|
|
51
|
+
return skills.filter((skill) => skill !== null);
|
|
52
|
+
}
|
|
53
|
+
async readCommands(directory) {
|
|
54
|
+
if (!(await pathExists(directory))) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const commandFiles = await collectMarkdownFiles(directory);
|
|
58
|
+
const commands = await Promise.all(commandFiles.map(async (commandPath) => {
|
|
59
|
+
const content = await fs.readFile(commandPath, 'utf8');
|
|
60
|
+
return {
|
|
61
|
+
name: path.basename(commandPath, path.extname(commandPath)),
|
|
62
|
+
description: extractMarkdownDescription(content),
|
|
63
|
+
source: 'command',
|
|
64
|
+
path: commandPath,
|
|
65
|
+
};
|
|
66
|
+
}));
|
|
67
|
+
return commands.sort((left, right) => left.name.localeCompare(right.name));
|
|
68
|
+
}
|
|
69
|
+
async readSettings(claudeDirectory) {
|
|
70
|
+
const candidatePaths = [
|
|
71
|
+
path.join(claudeDirectory, 'settings.json'),
|
|
72
|
+
path.join(claudeDirectory, 'settings.local.json'),
|
|
73
|
+
];
|
|
74
|
+
const settingsPaths = [];
|
|
75
|
+
const hooks = [];
|
|
76
|
+
for (const candidatePath of candidatePaths) {
|
|
77
|
+
if (!(await pathExists(candidatePath))) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
settingsPaths.push(candidatePath);
|
|
81
|
+
const content = await fs.readFile(candidatePath, 'utf8');
|
|
82
|
+
const parsed = JSON5.parse(content);
|
|
83
|
+
const hookEntries = Object.entries(parsed.hooks ?? {});
|
|
84
|
+
for (const [hookName, hookValue] of hookEntries) {
|
|
85
|
+
const hookMatchers = Array.isArray(hookValue) ? hookValue : [hookValue];
|
|
86
|
+
for (const hookMatcher of hookMatchers) {
|
|
87
|
+
if (!hookMatcher || typeof hookMatcher !== 'object') {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const matcher = typeof hookMatcher.matcher === 'string'
|
|
91
|
+
? hookMatcher.matcher
|
|
92
|
+
: undefined;
|
|
93
|
+
const commandCount = Array.isArray(hookMatcher.hooks)
|
|
94
|
+
? (hookMatcher.hooks?.length ?? 0)
|
|
95
|
+
: 0;
|
|
96
|
+
hooks.push({
|
|
97
|
+
name: hookName,
|
|
98
|
+
matcher,
|
|
99
|
+
sourcePath: candidatePath,
|
|
100
|
+
commandCount,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
settingsPaths,
|
|
107
|
+
hooks,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function extractMarkdownDescription(markdown) {
|
|
112
|
+
const lines = markdown
|
|
113
|
+
.split(/\r?\n/)
|
|
114
|
+
.map((line) => line.trim())
|
|
115
|
+
.filter(Boolean);
|
|
116
|
+
const descriptionLine = lines.find((line) => !line.startsWith('#') && !line.startsWith('---'));
|
|
117
|
+
return descriptionLine ?? 'No description provided.';
|
|
118
|
+
}
|
|
119
|
+
async function collectMarkdownFiles(directory) {
|
|
120
|
+
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
121
|
+
const files = await Promise.all(entries.map(async (entry) => {
|
|
122
|
+
const resolvedPath = path.join(directory, entry.name);
|
|
123
|
+
if (entry.isDirectory()) {
|
|
124
|
+
return collectMarkdownFiles(resolvedPath);
|
|
125
|
+
}
|
|
126
|
+
return entry.name.endsWith('.md') ? [resolvedPath] : [];
|
|
127
|
+
}));
|
|
128
|
+
return files.flat();
|
|
129
|
+
}
|
|
130
|
+
async function pathExists(candidatePath) {
|
|
131
|
+
try {
|
|
132
|
+
await fs.access(candidatePath);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function findFirstExistingPath(candidatePaths) {
|
|
140
|
+
for (const candidatePath of candidatePaths) {
|
|
141
|
+
if (await pathExists(candidatePath)) {
|
|
142
|
+
return candidatePath;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
function skillsToCommands(skills) {
|
|
148
|
+
return skills.map((skill) => ({
|
|
149
|
+
name: skill.name,
|
|
150
|
+
description: skill.description,
|
|
151
|
+
source: 'skill',
|
|
152
|
+
path: skill.path,
|
|
153
|
+
}));
|
|
154
|
+
}
|