agent-proteus 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/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/agent-registry-IWDWNZDN.js +12 -0
- package/dist/chunk-XNEZQVEV.js +236 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +2359 -0
- package/package.json +59 -0
- package/templates/README.md +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# 🔱 Proteus
|
|
2
|
+
|
|
3
|
+
> Shape-shifting project intelligence for Claude Code
|
|
4
|
+
|
|
5
|
+
Proteus analyzes your project and generates **project-specific agents** — specialized AI assistants that understand your codebase's language, framework, conventions, and rules.
|
|
6
|
+
|
|
7
|
+
## Why Proteus?
|
|
8
|
+
|
|
9
|
+
Claude Code works best with context. But generic agents don't know your project's:
|
|
10
|
+
- Coding conventions and style
|
|
11
|
+
- Directory structure
|
|
12
|
+
- Testing patterns
|
|
13
|
+
- Project-specific rules
|
|
14
|
+
|
|
15
|
+
**Proteus transforms into your project**, creating personalized agents that already understand everything.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Run directly with npx
|
|
21
|
+
npx agent-proteus
|
|
22
|
+
|
|
23
|
+
# Or install globally
|
|
24
|
+
npm install -g agent-proteus
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# In your project directory
|
|
31
|
+
proteus
|
|
32
|
+
|
|
33
|
+
# Preview without saving
|
|
34
|
+
proteus --dry-run
|
|
35
|
+
|
|
36
|
+
# Specify output language
|
|
37
|
+
proteus --lang ja
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Proteus will:
|
|
41
|
+
1. Analyze your project structure
|
|
42
|
+
2. Read existing CLAUDE.md (if present) for rules
|
|
43
|
+
3. Suggest project-specific agents using Claude Code
|
|
44
|
+
4. Generate selected agents to `.claude/agents/`
|
|
45
|
+
5. Optionally generate `/proteus` skill for easy routing
|
|
46
|
+
|
|
47
|
+
## Generated Structure
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
.claude/
|
|
51
|
+
├── agents/ # Project-specific agents
|
|
52
|
+
│ ├── rails-graphql-type-generator.md
|
|
53
|
+
│ ├── rspec-request-spec-writer.md
|
|
54
|
+
│ └── ...
|
|
55
|
+
└── skills/
|
|
56
|
+
└── proteus/
|
|
57
|
+
└── SKILL.md # Router skill for agents
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Commands
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Default: Analyze and generate agents
|
|
64
|
+
proteus
|
|
65
|
+
|
|
66
|
+
# Generate CLAUDE.md only
|
|
67
|
+
proteus init
|
|
68
|
+
|
|
69
|
+
# Update agent list in CLAUDE.md or agents.md
|
|
70
|
+
proteus registry
|
|
71
|
+
|
|
72
|
+
# Just analyze (no generation)
|
|
73
|
+
proteus analyze
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Options
|
|
77
|
+
|
|
78
|
+
| Option | Description |
|
|
79
|
+
|--------|-------------|
|
|
80
|
+
| `-o, --output <dir>` | Output directory (default: `.claude/agents`) |
|
|
81
|
+
| `-l, --lang <code>` | Output language (en, ja, zh, ko, es, fr, de) |
|
|
82
|
+
| `-d, --dry-run` | Preview without saving |
|
|
83
|
+
| `-f, --force` | Skip confirmations |
|
|
84
|
+
| `--include-claude-md` | Also generate CLAUDE.md if not exists |
|
|
85
|
+
|
|
86
|
+
## How It Works
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
┌─────────────────────────────────────┐
|
|
90
|
+
│ 1. Analyze Project │
|
|
91
|
+
│ - Language, framework, tools │
|
|
92
|
+
│ - Directory structure │
|
|
93
|
+
│ - Naming conventions │
|
|
94
|
+
└─────────────────────────────────────┘
|
|
95
|
+
↓
|
|
96
|
+
┌─────────────────────────────────────┐
|
|
97
|
+
│ 2. Read Existing Documents │
|
|
98
|
+
│ - CLAUDE.md (rules, conventions) │
|
|
99
|
+
│ - README.md (description) │
|
|
100
|
+
│ - Existing agents (avoids dupes) │
|
|
101
|
+
└─────────────────────────────────────┘
|
|
102
|
+
↓
|
|
103
|
+
┌─────────────────────────────────────┐
|
|
104
|
+
│ 3. Suggest Agents (via Claude) │
|
|
105
|
+
│ - Dynamic based on your stack │
|
|
106
|
+
│ - Considers existing coverage │
|
|
107
|
+
│ - Project-specific naming │
|
|
108
|
+
└─────────────────────────────────────┘
|
|
109
|
+
↓
|
|
110
|
+
┌─────────────────────────────────────┐
|
|
111
|
+
│ 4. Generate & Save │
|
|
112
|
+
│ - Personalized agent definitions │
|
|
113
|
+
│ - /proteus skill for routing │
|
|
114
|
+
│ - Registry in CLAUDE.md │
|
|
115
|
+
└─────────────────────────────────────┘
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Smart Agent Suggestions
|
|
119
|
+
|
|
120
|
+
Proteus adjusts suggestions based on existing coverage:
|
|
121
|
+
|
|
122
|
+
| Existing Agents | Max Suggestions |
|
|
123
|
+
|-----------------|-----------------|
|
|
124
|
+
| 0 | 5 agents |
|
|
125
|
+
| 1-2 | 3 agents |
|
|
126
|
+
| 3-4 | 2 agents |
|
|
127
|
+
| 5+ | 0-1 agents (if gaps exist) |
|
|
128
|
+
|
|
129
|
+
## Supported Languages & Frameworks
|
|
130
|
+
|
|
131
|
+
| Language | Frameworks |
|
|
132
|
+
|----------|------------|
|
|
133
|
+
| TypeScript/JavaScript | Next.js, React, Vue, Angular, Svelte, Express, Fastify, NestJS |
|
|
134
|
+
| Go | Gin, Echo, Fiber |
|
|
135
|
+
| Python | Django, Flask, FastAPI |
|
|
136
|
+
| Ruby | Rails |
|
|
137
|
+
| Rust | Actix, Axum |
|
|
138
|
+
| Java | Spring |
|
|
139
|
+
| PHP | Laravel |
|
|
140
|
+
|
|
141
|
+
## Example: Rails Project
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
$ proteus
|
|
145
|
+
|
|
146
|
+
🔱 PROTEUS - Shape-shifting project intelligence
|
|
147
|
+
|
|
148
|
+
✓ Claude Code detected - using AI-powered generation
|
|
149
|
+
✔ Output language: 日本語
|
|
150
|
+
|
|
151
|
+
Tech Stack:
|
|
152
|
+
Language: ruby
|
|
153
|
+
Framework: rails
|
|
154
|
+
Testing: rspec
|
|
155
|
+
|
|
156
|
+
Recommended agents:
|
|
157
|
+
1. rails-graphql-type-generator
|
|
158
|
+
2. serializable-pattern-enforcer
|
|
159
|
+
3. rspec-request-spec-writer
|
|
160
|
+
...
|
|
161
|
+
|
|
162
|
+
✅ Created .claude/agents/rails-graphql-type-generator.md
|
|
163
|
+
✅ Created .claude/skills/proteus/SKILL.md
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Using Generated Agents
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Use specific agent
|
|
170
|
+
@rails-graphql-type-generator このResolverをレビューして
|
|
171
|
+
|
|
172
|
+
# Use /proteus to auto-route
|
|
173
|
+
/proteus テストを書いて # → automatically uses rspec-request-spec-writer
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Contributing
|
|
177
|
+
|
|
178
|
+
Contributions welcome! Please read our [Contributing Guide](CONTRIBUTING.md).
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
<p align="center">
|
|
187
|
+
<i>Named after Proteus, the shape-shifting Greek sea god who could transform into anything — just like this tool transforms into your project.</i>
|
|
188
|
+
</p>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// src/agent-registry.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
var I18N = {
|
|
5
|
+
en: {
|
|
6
|
+
availableAgents: "Available Agents",
|
|
7
|
+
noAgentsConfigured: "No agents configured yet.",
|
|
8
|
+
agentHeader: "Agent",
|
|
9
|
+
descriptionHeader: "Description",
|
|
10
|
+
pathHeader: "Path",
|
|
11
|
+
agentsAvailable: (n) => `${n} agent(s) available`,
|
|
12
|
+
projectAgentsTitle: "Project Agents",
|
|
13
|
+
projectAgentsDescription: "This file lists all available Claude Code agents for this project."
|
|
14
|
+
},
|
|
15
|
+
ja: {
|
|
16
|
+
availableAgents: "\u5229\u7528\u53EF\u80FD\u306A\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
|
|
17
|
+
noAgentsConfigured: "\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u306F\u307E\u3060\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",
|
|
18
|
+
agentHeader: "\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
|
|
19
|
+
descriptionHeader: "\u8AAC\u660E",
|
|
20
|
+
pathHeader: "\u30D1\u30B9",
|
|
21
|
+
agentsAvailable: (n) => `${n}\u500B\u306E\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u304C\u5229\u7528\u53EF\u80FD`,
|
|
22
|
+
projectAgentsTitle: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
|
|
23
|
+
projectAgentsDescription: "\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u306F\u3001\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067\u5229\u7528\u53EF\u80FD\u306AClaude Code\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u306E\u4E00\u89A7\u3067\u3059\u3002"
|
|
24
|
+
},
|
|
25
|
+
zh: {
|
|
26
|
+
availableAgents: "\u53EF\u7528\u4EE3\u7406",
|
|
27
|
+
noAgentsConfigured: "\u5C1A\u672A\u914D\u7F6E\u4EE3\u7406\u3002",
|
|
28
|
+
agentHeader: "\u4EE3\u7406",
|
|
29
|
+
descriptionHeader: "\u63CF\u8FF0",
|
|
30
|
+
pathHeader: "\u8DEF\u5F84",
|
|
31
|
+
agentsAvailable: (n) => `${n}\u4E2A\u4EE3\u7406\u53EF\u7528`,
|
|
32
|
+
projectAgentsTitle: "\u9879\u76EE\u4EE3\u7406",
|
|
33
|
+
projectAgentsDescription: "\u6B64\u6587\u4EF6\u5217\u51FA\u4E86\u6B64\u9879\u76EE\u6240\u6709\u53EF\u7528\u7684Claude Code\u4EE3\u7406\u3002"
|
|
34
|
+
},
|
|
35
|
+
ko: {
|
|
36
|
+
availableAgents: "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC5D0\uC774\uC804\uD2B8",
|
|
37
|
+
noAgentsConfigured: "\uC544\uC9C1 \uAD6C\uC131\uB41C \uC5D0\uC774\uC804\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
38
|
+
agentHeader: "\uC5D0\uC774\uC804\uD2B8",
|
|
39
|
+
descriptionHeader: "\uC124\uBA85",
|
|
40
|
+
pathHeader: "\uACBD\uB85C",
|
|
41
|
+
agentsAvailable: (n) => `${n}\uAC1C\uC758 \uC5D0\uC774\uC804\uD2B8 \uC0AC\uC6A9 \uAC00\uB2A5`,
|
|
42
|
+
projectAgentsTitle: "\uD504\uB85C\uC81D\uD2B8 \uC5D0\uC774\uC804\uD2B8",
|
|
43
|
+
projectAgentsDescription: "\uC774 \uD30C\uC77C\uC740 \uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C Claude Code \uC5D0\uC774\uC804\uD2B8 \uBAA9\uB85D\uC785\uB2C8\uB2E4."
|
|
44
|
+
},
|
|
45
|
+
es: {
|
|
46
|
+
availableAgents: "Agentes Disponibles",
|
|
47
|
+
noAgentsConfigured: "No hay agentes configurados todav\xEDa.",
|
|
48
|
+
agentHeader: "Agente",
|
|
49
|
+
descriptionHeader: "Descripci\xF3n",
|
|
50
|
+
pathHeader: "Ruta",
|
|
51
|
+
agentsAvailable: (n) => `${n} agente(s) disponible(s)`,
|
|
52
|
+
projectAgentsTitle: "Agentes del Proyecto",
|
|
53
|
+
projectAgentsDescription: "Este archivo lista todos los agentes de Claude Code disponibles para este proyecto."
|
|
54
|
+
},
|
|
55
|
+
fr: {
|
|
56
|
+
availableAgents: "Agents Disponibles",
|
|
57
|
+
noAgentsConfigured: "Aucun agent configur\xE9 pour le moment.",
|
|
58
|
+
agentHeader: "Agent",
|
|
59
|
+
descriptionHeader: "Description",
|
|
60
|
+
pathHeader: "Chemin",
|
|
61
|
+
agentsAvailable: (n) => `${n} agent(s) disponible(s)`,
|
|
62
|
+
projectAgentsTitle: "Agents du Projet",
|
|
63
|
+
projectAgentsDescription: "Ce fichier liste tous les agents Claude Code disponibles pour ce projet."
|
|
64
|
+
},
|
|
65
|
+
de: {
|
|
66
|
+
availableAgents: "Verf\xFCgbare Agenten",
|
|
67
|
+
noAgentsConfigured: "Noch keine Agenten konfiguriert.",
|
|
68
|
+
agentHeader: "Agent",
|
|
69
|
+
descriptionHeader: "Beschreibung",
|
|
70
|
+
pathHeader: "Pfad",
|
|
71
|
+
agentsAvailable: (n) => `${n} Agent(en) verf\xFCgbar`,
|
|
72
|
+
projectAgentsTitle: "Projekt-Agenten",
|
|
73
|
+
projectAgentsDescription: "Diese Datei listet alle verf\xFCgbaren Claude Code Agenten f\xFCr dieses Projekt auf."
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
function scanExistingAgents(agentDir) {
|
|
77
|
+
const agents = [];
|
|
78
|
+
if (!fs.existsSync(agentDir)) {
|
|
79
|
+
return agents;
|
|
80
|
+
}
|
|
81
|
+
const files = fs.readdirSync(agentDir);
|
|
82
|
+
for (const file of files) {
|
|
83
|
+
if (!file.endsWith(".md") || file.startsWith("_") || file.toLowerCase() === "readme.md") {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const filePath = path.join(agentDir, file);
|
|
87
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
88
|
+
const h1Match = content.match(/^#\s+(.+)$/m);
|
|
89
|
+
const name = h1Match ? h1Match[1].trim() : file.replace(".md", "");
|
|
90
|
+
const descMatch = content.match(/^#\s+.+\n+([^#\n].+)/m);
|
|
91
|
+
const description = descMatch ? descMatch[1].trim() : void 0;
|
|
92
|
+
agents.push({
|
|
93
|
+
name,
|
|
94
|
+
description,
|
|
95
|
+
path: file
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return agents;
|
|
99
|
+
}
|
|
100
|
+
function generateAgentListSection(agents, agentDir, format = "table", lang = "en") {
|
|
101
|
+
const t = I18N[lang];
|
|
102
|
+
if (agents.length === 0) {
|
|
103
|
+
return `## ${t.availableAgents}
|
|
104
|
+
|
|
105
|
+
${t.noAgentsConfigured}
|
|
106
|
+
`;
|
|
107
|
+
}
|
|
108
|
+
const relativePath = agentDir.replace(/^\.\//, "");
|
|
109
|
+
if (format === "table") {
|
|
110
|
+
let section = `## ${t.availableAgents}
|
|
111
|
+
|
|
112
|
+
`;
|
|
113
|
+
section += `| ${t.agentHeader} | ${t.descriptionHeader} | ${t.pathHeader} |
|
|
114
|
+
`;
|
|
115
|
+
section += "|-------|-------------|------|\n";
|
|
116
|
+
for (const agent of agents) {
|
|
117
|
+
const desc = agent.description ? truncate(agent.description, 60) : "-";
|
|
118
|
+
section += `| ${agent.name} | ${desc} | \`${relativePath}/${agent.path}\` |
|
|
119
|
+
`;
|
|
120
|
+
}
|
|
121
|
+
section += `
|
|
122
|
+
*${t.agentsAvailable(agents.length)}*
|
|
123
|
+
`;
|
|
124
|
+
return section;
|
|
125
|
+
} else {
|
|
126
|
+
let section = `## ${t.availableAgents}
|
|
127
|
+
|
|
128
|
+
`;
|
|
129
|
+
for (const agent of agents) {
|
|
130
|
+
section += `### ${agent.name}
|
|
131
|
+
`;
|
|
132
|
+
if (agent.description) {
|
|
133
|
+
section += `${agent.description}
|
|
134
|
+
`;
|
|
135
|
+
}
|
|
136
|
+
section += `- **${t.pathHeader}**: \`${relativePath}/${agent.path}\`
|
|
137
|
+
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
return section;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function updateAgentRegistry(options, newAgents = []) {
|
|
144
|
+
const { projectPath, agentDir, format = "table", lang = "en" } = options;
|
|
145
|
+
const t = I18N[lang];
|
|
146
|
+
const existingAgents = scanExistingAgents(path.join(projectPath, agentDir));
|
|
147
|
+
const allAgents = [...existingAgents];
|
|
148
|
+
for (const newAgent of newAgents) {
|
|
149
|
+
const filename = `${newAgent.name}.md`;
|
|
150
|
+
if (!allAgents.some((a) => a.path === filename)) {
|
|
151
|
+
allAgents.push({
|
|
152
|
+
name: formatAgentName(newAgent.name),
|
|
153
|
+
description: newAgent.description,
|
|
154
|
+
path: filename
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const agentSection = generateAgentListSection(allAgents, agentDir, format, lang);
|
|
159
|
+
const claudeMdPath = path.join(projectPath, "CLAUDE.md");
|
|
160
|
+
const agentsMdPath = path.join(projectPath, "agents.md");
|
|
161
|
+
if (fs.existsSync(claudeMdPath)) {
|
|
162
|
+
const result = updateFileWithAgentSection(claudeMdPath, agentSection, lang);
|
|
163
|
+
return {
|
|
164
|
+
file: "CLAUDE.md",
|
|
165
|
+
action: result.action,
|
|
166
|
+
agentCount: allAgents.length
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (fs.existsSync(agentsMdPath)) {
|
|
170
|
+
const result = updateFileWithAgentSection(agentsMdPath, agentSection, lang);
|
|
171
|
+
return {
|
|
172
|
+
file: "agents.md",
|
|
173
|
+
action: result.action,
|
|
174
|
+
agentCount: allAgents.length
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const newContent = `# ${t.projectAgentsTitle}
|
|
178
|
+
|
|
179
|
+
${t.projectAgentsDescription}
|
|
180
|
+
|
|
181
|
+
${agentSection}`;
|
|
182
|
+
fs.writeFileSync(agentsMdPath, newContent, "utf-8");
|
|
183
|
+
return {
|
|
184
|
+
file: "agents.md",
|
|
185
|
+
action: "created",
|
|
186
|
+
agentCount: allAgents.length
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function updateFileWithAgentSection(filePath, agentSection, lang) {
|
|
190
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
191
|
+
const t = I18N[lang];
|
|
192
|
+
const allSectionHeaders = Object.values(I18N).map((i) => i.availableAgents).join("|");
|
|
193
|
+
const agentSectionPattern = new RegExp(`## (${allSectionHeaders})[\\s\\S]*?(?=\\n## |\\n# |$)`);
|
|
194
|
+
if (agentSectionPattern.test(content)) {
|
|
195
|
+
const newContent = content.replace(agentSectionPattern, agentSection.trim());
|
|
196
|
+
fs.writeFileSync(filePath, newContent, "utf-8");
|
|
197
|
+
return { action: "updated" };
|
|
198
|
+
} else {
|
|
199
|
+
const newContent = content.trimEnd() + "\n\n" + agentSection;
|
|
200
|
+
fs.writeFileSync(filePath, newContent, "utf-8");
|
|
201
|
+
return { action: "added-section" };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function formatAgentName(name) {
|
|
205
|
+
return name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
206
|
+
}
|
|
207
|
+
function truncate(str, maxLength) {
|
|
208
|
+
if (str.length <= maxLength) return str;
|
|
209
|
+
return str.slice(0, maxLength - 3) + "...";
|
|
210
|
+
}
|
|
211
|
+
function shouldUpdateRegistry(projectPath, agentDir, newAgentCount) {
|
|
212
|
+
const claudeMdPath = path.join(projectPath, "CLAUDE.md");
|
|
213
|
+
const agentsMdPath = path.join(projectPath, "agents.md");
|
|
214
|
+
if (!fs.existsSync(claudeMdPath) && !fs.existsSync(agentsMdPath)) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
const existingAgents = scanExistingAgents(path.join(projectPath, agentDir));
|
|
218
|
+
if (newAgentCount > 0) {
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
const registryPath = fs.existsSync(claudeMdPath) ? claudeMdPath : agentsMdPath;
|
|
222
|
+
const content = fs.readFileSync(registryPath, "utf-8");
|
|
223
|
+
const agentCountMatch = content.match(/\*(\d+)/);
|
|
224
|
+
if (agentCountMatch) {
|
|
225
|
+
const registeredCount = parseInt(agentCountMatch[1], 10);
|
|
226
|
+
return registeredCount !== existingAgents.length;
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export {
|
|
232
|
+
scanExistingAgents,
|
|
233
|
+
generateAgentListSection,
|
|
234
|
+
updateAgentRegistry,
|
|
235
|
+
shouldUpdateRegistry
|
|
236
|
+
};
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|