ide-agents 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 +131 -0
- package/dist/adapters/cursor.d.ts +10 -0
- package/dist/adapters/cursor.js +39 -0
- package/dist/apply.d.ts +2 -0
- package/dist/apply.js +100 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +82 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +86 -0
- package/dist/git.d.ts +6 -0
- package/dist/git.js +173 -0
- package/dist/paths.d.ts +8 -0
- package/dist/paths.js +57 -0
- package/dist/scan.d.ts +2 -0
- package/dist/scan.js +112 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +195 -0
- package/dist/targets.d.ts +4 -0
- package/dist/targets.js +42 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.js +1 -0
- package/package.json +77 -0
- package/web/dist/assets/index-D7KhBlEO.js +124 -0
- package/web/dist/assets/index-JihkyerF.css +1 -0
- package/web/dist/index.html +13 -0
package/dist/paths.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
export function getIdeAgentsHome() {
|
|
5
|
+
return path.join(homedir(), ".ide-agents");
|
|
6
|
+
}
|
|
7
|
+
export function getConfigPath() {
|
|
8
|
+
return path.join(getIdeAgentsHome(), "config.json");
|
|
9
|
+
}
|
|
10
|
+
export function getStatePath() {
|
|
11
|
+
return path.join(getIdeAgentsHome(), "state.json");
|
|
12
|
+
}
|
|
13
|
+
export function getReposDir() {
|
|
14
|
+
return path.join(getIdeAgentsHome(), "repos");
|
|
15
|
+
}
|
|
16
|
+
export function getRepoPath(slug) {
|
|
17
|
+
return path.join(getReposDir(), slug);
|
|
18
|
+
}
|
|
19
|
+
export function slugFromUrl(url) {
|
|
20
|
+
const normalized = url
|
|
21
|
+
.replace(/^git@([^:]+):(.+)\.git$/, "https://$1/$2")
|
|
22
|
+
.replace(/^file:\/\//, "file://")
|
|
23
|
+
.replace(/\.git$/, "")
|
|
24
|
+
.replace(/\/$/, "");
|
|
25
|
+
if (normalized.startsWith("file://")) {
|
|
26
|
+
const localPath = normalized.slice("file://".length);
|
|
27
|
+
return localPath
|
|
28
|
+
.replace(/^\/+/, "")
|
|
29
|
+
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
30
|
+
.replace(/^-+|-+$/g, "")
|
|
31
|
+
.toLowerCase() || "local-repo";
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const parsed = new URL(normalized);
|
|
35
|
+
const host = parsed.hostname.replace(/\./g, "-");
|
|
36
|
+
const pathname = parsed.pathname
|
|
37
|
+
.replace(/^\//, "")
|
|
38
|
+
.replace(/\//g, "-")
|
|
39
|
+
.replace(/[^a-zA-Z0-9-]/g, "-")
|
|
40
|
+
.replace(/-+/g, "-")
|
|
41
|
+
.replace(/^-|-$/g, "");
|
|
42
|
+
return `${host}-${pathname}`.toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return normalized
|
|
46
|
+
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
47
|
+
.replace(/^-+|-+$/g, "")
|
|
48
|
+
.toLowerCase();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function getWebDistDir() {
|
|
52
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
53
|
+
return path.resolve(moduleDir, "../web/dist");
|
|
54
|
+
}
|
|
55
|
+
export function resolveProjectPath(projectPath) {
|
|
56
|
+
return path.resolve(projectPath);
|
|
57
|
+
}
|
package/dist/scan.d.ts
ADDED
package/dist/scan.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
async function pathExists(filePath) {
|
|
5
|
+
try {
|
|
6
|
+
await stat(filePath);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function parseAllowedScope(data) {
|
|
14
|
+
const scope = data.scope;
|
|
15
|
+
if (scope === "global" || scope === "project" || scope === "any") {
|
|
16
|
+
return scope;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function parseAgentDescription(content, fallbackName) {
|
|
21
|
+
const parsed = matter(content);
|
|
22
|
+
if (typeof parsed.data.description === "string" && parsed.data.description.trim()) {
|
|
23
|
+
return parsed.data.description.trim();
|
|
24
|
+
}
|
|
25
|
+
const body = parsed.content.trim();
|
|
26
|
+
if (!body) {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
for (const line of body.split("\n")) {
|
|
30
|
+
const trimmed = line.trim();
|
|
31
|
+
if (!trimmed)
|
|
32
|
+
continue;
|
|
33
|
+
if (trimmed.startsWith("#")) {
|
|
34
|
+
return trimmed.replace(/^#+\s*/, "");
|
|
35
|
+
}
|
|
36
|
+
return trimmed;
|
|
37
|
+
}
|
|
38
|
+
return fallbackName;
|
|
39
|
+
}
|
|
40
|
+
async function scanSkills(repoPath) {
|
|
41
|
+
const skillsDir = path.join(repoPath, "skills");
|
|
42
|
+
if (!(await pathExists(skillsDir))) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
46
|
+
const artifacts = [];
|
|
47
|
+
for (const entry of entries) {
|
|
48
|
+
if (!entry.isDirectory())
|
|
49
|
+
continue;
|
|
50
|
+
const skillDir = path.join(skillsDir, entry.name);
|
|
51
|
+
const skillMdPath = path.join(skillDir, "SKILL.md");
|
|
52
|
+
const hasSkillMd = await pathExists(skillMdPath);
|
|
53
|
+
let name = entry.name;
|
|
54
|
+
let description = "";
|
|
55
|
+
let allowedScope = null;
|
|
56
|
+
if (hasSkillMd) {
|
|
57
|
+
const raw = await readFile(skillMdPath, "utf8");
|
|
58
|
+
const parsed = matter(raw);
|
|
59
|
+
if (typeof parsed.data.name === "string" && parsed.data.name.trim()) {
|
|
60
|
+
name = parsed.data.name.trim();
|
|
61
|
+
}
|
|
62
|
+
if (typeof parsed.data.description === "string") {
|
|
63
|
+
description = parsed.data.description.trim();
|
|
64
|
+
}
|
|
65
|
+
allowedScope = parseAllowedScope(parsed.data);
|
|
66
|
+
}
|
|
67
|
+
artifacts.push({
|
|
68
|
+
id: entry.name,
|
|
69
|
+
kind: "skill",
|
|
70
|
+
sourcePath: path.join("skills", entry.name),
|
|
71
|
+
name,
|
|
72
|
+
description,
|
|
73
|
+
hasSkillMd,
|
|
74
|
+
allowedScope,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return artifacts.sort((a, b) => a.id.localeCompare(b.id));
|
|
78
|
+
}
|
|
79
|
+
async function scanAgents(repoPath) {
|
|
80
|
+
const agentsDir = path.join(repoPath, "agents");
|
|
81
|
+
if (!(await pathExists(agentsDir))) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
const entries = await readdir(agentsDir, { withFileTypes: true });
|
|
85
|
+
const artifacts = [];
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
88
|
+
continue;
|
|
89
|
+
const agentPath = path.join(agentsDir, entry.name);
|
|
90
|
+
const id = entry.name.replace(/\.md$/, "");
|
|
91
|
+
const raw = await readFile(agentPath, "utf8");
|
|
92
|
+
const parsed = matter(raw);
|
|
93
|
+
const description = parseAgentDescription(raw, id);
|
|
94
|
+
const allowedScope = parseAllowedScope(parsed.data);
|
|
95
|
+
artifacts.push({
|
|
96
|
+
id,
|
|
97
|
+
kind: "agent",
|
|
98
|
+
sourcePath: path.join("agents", entry.name),
|
|
99
|
+
name: id,
|
|
100
|
+
description,
|
|
101
|
+
allowedScope,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return artifacts.sort((a, b) => a.id.localeCompare(b.id));
|
|
105
|
+
}
|
|
106
|
+
export async function scanRepoArtifacts(repoPath) {
|
|
107
|
+
const [skills, agents] = await Promise.all([
|
|
108
|
+
scanSkills(repoPath),
|
|
109
|
+
scanAgents(repoPath),
|
|
110
|
+
]);
|
|
111
|
+
return [...skills, ...agents];
|
|
112
|
+
}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import Fastify from "fastify";
|
|
2
|
+
export interface ServerOptions {
|
|
3
|
+
port: number;
|
|
4
|
+
host?: string;
|
|
5
|
+
launchCwd?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createServer(options: ServerOptions): Promise<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>>;
|
|
8
|
+
export declare function startServer(options: ServerOptions): Promise<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>>;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import Fastify from "fastify";
|
|
2
|
+
import fastifyStatic from "@fastify/static";
|
|
3
|
+
import { v4 as uuidv4 } from "uuid";
|
|
4
|
+
import { addRecentProject, readConfig, writeConfig, } from "./config.js";
|
|
5
|
+
import { cloneRepo, fetchRepo, getGitStatusWithoutFetch, pullRepo, } from "./git.js";
|
|
6
|
+
import { applyInstallations } from "./apply.js";
|
|
7
|
+
import { scanRepoArtifacts } from "./scan.js";
|
|
8
|
+
import { getArtifactTargets } from "./targets.js";
|
|
9
|
+
import { getIdeAgentsHome, getRepoPath, getWebDistDir, slugFromUrl, } from "./paths.js";
|
|
10
|
+
import { PACKAGE_VERSION as VERSION } from "./types.js";
|
|
11
|
+
export async function createServer(options) {
|
|
12
|
+
const app = Fastify({ logger: false });
|
|
13
|
+
app.setErrorHandler((error, _request, reply) => {
|
|
14
|
+
reply.status(500).send({
|
|
15
|
+
error: error instanceof Error ? error.message : String(error),
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
app.get("/api/status", async () => {
|
|
19
|
+
const config = await readConfig();
|
|
20
|
+
return {
|
|
21
|
+
home: getIdeAgentsHome(),
|
|
22
|
+
adapter: config.adapter,
|
|
23
|
+
port: options.port,
|
|
24
|
+
version: VERSION,
|
|
25
|
+
defaultProjectPath: options.launchCwd ?? null,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
app.get("/api/repos", async () => {
|
|
29
|
+
const config = await readConfig();
|
|
30
|
+
const repos = [];
|
|
31
|
+
for (const repo of config.repos) {
|
|
32
|
+
const git = await getGitStatusWithoutFetch(repo.slug, repo.ref);
|
|
33
|
+
repos.push({
|
|
34
|
+
...repo,
|
|
35
|
+
localPath: getRepoPath(repo.slug),
|
|
36
|
+
git,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return { repos };
|
|
40
|
+
});
|
|
41
|
+
app.post("/api/repos", async (request, reply) => {
|
|
42
|
+
const { url, ref = "main", id } = request.body ?? {};
|
|
43
|
+
if (!url?.trim()) {
|
|
44
|
+
return reply.status(400).send({ error: "url is required" });
|
|
45
|
+
}
|
|
46
|
+
const config = await readConfig();
|
|
47
|
+
const slug = slugFromUrl(url.trim());
|
|
48
|
+
const repoId = id?.trim() || slug;
|
|
49
|
+
if (config.repos.some((r) => r.id === repoId)) {
|
|
50
|
+
return reply.status(409).send({ error: `Repository id already exists: ${repoId}` });
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await cloneRepo(url.trim(), slug, ref);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
return reply.status(400).send({
|
|
57
|
+
error: err instanceof Error ? err.message : String(err),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const repo = { id: repoId, url: url.trim(), ref, slug };
|
|
61
|
+
config.repos.push(repo);
|
|
62
|
+
await writeConfig(config);
|
|
63
|
+
const git = await getGitStatusWithoutFetch(slug, ref);
|
|
64
|
+
return {
|
|
65
|
+
repo: {
|
|
66
|
+
...repo,
|
|
67
|
+
localPath: getRepoPath(slug),
|
|
68
|
+
git,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
app.delete("/api/repos/:id", async (request, reply) => {
|
|
73
|
+
const config = await readConfig();
|
|
74
|
+
const index = config.repos.findIndex((r) => r.id === request.params.id);
|
|
75
|
+
if (index === -1) {
|
|
76
|
+
return reply.status(404).send({ error: "Repository not found" });
|
|
77
|
+
}
|
|
78
|
+
config.repos.splice(index, 1);
|
|
79
|
+
config.installations = config.installations.filter((i) => i.repoId !== request.params.id);
|
|
80
|
+
await writeConfig(config);
|
|
81
|
+
return { ok: true };
|
|
82
|
+
});
|
|
83
|
+
app.post("/api/repos/:id/fetch", async (request, reply) => {
|
|
84
|
+
const config = await readConfig();
|
|
85
|
+
const repo = config.repos.find((r) => r.id === request.params.id);
|
|
86
|
+
if (!repo) {
|
|
87
|
+
return reply.status(404).send({ error: "Repository not found" });
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
await fetchRepo(repo.slug);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
return reply.status(400).send({
|
|
94
|
+
error: err instanceof Error ? err.message : String(err),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const git = await getGitStatusWithoutFetch(repo.slug, repo.ref);
|
|
98
|
+
return { git };
|
|
99
|
+
});
|
|
100
|
+
app.post("/api/repos/:id/pull", async (request, reply) => {
|
|
101
|
+
const config = await readConfig();
|
|
102
|
+
const repo = config.repos.find((r) => r.id === request.params.id);
|
|
103
|
+
if (!repo) {
|
|
104
|
+
return reply.status(404).send({ error: "Repository not found" });
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
await pullRepo(repo.slug);
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
return reply.status(400).send({
|
|
111
|
+
error: err instanceof Error ? err.message : String(err),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const git = await getGitStatusWithoutFetch(repo.slug, repo.ref);
|
|
115
|
+
return { git };
|
|
116
|
+
});
|
|
117
|
+
app.get("/api/repos/:id/artifacts", async (request, reply) => {
|
|
118
|
+
const config = await readConfig();
|
|
119
|
+
const repo = config.repos.find((r) => r.id === request.params.id);
|
|
120
|
+
if (!repo) {
|
|
121
|
+
return reply.status(404).send({ error: "Repository not found" });
|
|
122
|
+
}
|
|
123
|
+
const projectPath = request.query.projectPath?.trim() || null;
|
|
124
|
+
const scanned = await scanRepoArtifacts(getRepoPath(repo.slug));
|
|
125
|
+
const artifacts = await Promise.all(scanned.map(async (artifact) => ({
|
|
126
|
+
...artifact,
|
|
127
|
+
targets: await getArtifactTargets(artifact, projectPath, config.adapter),
|
|
128
|
+
})));
|
|
129
|
+
return { artifacts };
|
|
130
|
+
});
|
|
131
|
+
app.get("/api/installations", async () => {
|
|
132
|
+
const config = await readConfig();
|
|
133
|
+
return {
|
|
134
|
+
installations: config.installations,
|
|
135
|
+
recentProjects: config.recentProjects,
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
app.put("/api/installations", async (request, reply) => {
|
|
139
|
+
const { installations } = request.body ?? {};
|
|
140
|
+
if (!Array.isArray(installations)) {
|
|
141
|
+
return reply.status(400).send({ error: "installations array is required" });
|
|
142
|
+
}
|
|
143
|
+
const config = await readConfig();
|
|
144
|
+
const normalized = installations.map((installation) => ({
|
|
145
|
+
...installation,
|
|
146
|
+
id: installation.id || uuidv4(),
|
|
147
|
+
}));
|
|
148
|
+
for (const installation of normalized) {
|
|
149
|
+
if (installation.project && installation.projectPath) {
|
|
150
|
+
const updated = await addRecentProject(config, installation.projectPath);
|
|
151
|
+
config.recentProjects = updated.recentProjects;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
config.installations = normalized;
|
|
155
|
+
await writeConfig(config);
|
|
156
|
+
return { installations: config.installations };
|
|
157
|
+
});
|
|
158
|
+
app.post("/api/apply", async (_request, reply) => {
|
|
159
|
+
const config = await readConfig();
|
|
160
|
+
try {
|
|
161
|
+
const result = await applyInstallations(config);
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
return reply.status(400).send({
|
|
166
|
+
error: err instanceof Error ? err.message : String(err),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
app.post("/api/open", async (request, reply) => {
|
|
171
|
+
const { url } = request.body ?? {};
|
|
172
|
+
if (!url?.trim()) {
|
|
173
|
+
return reply.status(400).send({ error: "url is required" });
|
|
174
|
+
}
|
|
175
|
+
return { url: url.trim() };
|
|
176
|
+
});
|
|
177
|
+
const webDist = getWebDistDir();
|
|
178
|
+
await app.register(fastifyStatic, {
|
|
179
|
+
root: webDist,
|
|
180
|
+
prefix: "/",
|
|
181
|
+
wildcard: false,
|
|
182
|
+
});
|
|
183
|
+
app.setNotFoundHandler((request, reply) => {
|
|
184
|
+
if (request.url.startsWith("/api/")) {
|
|
185
|
+
return reply.status(404).send({ error: "Not found" });
|
|
186
|
+
}
|
|
187
|
+
return reply.sendFile("index.html", webDist);
|
|
188
|
+
});
|
|
189
|
+
return app;
|
|
190
|
+
}
|
|
191
|
+
export async function startServer(options) {
|
|
192
|
+
const app = await createServer(options);
|
|
193
|
+
await app.listen({ port: options.port, host: options.host ?? "127.0.0.1" });
|
|
194
|
+
return app;
|
|
195
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Artifact, ArtifactTargets, Installation, TargetStatus } from "./types.js";
|
|
2
|
+
export declare function getTargetStatus(targetPath: string): Promise<TargetStatus>;
|
|
3
|
+
export declare function getArtifactTargets(artifact: Pick<Artifact, "kind" | "id">, projectPath: string | null, adapterId: string): Promise<ArtifactTargets>;
|
|
4
|
+
export declare function installationStub(artifact: Pick<Artifact, "kind" | "id" | "sourcePath">, projectPath: string | null): Pick<Installation, "kind" | "targetName" | "sourcePath" | "projectPath">;
|
package/dist/targets.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { lstat } from "node:fs/promises";
|
|
2
|
+
import { getAdapter } from "./adapters/cursor.js";
|
|
3
|
+
export async function getTargetStatus(targetPath) {
|
|
4
|
+
try {
|
|
5
|
+
const stats = await lstat(targetPath);
|
|
6
|
+
const isSymlink = stats.isSymbolicLink();
|
|
7
|
+
return {
|
|
8
|
+
exists: true,
|
|
9
|
+
isSymlink,
|
|
10
|
+
blocked: !isSymlink,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return {
|
|
15
|
+
exists: false,
|
|
16
|
+
isSymlink: false,
|
|
17
|
+
blocked: false,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function getArtifactTargets(artifact, projectPath, adapterId) {
|
|
22
|
+
const adapter = getAdapter(adapterId);
|
|
23
|
+
const installation = {
|
|
24
|
+
kind: artifact.kind,
|
|
25
|
+
targetName: artifact.id,
|
|
26
|
+
projectPath,
|
|
27
|
+
};
|
|
28
|
+
const global = await getTargetStatus(adapter.getGlobalTargetPath(installation));
|
|
29
|
+
let project = null;
|
|
30
|
+
if (projectPath) {
|
|
31
|
+
project = await getTargetStatus(adapter.getProjectTargetPath(installation));
|
|
32
|
+
}
|
|
33
|
+
return { global, project };
|
|
34
|
+
}
|
|
35
|
+
export function installationStub(artifact, projectPath) {
|
|
36
|
+
return {
|
|
37
|
+
kind: artifact.kind,
|
|
38
|
+
targetName: artifact.id,
|
|
39
|
+
sourcePath: artifact.sourcePath,
|
|
40
|
+
projectPath,
|
|
41
|
+
};
|
|
42
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export type ArtifactKind = "skill" | "agent";
|
|
2
|
+
export type ArtifactAllowedScope = "global" | "project" | "any";
|
|
3
|
+
export type AdapterId = "cursor";
|
|
4
|
+
export interface ServerConfig {
|
|
5
|
+
port: number;
|
|
6
|
+
}
|
|
7
|
+
export interface RepoConfig {
|
|
8
|
+
id: string;
|
|
9
|
+
url: string;
|
|
10
|
+
ref: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Installation {
|
|
14
|
+
id: string;
|
|
15
|
+
repoId: string;
|
|
16
|
+
kind: ArtifactKind;
|
|
17
|
+
artifactId: string;
|
|
18
|
+
sourcePath: string;
|
|
19
|
+
targetName: string;
|
|
20
|
+
global: boolean;
|
|
21
|
+
project: boolean;
|
|
22
|
+
projectPath: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface IdeAgentsConfig {
|
|
25
|
+
version: 1;
|
|
26
|
+
adapter: AdapterId;
|
|
27
|
+
server: ServerConfig;
|
|
28
|
+
repos: RepoConfig[];
|
|
29
|
+
installations: Installation[];
|
|
30
|
+
recentProjects: string[];
|
|
31
|
+
}
|
|
32
|
+
/** @deprecated renamed to IdeAgentsConfig */
|
|
33
|
+
export type AgentDeskConfig = IdeAgentsConfig;
|
|
34
|
+
export interface TargetStatus {
|
|
35
|
+
exists: boolean;
|
|
36
|
+
isSymlink: boolean;
|
|
37
|
+
blocked: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface ArtifactTargets {
|
|
40
|
+
global: TargetStatus;
|
|
41
|
+
project: TargetStatus | null;
|
|
42
|
+
}
|
|
43
|
+
export interface Artifact {
|
|
44
|
+
id: string;
|
|
45
|
+
kind: ArtifactKind;
|
|
46
|
+
sourcePath: string;
|
|
47
|
+
name: string;
|
|
48
|
+
description: string;
|
|
49
|
+
hasSkillMd?: boolean;
|
|
50
|
+
allowedScope: ArtifactAllowedScope | null;
|
|
51
|
+
targets?: ArtifactTargets;
|
|
52
|
+
}
|
|
53
|
+
export interface GitStatus {
|
|
54
|
+
branch: string | null;
|
|
55
|
+
sha: string | null;
|
|
56
|
+
dirty: boolean;
|
|
57
|
+
behind: number | null;
|
|
58
|
+
ahead: number | null;
|
|
59
|
+
error?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface RepoWithStatus extends RepoConfig {
|
|
62
|
+
localPath: string;
|
|
63
|
+
git: GitStatus;
|
|
64
|
+
}
|
|
65
|
+
export interface ApplyResultItem {
|
|
66
|
+
path: string;
|
|
67
|
+
action: "created" | "removed" | "skipped";
|
|
68
|
+
error?: string;
|
|
69
|
+
}
|
|
70
|
+
export interface ApplyResult {
|
|
71
|
+
results: ApplyResultItem[];
|
|
72
|
+
}
|
|
73
|
+
export declare const PACKAGE_VERSION = "0.1.0";
|
|
74
|
+
/** @deprecated legacy config field */
|
|
75
|
+
export type Scope = "global" | "project" | "off";
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const PACKAGE_VERSION = "0.1.0";
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ide-agents",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local admin for IDE agents and skills from git repos",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ide-agents": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"web/dist",
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build:server": "tsc",
|
|
17
|
+
"build:web": "vite build --config web/vite.config.ts",
|
|
18
|
+
"build": "npm run build:server && npm run build:web",
|
|
19
|
+
"prepublishOnly": "npm run build",
|
|
20
|
+
"dev:server": "tsx watch src/cli.ts --no-open",
|
|
21
|
+
"dev:web": "vite --config web/vite.config.ts",
|
|
22
|
+
"dev": "concurrently -n server,web -c blue,green \"npm run dev:server\" \"npm run dev:web\"",
|
|
23
|
+
"start": "node dist/cli.js",
|
|
24
|
+
"docs:install": "npm install --prefix docs",
|
|
25
|
+
"docs:start": "npm --prefix docs start",
|
|
26
|
+
"docs:build": "npm --prefix docs run build"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"ide-agents",
|
|
33
|
+
"cursor",
|
|
34
|
+
"skills",
|
|
35
|
+
"agents",
|
|
36
|
+
"subagents",
|
|
37
|
+
"cli",
|
|
38
|
+
"symlink",
|
|
39
|
+
"ide",
|
|
40
|
+
"ai"
|
|
41
|
+
],
|
|
42
|
+
"author": "sergeychernov",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/sergeychernov/agentdesk.git"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/sergeychernov/agentdesk#readme",
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/sergeychernov/agentdesk/issues"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@fastify/static": "^8.1.1",
|
|
54
|
+
"fastify": "^5.2.1",
|
|
55
|
+
"gray-matter": "^4.0.3",
|
|
56
|
+
"uuid": "^11.1.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@mantine/core": "^9.2.2",
|
|
60
|
+
"@mantine/hooks": "^9.2.2",
|
|
61
|
+
"@tabler/icons-react": "^3.44.0",
|
|
62
|
+
"@types/node": "^22.13.10",
|
|
63
|
+
"@types/react": "^19.0.10",
|
|
64
|
+
"@types/react-dom": "^19.0.4",
|
|
65
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
66
|
+
"concurrently": "^9.1.2",
|
|
67
|
+
"postcss": "^8.5.15",
|
|
68
|
+
"postcss-preset-mantine": "^1.18.0",
|
|
69
|
+
"postcss-simple-vars": "^7.0.1",
|
|
70
|
+
"react": "^19.0.0",
|
|
71
|
+
"react-dom": "^19.0.0",
|
|
72
|
+
"react-router-dom": "^7.3.0",
|
|
73
|
+
"tsx": "^4.19.3",
|
|
74
|
+
"typescript": "^5.8.2",
|
|
75
|
+
"vite": "^6.2.1"
|
|
76
|
+
}
|
|
77
|
+
}
|