@evo-dev/core 0.0.1-alpha
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/assets/agents/review/code-reviewer/examples.md +19 -0
- package/assets/agents/review/code-reviewer/manifest.json +10 -0
- package/assets/agents/review/code-reviewer/prompt.md +59 -0
- package/assets/agents/review/code-reviewer/verification.md +11 -0
- package/assets/skills/coding/engineering-discipline/SKILL.md +63 -0
- package/assets/skills/coding/engineering-discipline/anti-patterns.md +21 -0
- package/assets/skills/coding/engineering-discipline/examples.md +19 -0
- package/assets/skills/coding/engineering-discipline/manifest.json +10 -0
- package/assets/skills/coding/engineering-discipline/verification.md +11 -0
- package/assets/workflows/rd-bug-fix/WORKFLOW.json +45 -0
- package/assets/workflows/rd-code-review/WORKFLOW.json +45 -0
- package/assets/workflows/rd-docs-update/WORKFLOW.json +45 -0
- package/assets/workflows/rd-feature-implementation/WORKFLOW.json +45 -0
- package/assets/workflows/rd-refactor/WORKFLOW.json +45 -0
- package/assets/workflows/rd-release-readiness/WORKFLOW.json +49 -0
- package/assets/workflows/rd-security-boundary-review/WORKFLOW.json +45 -0
- package/assets/workflows/rd-test-generation/WORKFLOW.json +45 -0
- package/dist/assets/index.js +209 -0
- package/dist/config/index.js +601 -0
- package/dist/index.js +4879 -0
- package/dist/plugins/index.js +265 -0
- package/package.json +30 -0
- package/src/.gitkeep +0 -0
- package/src/agents/index.ts +561 -0
- package/src/assets/errors.ts +21 -0
- package/src/assets/index.ts +18 -0
- package/src/assets/manifest.ts +109 -0
- package/src/assets/scanner.ts +189 -0
- package/src/config/errors.ts +21 -0
- package/src/config/index.ts +26 -0
- package/src/config/paths.ts +43 -0
- package/src/config/registry.ts +84 -0
- package/src/config/settings.ts +212 -0
- package/src/config/state.ts +130 -0
- package/src/config/store.ts +166 -0
- package/src/daemon/index.ts +414 -0
- package/src/hooks/index.ts +1023 -0
- package/src/index.ts +14 -0
- package/src/learning/index.ts +714 -0
- package/src/observability/index.ts +272 -0
- package/src/pack/index.ts +779 -0
- package/src/plugins/capabilities.ts +347 -0
- package/src/plugins/index.ts +41 -0
- package/src/plugins/registry.ts +60 -0
- package/src/plugins/types.ts +123 -0
- package/src/project/index.ts +507 -0
- package/src/protected-zones/index.ts +137 -0
- package/src/sync/index.ts +7 -0
- package/src/sync/orchestrator.ts +298 -0
- package/src/task/index.ts +840 -0
- package/src/workflow/index.ts +137 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// packages/core/src/assets/errors.ts
|
|
2
|
+
class EvoDevAssetError extends Error {
|
|
3
|
+
filePath;
|
|
4
|
+
constructor(message, filePath) {
|
|
5
|
+
super(filePath ? `${message}: ${filePath}` : message);
|
|
6
|
+
this.filePath = filePath;
|
|
7
|
+
this.name = "EvoDevAssetError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function describeType(value) {
|
|
11
|
+
if (value === null) {
|
|
12
|
+
return "null";
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return "array";
|
|
16
|
+
}
|
|
17
|
+
return typeof value;
|
|
18
|
+
}
|
|
19
|
+
// packages/core/src/assets/manifest.ts
|
|
20
|
+
function parseSkillManifest(value) {
|
|
21
|
+
return {
|
|
22
|
+
...parseBaseManifest(value, "skill manifest"),
|
|
23
|
+
kind: "skill"
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function parseAgentManifest(value) {
|
|
27
|
+
return {
|
|
28
|
+
...parseBaseManifest(value, "agent manifest"),
|
|
29
|
+
kind: "agent"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function parseBaseManifest(value, label) {
|
|
33
|
+
const root = expectRecord(value, label);
|
|
34
|
+
const manifest = {
|
|
35
|
+
id: expectSlug(root.id, `${label}.id`),
|
|
36
|
+
name: expectNonEmptyString(root.name, `${label}.name`),
|
|
37
|
+
version: expectNonEmptyString(root.version, `${label}.version`),
|
|
38
|
+
category: expectSlug(root.category, `${label}.category`),
|
|
39
|
+
description: expectNonEmptyString(root.description, `${label}.description`),
|
|
40
|
+
targets: expectTargets(root.targets, `${label}.targets`),
|
|
41
|
+
entry: expectRelativePath(root.entry, `${label}.entry`)
|
|
42
|
+
};
|
|
43
|
+
if (root.license !== undefined) {
|
|
44
|
+
manifest.license = expectNonEmptyString(root.license, `${label}.license`);
|
|
45
|
+
}
|
|
46
|
+
return manifest;
|
|
47
|
+
}
|
|
48
|
+
function expectRecord(value, path) {
|
|
49
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
50
|
+
throw new EvoDevAssetError(`Invalid ${path}; expected object, got ${describeType(value)}`);
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
function expectNonEmptyString(value, path) {
|
|
55
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
56
|
+
throw new EvoDevAssetError(`Invalid ${path}; expected non-empty string`);
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
function expectSlug(value, path) {
|
|
61
|
+
const text = expectNonEmptyString(value, path);
|
|
62
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(text)) {
|
|
63
|
+
throw new EvoDevAssetError(`Invalid ${path}; expected lowercase kebab-case slug`);
|
|
64
|
+
}
|
|
65
|
+
return text;
|
|
66
|
+
}
|
|
67
|
+
function expectTargets(value, path) {
|
|
68
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
69
|
+
throw new EvoDevAssetError(`Invalid ${path}; expected non-empty target array`);
|
|
70
|
+
}
|
|
71
|
+
const targets = value.map((target, index) => {
|
|
72
|
+
if (target !== "claude" && target !== "codex") {
|
|
73
|
+
throw new EvoDevAssetError(`Invalid ${path}[${index}]; expected claude or codex`);
|
|
74
|
+
}
|
|
75
|
+
return target;
|
|
76
|
+
});
|
|
77
|
+
return [...new Set(targets)];
|
|
78
|
+
}
|
|
79
|
+
function expectRelativePath(value, path) {
|
|
80
|
+
const text = expectNonEmptyString(value, path);
|
|
81
|
+
if (text.startsWith("/") || text.includes("..")) {
|
|
82
|
+
throw new EvoDevAssetError(`Invalid ${path}; expected safe relative path`);
|
|
83
|
+
}
|
|
84
|
+
return text;
|
|
85
|
+
}
|
|
86
|
+
// packages/core/src/assets/scanner.ts
|
|
87
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
88
|
+
import { join, relative } from "node:path";
|
|
89
|
+
async function scanAssets(paths) {
|
|
90
|
+
const [skills, agents] = await Promise.all([
|
|
91
|
+
scanSkillAssets(paths.skillsDir),
|
|
92
|
+
scanAgentAssets(paths.agentsDir)
|
|
93
|
+
]);
|
|
94
|
+
return { skills, agents };
|
|
95
|
+
}
|
|
96
|
+
async function scanSkillAssets(skillsDir) {
|
|
97
|
+
return scanAssetKind(skillsDir, parseSkillManifest);
|
|
98
|
+
}
|
|
99
|
+
async function scanAgentAssets(agentsDir) {
|
|
100
|
+
return scanAssetKind(agentsDir, parseAgentManifest);
|
|
101
|
+
}
|
|
102
|
+
async function scanAssetKind(rootDir, parseManifest) {
|
|
103
|
+
if (!await pathExists(rootDir)) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
const manifestPaths = await findManifestFiles(rootDir);
|
|
107
|
+
const assets = await Promise.all(manifestPaths.map((manifestPath) => readScannedAsset(rootDir, manifestPath, parseManifest)));
|
|
108
|
+
return assets.sort((left, right) => left.registryKey.localeCompare(right.registryKey));
|
|
109
|
+
}
|
|
110
|
+
async function findManifestFiles(rootDir) {
|
|
111
|
+
const entries = await readdir(rootDir, { withFileTypes: true });
|
|
112
|
+
const nested = await Promise.all(entries.map(async (entry) => {
|
|
113
|
+
const entryPath = join(rootDir, entry.name);
|
|
114
|
+
if (entry.isDirectory()) {
|
|
115
|
+
return findManifestFiles(entryPath);
|
|
116
|
+
}
|
|
117
|
+
if (entry.isFile() && entry.name === "manifest.json") {
|
|
118
|
+
return [entryPath];
|
|
119
|
+
}
|
|
120
|
+
return [];
|
|
121
|
+
}));
|
|
122
|
+
return nested.flat();
|
|
123
|
+
}
|
|
124
|
+
async function readScannedAsset(rootDir, manifestPath, parseManifest) {
|
|
125
|
+
const json = await readManifestJson(manifestPath);
|
|
126
|
+
const manifest = parseManifestWithPath(json, manifestPath, parseManifest);
|
|
127
|
+
const assetDir = manifestPath.slice(0, -"/manifest.json".length);
|
|
128
|
+
const entryPath = join(assetDir, manifest.entry);
|
|
129
|
+
if (!await isFile(entryPath)) {
|
|
130
|
+
throw new EvoDevAssetError(`Asset entry file not found for ${manifest.id}`, entryPath);
|
|
131
|
+
}
|
|
132
|
+
const registryKey = createRegistryKey(rootDir, assetDir, manifest);
|
|
133
|
+
return {
|
|
134
|
+
manifest,
|
|
135
|
+
manifestPath,
|
|
136
|
+
entryPath,
|
|
137
|
+
assetDir,
|
|
138
|
+
registryKey
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async function readManifestJson(manifestPath) {
|
|
142
|
+
let raw;
|
|
143
|
+
try {
|
|
144
|
+
raw = await readFile(manifestPath, "utf8");
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new EvoDevAssetError(`Cannot read manifest (${describeFileError(error)})`, manifestPath);
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
return JSON.parse(raw);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
throw new EvoDevAssetError(`Invalid manifest JSON (${describeFileError(error)})`, manifestPath);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function parseManifestWithPath(json, manifestPath, parseManifest) {
|
|
155
|
+
try {
|
|
156
|
+
return parseManifest(json);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (error instanceof EvoDevAssetError) {
|
|
159
|
+
throw new EvoDevAssetError(error.message, manifestPath);
|
|
160
|
+
}
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function createRegistryKey(rootDir, assetDir, manifest) {
|
|
165
|
+
const relativeDir = relative(rootDir, assetDir).replaceAll("\\", "/");
|
|
166
|
+
if (relativeDir === "" || relativeDir === manifest.id) {
|
|
167
|
+
return manifest.id;
|
|
168
|
+
}
|
|
169
|
+
return relativeDir;
|
|
170
|
+
}
|
|
171
|
+
async function pathExists(path) {
|
|
172
|
+
try {
|
|
173
|
+
await stat(path);
|
|
174
|
+
return true;
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function isFile(path) {
|
|
183
|
+
try {
|
|
184
|
+
const fileStat = await stat(path);
|
|
185
|
+
return fileStat.isFile();
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function describeFileError(error) {
|
|
194
|
+
if (error instanceof Error) {
|
|
195
|
+
return error.message;
|
|
196
|
+
}
|
|
197
|
+
return String(error);
|
|
198
|
+
}
|
|
199
|
+
function isNodeError(error) {
|
|
200
|
+
return error instanceof Error && "code" in error;
|
|
201
|
+
}
|
|
202
|
+
export {
|
|
203
|
+
scanSkillAssets,
|
|
204
|
+
scanAssets,
|
|
205
|
+
scanAgentAssets,
|
|
206
|
+
parseSkillManifest,
|
|
207
|
+
parseAgentManifest,
|
|
208
|
+
EvoDevAssetError
|
|
209
|
+
};
|