@evo-dev/core 0.0.1-alpha → 0.0.1-alpha.2
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 +1 -1
- package/assets/agents/review/code-reviewer/prompt.md +1 -1
- package/assets/agents/review/code-reviewer/verification.md +1 -1
- package/assets/skills/coding/knowledge-distillation/SKILL.md +249 -0
- package/assets/skills/coding/knowledge-distillation/manifest.json +10 -0
- package/assets/skills/coding/knowledge-distillation/references/knowledge-distillation-methods.md +126 -0
- package/assets/workflows/rd-bug-fix/WORKFLOW.json +1 -1
- package/assets/workflows/rd-code-review/WORKFLOW.json +1 -1
- package/assets/workflows/rd-docs-update/WORKFLOW.json +1 -1
- package/assets/workflows/rd-feature-implementation/WORKFLOW.json +1 -1
- package/assets/workflows/rd-refactor/WORKFLOW.json +1 -1
- package/assets/workflows/rd-release-readiness/WORKFLOW.json +1 -1
- package/assets/workflows/rd-security-boundary-review/WORKFLOW.json +2 -2
- package/assets/workflows/rd-test-generation/WORKFLOW.json +1 -1
- package/dist/config/index.js +968 -39
- package/dist/index.js +10914 -1476
- package/dist/plugins/index.js +32 -32
- package/package.json +5 -1
- package/src/agents/index.ts +84 -49
- package/src/code-agent-traces/index.ts +521 -0
- package/src/config/index.ts +5 -0
- package/src/config/paths.ts +30 -0
- package/src/config/settings.ts +130 -0
- package/src/config/store.ts +152 -0
- package/src/daemon/index.ts +465 -3
- package/src/evolution/index.ts +2827 -0
- package/src/hooks/index.ts +543 -247
- package/src/index.ts +6 -0
- package/src/knowledge/index.ts +4784 -0
- package/src/pack/index.ts +13 -13
- package/src/plugins/capabilities.ts +40 -42
- package/src/plugins/index.ts +0 -1
- package/src/plugins/types.ts +4 -0
- package/src/protected-zones/index.ts +29 -11
- package/src/runtime-logs/index.ts +798 -0
- package/src/sync/orchestrator.ts +6 -0
- package/src/task/index.ts +3 -3
- package/src/team/index.ts +3069 -0
- package/src/team/mcp.ts +405 -0
- package/src/team/prompts.ts +141 -0
- package/src/workflow/index.ts +6 -6
package/dist/config/index.js
CHANGED
|
@@ -21,12 +21,30 @@ function resolveEvoDevPaths(homeDir = getHomeDir()) {
|
|
|
21
21
|
const normalizedHome = stripTrailingSlash(homeDir);
|
|
22
22
|
const rootDir = `${normalizedHome}/.evodev`;
|
|
23
23
|
const stateDir = `${rootDir}/state`;
|
|
24
|
+
const logsDir = `${rootDir}/logs`;
|
|
25
|
+
const knowledgeDir = `${rootDir}/knowledge`;
|
|
26
|
+
const evosDir = `${rootDir}/evos`;
|
|
27
|
+
const roleAgentsDir = `${rootDir}/agents/roles`;
|
|
28
|
+
const teamsDir = `${rootDir}/teams`;
|
|
29
|
+
const runsDir = `${teamsDir}/runs`;
|
|
24
30
|
return {
|
|
25
31
|
homeDir: normalizedHome,
|
|
26
32
|
rootDir,
|
|
27
33
|
settingsPath: `${rootDir}/settings.json`,
|
|
28
34
|
registryPath: `${rootDir}/registry.json`,
|
|
29
35
|
stateDir,
|
|
36
|
+
logsDir,
|
|
37
|
+
knowledgeDir,
|
|
38
|
+
knowledgeIndexPath: `${knowledgeDir}/index.json`,
|
|
39
|
+
evosDir,
|
|
40
|
+
evosCasesDir: `${evosDir}/cases`,
|
|
41
|
+
evosIndexPath: `${evosDir}/index.json`,
|
|
42
|
+
roleAgentsDir,
|
|
43
|
+
roleAgentsIndexPath: `${roleAgentsDir}/index.json`,
|
|
44
|
+
teamsDir,
|
|
45
|
+
teamsIndexPath: `${teamsDir}/index.json`,
|
|
46
|
+
runsDir,
|
|
47
|
+
latestRunPath: `${runsDir}/latest.json`,
|
|
30
48
|
installStatePath: `${stateDir}/install.json`,
|
|
31
49
|
syncStatePath: `${stateDir}/sync.json`
|
|
32
50
|
};
|
|
@@ -98,11 +116,643 @@ function expectString(value, path) {
|
|
|
98
116
|
}
|
|
99
117
|
return value;
|
|
100
118
|
}
|
|
119
|
+
// packages/core/src/config/settings.ts
|
|
120
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
121
|
+
|
|
122
|
+
// packages/core/src/runtime-logs/index.ts
|
|
123
|
+
var SAFE_EXECUTION_METADATA_KEYS = new Set([
|
|
124
|
+
"phase",
|
|
125
|
+
"runtimeSurface",
|
|
126
|
+
"stdinBytes",
|
|
127
|
+
"durationMs",
|
|
128
|
+
"enabled",
|
|
129
|
+
"stateWriteCount",
|
|
130
|
+
"warningCount",
|
|
131
|
+
"commandClass",
|
|
132
|
+
"exitCode",
|
|
133
|
+
"status",
|
|
134
|
+
"redactionCount",
|
|
135
|
+
"redactionLabels",
|
|
136
|
+
"normalizedEventType"
|
|
137
|
+
]);
|
|
138
|
+
var SAFE_REDACTION_LABELS = new Set([
|
|
139
|
+
"raw-command",
|
|
140
|
+
"raw-command-output",
|
|
141
|
+
"raw-prompt",
|
|
142
|
+
"sensitive-command",
|
|
143
|
+
"sensitive-text"
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
// packages/core/src/knowledge/index.ts
|
|
147
|
+
import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
148
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
149
|
+
var RESERVED_OKF_FILENAMES = new Set(["index.md", "log.md"]);
|
|
150
|
+
var FORBIDDEN_OKF_TEXT = /\b(secret|token|password|passwd|api[_-]?key|apikey|credential|credentials|secret[\s_-]*token(?:[\s_-]*repro)?|raw[\s_-]*(?:log|logs|output|source|prompt)(?:[\s_-]*repro)?|shell[\s_-]*history|command[\s_-]*history)\b/i;
|
|
151
|
+
var PRIVATE_OR_INTERNAL_URL = /https?:\/\/\S*(?:internal|private|corp|localhost|127\.0\.0\.1)\S*/i;
|
|
152
|
+
var OKF_PRIVACY_FLAG_KEYS = [
|
|
153
|
+
"rawPromptsStored",
|
|
154
|
+
"rawLogsStored",
|
|
155
|
+
"sourceDumpsStored",
|
|
156
|
+
"rawCommandOutputStored",
|
|
157
|
+
"secretsStored",
|
|
158
|
+
"internalLinksStored"
|
|
159
|
+
];
|
|
160
|
+
var OKF_QUERY_PRIVACY_FLAG_KEYS = [
|
|
161
|
+
...OKF_PRIVACY_FLAG_KEYS,
|
|
162
|
+
"rawOutputStored",
|
|
163
|
+
"sourceContentStored"
|
|
164
|
+
];
|
|
165
|
+
var ACTIVE_OKF_REVIEW_STATES = ["accepted", "auto-accepted"];
|
|
166
|
+
var OKF_REVIEW_STATES = [
|
|
167
|
+
"auto-accepted",
|
|
168
|
+
"accepted",
|
|
169
|
+
"needs-human",
|
|
170
|
+
"rejected",
|
|
171
|
+
"deferred",
|
|
172
|
+
"stale",
|
|
173
|
+
"deprecated",
|
|
174
|
+
"revoked",
|
|
175
|
+
"superseded",
|
|
176
|
+
"auto-stored/unreviewed"
|
|
177
|
+
];
|
|
178
|
+
var OKF_LIFECYCLE_STATUSES = [
|
|
179
|
+
"active",
|
|
180
|
+
"stale",
|
|
181
|
+
"deprecated",
|
|
182
|
+
"revoked",
|
|
183
|
+
"superseded"
|
|
184
|
+
];
|
|
185
|
+
var BEHAVIOR_CHANGE_KINDS = new Set([
|
|
186
|
+
"skill-improvement",
|
|
187
|
+
"role-agent-suggestion",
|
|
188
|
+
"team-suggestion",
|
|
189
|
+
"workflow-improvement",
|
|
190
|
+
"task-split-improvement",
|
|
191
|
+
"tool-use-improvement",
|
|
192
|
+
"repo-asset-suggestion"
|
|
193
|
+
]);
|
|
194
|
+
function resolveOkfKnowledgePaths(homeDir) {
|
|
195
|
+
const paths = resolveEvoDevPaths(homeDir);
|
|
196
|
+
return {
|
|
197
|
+
knowledgeDir: paths.knowledgeDir,
|
|
198
|
+
okfDir: join(paths.knowledgeDir, "okf"),
|
|
199
|
+
indexesDir: join(paths.knowledgeDir, "indexes"),
|
|
200
|
+
tmpDir: join(paths.knowledgeDir, "tmp")
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
async function ensureOkfKnowledgeBase(homeDir) {
|
|
204
|
+
const paths = resolveOkfKnowledgePaths(homeDir);
|
|
205
|
+
await ensureLocalKnowledgeGitRepository(paths.knowledgeDir);
|
|
206
|
+
await mkdir(paths.indexesDir, { recursive: true });
|
|
207
|
+
await mkdir(paths.tmpDir, { recursive: true });
|
|
208
|
+
const directories = [
|
|
209
|
+
{
|
|
210
|
+
path: "",
|
|
211
|
+
title: "EvoDev Knowledge",
|
|
212
|
+
description: "User-local active engineering knowledge."
|
|
213
|
+
},
|
|
214
|
+
{ path: "concepts", title: "Core Concepts", description: "Canonical core knowledge." },
|
|
215
|
+
{ path: "concepts/rules", title: "Rules", description: "Normative engineering rules." },
|
|
216
|
+
{
|
|
217
|
+
path: "concepts/decisions",
|
|
218
|
+
title: "Decisions",
|
|
219
|
+
description: "Durable engineering decisions."
|
|
220
|
+
},
|
|
221
|
+
{ path: "concepts/patterns", title: "Patterns", description: "Reusable engineering patterns." },
|
|
222
|
+
{ path: "concepts/warnings", title: "Warnings", description: "Risks and anti-patterns." },
|
|
223
|
+
{ path: "concepts/checklists", title: "Checklists", description: "Verification checklists." },
|
|
224
|
+
{
|
|
225
|
+
path: "concepts/verification",
|
|
226
|
+
title: "Verification",
|
|
227
|
+
description: "Repeatable verification patterns."
|
|
228
|
+
},
|
|
229
|
+
{ path: "concepts/evos", title: "Evolution Cases", description: "Reviewed evolution cases." },
|
|
230
|
+
{ path: "concepts/glossary", title: "Glossary", description: "Terms and taxonomy notes." },
|
|
231
|
+
{ path: "repos", title: "Repositories", description: "Repository attention overlays." },
|
|
232
|
+
{ path: "roles", title: "Roles", description: "Role attention overlays." },
|
|
233
|
+
{ path: "workflows", title: "Workflows", description: "Workflow attention overlays." },
|
|
234
|
+
{ path: "references", title: "References", description: "Cited references." }
|
|
235
|
+
];
|
|
236
|
+
for (const directory of directories) {
|
|
237
|
+
await ensureOkfDirectory(paths.okfDir, directory.path, directory.title, directory.description);
|
|
238
|
+
}
|
|
239
|
+
await rebuildOkfKnowledgeIndexes({ homeDir });
|
|
240
|
+
}
|
|
241
|
+
async function rebuildOkfKnowledgeIndexes(input) {
|
|
242
|
+
const paths = resolveOkfKnowledgePaths(input.homeDir);
|
|
243
|
+
await mkdir(paths.indexesDir, { recursive: true });
|
|
244
|
+
const concepts = (await listOkfKnowledgeConcepts({ homeDir: input.homeDir })).filter(isActiveOkfConcept);
|
|
245
|
+
const conceptSummaries = concepts.map((concept) => ({
|
|
246
|
+
id: concept.id,
|
|
247
|
+
type: concept.type,
|
|
248
|
+
title: concept.title,
|
|
249
|
+
description: concept.description,
|
|
250
|
+
sourceLink: concept.sourceLink,
|
|
251
|
+
stableKey: concept.stableKey,
|
|
252
|
+
reviewState: concept.reviewState,
|
|
253
|
+
tags: concept.tags,
|
|
254
|
+
repoTags: concept.repoTags,
|
|
255
|
+
roleTags: concept.roleTags,
|
|
256
|
+
workflowTags: concept.workflowTags,
|
|
257
|
+
pathScopes: concept.pathScopes
|
|
258
|
+
}));
|
|
259
|
+
const pathsWritten = [
|
|
260
|
+
join(paths.indexesDir, "index.json"),
|
|
261
|
+
join(paths.indexesDir, "concepts.json"),
|
|
262
|
+
join(paths.indexesDir, "repos.json"),
|
|
263
|
+
join(paths.indexesDir, "roles.json"),
|
|
264
|
+
join(paths.indexesDir, "workflows.json")
|
|
265
|
+
];
|
|
266
|
+
await writeJson(pathsWritten[0], {
|
|
267
|
+
schemaVersion: 1,
|
|
268
|
+
kind: "okf-knowledge-index",
|
|
269
|
+
conceptCount: concepts.length,
|
|
270
|
+
updatedAt: new Date().toISOString()
|
|
271
|
+
}, { overwrite: true });
|
|
272
|
+
await writeJson(pathsWritten[1], {
|
|
273
|
+
schemaVersion: 1,
|
|
274
|
+
kind: "okf-concepts-index",
|
|
275
|
+
concepts: conceptSummaries
|
|
276
|
+
}, { overwrite: true });
|
|
277
|
+
await writeJson(pathsWritten[2], {
|
|
278
|
+
schemaVersion: 1,
|
|
279
|
+
kind: "okf-repos-index",
|
|
280
|
+
repos: groupConceptsByTag(concepts, "repoTags")
|
|
281
|
+
}, { overwrite: true });
|
|
282
|
+
await writeJson(pathsWritten[3], {
|
|
283
|
+
schemaVersion: 1,
|
|
284
|
+
kind: "okf-roles-index",
|
|
285
|
+
roles: groupConceptsByTag(concepts, "roleTags")
|
|
286
|
+
}, { overwrite: true });
|
|
287
|
+
await writeJson(pathsWritten[4], {
|
|
288
|
+
schemaVersion: 1,
|
|
289
|
+
kind: "okf-workflows-index",
|
|
290
|
+
workflows: groupConceptsByTag(concepts, "workflowTags")
|
|
291
|
+
}, { overwrite: true });
|
|
292
|
+
return pathsWritten;
|
|
293
|
+
}
|
|
294
|
+
async function listOkfKnowledgeConcepts(input) {
|
|
295
|
+
const okfDir = resolveOkfKnowledgePaths(input.homeDir).okfDir;
|
|
296
|
+
if (!await pathExists(okfDir))
|
|
297
|
+
return [];
|
|
298
|
+
const files = await listMarkdownFiles(okfDir);
|
|
299
|
+
const concepts = [];
|
|
300
|
+
for (const file of files) {
|
|
301
|
+
if (RESERVED_OKF_FILENAMES.has(file.name))
|
|
302
|
+
continue;
|
|
303
|
+
const content = await readFile(file.path, "utf8");
|
|
304
|
+
const parsed = parseOkfConceptFile(okfDir, file.path, content);
|
|
305
|
+
if (parsed !== null)
|
|
306
|
+
concepts.push(parsed);
|
|
307
|
+
}
|
|
308
|
+
return concepts.filter((concept) => matchesConceptFilters(concept, input)).sort((left, right) => left.id.localeCompare(right.id));
|
|
309
|
+
}
|
|
310
|
+
async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
|
|
311
|
+
await mkdir(knowledgeDir, { recursive: true });
|
|
312
|
+
const gitDir = join(knowledgeDir, ".git");
|
|
313
|
+
if (await pathExists(gitDir))
|
|
314
|
+
return;
|
|
315
|
+
await mkdir(join(gitDir, "objects", "info"), { recursive: true });
|
|
316
|
+
await mkdir(join(gitDir, "objects", "pack"), { recursive: true });
|
|
317
|
+
await mkdir(join(gitDir, "refs", "heads"), { recursive: true });
|
|
318
|
+
await mkdir(join(gitDir, "refs", "tags"), { recursive: true });
|
|
319
|
+
await mkdir(join(gitDir, "info"), { recursive: true });
|
|
320
|
+
await writeTextIfMissing(join(gitDir, "HEAD"), `ref: refs/heads/main
|
|
321
|
+
`);
|
|
322
|
+
await writeTextIfMissing(join(gitDir, "config"), [
|
|
323
|
+
"[core]",
|
|
324
|
+
"\trepositoryformatversion = 0",
|
|
325
|
+
"\tfilemode = true",
|
|
326
|
+
"\tbare = false",
|
|
327
|
+
"\tlogallrefupdates = true",
|
|
328
|
+
""
|
|
329
|
+
].join(`
|
|
330
|
+
`));
|
|
331
|
+
await writeTextIfMissing(join(gitDir, "info", "exclude"), [
|
|
332
|
+
"# EvoDev user-local knowledge git repository.",
|
|
333
|
+
"# No remote is configured by default.",
|
|
334
|
+
""
|
|
335
|
+
].join(`
|
|
336
|
+
`));
|
|
337
|
+
}
|
|
338
|
+
async function writeTextIfMissing(path, value) {
|
|
339
|
+
if (await pathExists(path))
|
|
340
|
+
return;
|
|
341
|
+
await mkdir(dirname(path), { recursive: true });
|
|
342
|
+
await writeFile(path, value, { encoding: "utf8", flag: "wx" });
|
|
343
|
+
}
|
|
344
|
+
function sanitizeOkfText(value) {
|
|
345
|
+
return value.replace(new RegExp(PRIVATE_OR_INTERNAL_URL.source, "gi"), "[redacted]").replace(new RegExp(FORBIDDEN_OKF_TEXT.source, "gi"), "[redacted]").replace(/\s+/gu, " ").trim().slice(0, 800);
|
|
346
|
+
}
|
|
347
|
+
async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
|
|
348
|
+
const dir = relativeDir === "" || relativeDir === "." ? okfDir : resolveOkfTargetPath(okfDir, relativeDir);
|
|
349
|
+
await mkdir(dir, { recursive: true });
|
|
350
|
+
const isRoot = dir === okfDir;
|
|
351
|
+
const indexPath = join(dir, "index.md");
|
|
352
|
+
if (!await pathExists(indexPath)) {
|
|
353
|
+
await writeFile(indexPath, isRoot ? [
|
|
354
|
+
"---",
|
|
355
|
+
`okf_version: ${yamlString("0.1")}`,
|
|
356
|
+
`title: ${yamlString(title)}`,
|
|
357
|
+
`description: ${yamlString(description)}`,
|
|
358
|
+
"---",
|
|
359
|
+
"",
|
|
360
|
+
`# ${title}`,
|
|
361
|
+
"",
|
|
362
|
+
description,
|
|
363
|
+
""
|
|
364
|
+
].join(`
|
|
365
|
+
`) : [`# ${title}`, "", description, ""].join(`
|
|
366
|
+
`), "utf8");
|
|
367
|
+
}
|
|
368
|
+
const logPath = join(dir, "log.md");
|
|
369
|
+
if (!await pathExists(logPath)) {
|
|
370
|
+
await writeFile(logPath, [
|
|
371
|
+
"# Directory Update Log",
|
|
372
|
+
"",
|
|
373
|
+
`## ${todayIsoDate()}`,
|
|
374
|
+
"* **Initialization**: Created OKF directory.",
|
|
375
|
+
""
|
|
376
|
+
].join(`
|
|
377
|
+
`), "utf8");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function parseOkfConceptFile(okfDir, filePath, content) {
|
|
381
|
+
const parsed = extractFrontmatter(content);
|
|
382
|
+
if (parsed === null)
|
|
383
|
+
return null;
|
|
384
|
+
const rel = toOkfRelativePath(okfDir, filePath);
|
|
385
|
+
const id = rel.replace(/\.md$/, "");
|
|
386
|
+
const frontmatter = parsed.frontmatter;
|
|
387
|
+
const stableKey = readIndentedYamlScalar(frontmatter, "stableKey") ?? `legacy:${rel.replace(/\.md$/, "")}`;
|
|
388
|
+
const reviewState = parseOkfReviewState(readIndentedYamlScalar(frontmatter, "reviewState") ?? "auto-stored/unreviewed");
|
|
389
|
+
const type = readYamlScalar(frontmatter, "type") ?? "Unknown";
|
|
390
|
+
const title = readYamlScalar(frontmatter, "title") ?? titleFromSlug(id.split("/").at(-1) ?? id);
|
|
391
|
+
const description = readYamlScalar(frontmatter, "description") ?? "";
|
|
392
|
+
const tags = readYamlList(frontmatter, "tags");
|
|
393
|
+
const repoTags = readYamlList(frontmatter, "repoTags");
|
|
394
|
+
const roleTags = readYamlList(frontmatter, "roleTags");
|
|
395
|
+
const workflowTags = readYamlList(frontmatter, "workflowTags");
|
|
396
|
+
const pathScopes = readYamlList(frontmatter, "pathScopes");
|
|
397
|
+
const lifecycleParsed = parseOkfLifecycle(frontmatter, {
|
|
398
|
+
type,
|
|
399
|
+
path: rel,
|
|
400
|
+
tags,
|
|
401
|
+
title,
|
|
402
|
+
reviewState,
|
|
403
|
+
createdAt: readYamlScalar(frontmatter, "timestamp") ?? undefined
|
|
404
|
+
});
|
|
405
|
+
return {
|
|
406
|
+
id,
|
|
407
|
+
path: filePath,
|
|
408
|
+
sourceLink: `/${rel}`,
|
|
409
|
+
type,
|
|
410
|
+
stableKey,
|
|
411
|
+
reviewState,
|
|
412
|
+
lifecycle: lifecycleParsed.lifecycle,
|
|
413
|
+
lifecyclePersisted: lifecycleParsed.persisted,
|
|
414
|
+
title,
|
|
415
|
+
description,
|
|
416
|
+
tags,
|
|
417
|
+
repoTags,
|
|
418
|
+
roleTags,
|
|
419
|
+
workflowTags,
|
|
420
|
+
pathScopes,
|
|
421
|
+
body: parsed.body
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function matchesConceptFilters(concept, input) {
|
|
425
|
+
if (input.projectKey !== undefined && concept.repoTags.length > 0 && !concept.repoTags.includes(sanitizeSlug(input.projectKey)) && !concept.tags.includes(`repo:${sanitizeSlug(input.projectKey)}`)) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
if (input.roleId !== undefined && concept.roleTags.length > 0 && !concept.roleTags.includes(sanitizeSlug(input.roleId)) && !concept.tags.includes(`role:${sanitizeSlug(input.roleId)}`)) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
if (input.workflowId !== undefined && concept.workflowTags.length > 0 && !concept.workflowTags.includes(sanitizeSlug(input.workflowId)) && !concept.tags.includes(`workflow:${sanitizeSlug(input.workflowId)}`)) {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (input.paths !== undefined && input.paths.length > 0 && concept.pathScopes.length > 0) {
|
|
435
|
+
return input.paths.some((path) => concept.pathScopes.some((scope) => path.startsWith(scope) || scope.startsWith(path)));
|
|
436
|
+
}
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
function isActiveOkfConcept(concept) {
|
|
440
|
+
return resolveOkfConceptQueryEligibility(concept, {
|
|
441
|
+
includeStale: false,
|
|
442
|
+
now: new Date
|
|
443
|
+
}).include;
|
|
444
|
+
}
|
|
445
|
+
function isActiveOkfReviewState(reviewState) {
|
|
446
|
+
return ACTIVE_OKF_REVIEW_STATES.includes(reviewState);
|
|
447
|
+
}
|
|
448
|
+
function resolveOkfConceptQueryEligibility(concept, input) {
|
|
449
|
+
if (concept.lifecycle.status === "deprecated" || concept.lifecycle.status === "revoked" || concept.lifecycle.status === "superseded" || concept.reviewState === "deprecated" || concept.reviewState === "revoked" || concept.reviewState === "superseded") {
|
|
450
|
+
return { include: false, stale: false, scoreAdjustment: 0, reason: "inactive" };
|
|
451
|
+
}
|
|
452
|
+
const staleByStatus = concept.lifecycle.status === "stale" || concept.reviewState === "stale";
|
|
453
|
+
const staleByDate = isLifecycleDateDue(concept.lifecycle.staleAfter, input.now);
|
|
454
|
+
const stale = staleByStatus || staleByDate;
|
|
455
|
+
if (stale) {
|
|
456
|
+
return {
|
|
457
|
+
include: input.includeStale,
|
|
458
|
+
stale: input.includeStale,
|
|
459
|
+
scoreAdjustment: input.includeStale ? -250 : 0,
|
|
460
|
+
reason: staleByStatus ? "status=stale" : `staleAfter=${concept.lifecycle.staleAfter}`
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
include: isActiveOkfReviewState(concept.reviewState) && concept.lifecycle.status === "active",
|
|
465
|
+
stale: false,
|
|
466
|
+
scoreAdjustment: 0,
|
|
467
|
+
reason: "active"
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
function isLifecycleDateDue(value, now) {
|
|
471
|
+
const normalized = normalizeIsoDateString(value);
|
|
472
|
+
return normalized !== null && Date.parse(normalized) <= now.getTime();
|
|
473
|
+
}
|
|
474
|
+
function createDefaultOkfLifecycle(input) {
|
|
475
|
+
const createdAt = normalizeIsoDateString(input.createdAt) ?? "1970-01-01T00:00:00.000Z";
|
|
476
|
+
const policy = resolveOkfLifecyclePolicy(input);
|
|
477
|
+
return {
|
|
478
|
+
status: lifecycleStatusFromReviewState(input.reviewState),
|
|
479
|
+
createdAt,
|
|
480
|
+
lastVerifiedAt: createdAt,
|
|
481
|
+
reviewAfter: addDaysIso(createdAt, policy.reviewAfterDays),
|
|
482
|
+
staleAfter: addDaysIso(createdAt, policy.staleAfterDays),
|
|
483
|
+
supersedes: [],
|
|
484
|
+
supersededBy: null,
|
|
485
|
+
revokedAt: null,
|
|
486
|
+
revokedReason: null
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
function parseOkfLifecycle(frontmatter, input) {
|
|
490
|
+
const defaults = createDefaultOkfLifecycle(input);
|
|
491
|
+
const block = extractNestedYamlBlock(frontmatter, "evodev", "lifecycle");
|
|
492
|
+
if (block === null)
|
|
493
|
+
return { lifecycle: defaults, persisted: false };
|
|
494
|
+
const status = readIndentedYamlScalar(block, "status");
|
|
495
|
+
const createdAt = readIndentedYamlScalar(block, "createdAt");
|
|
496
|
+
const lastVerifiedAt = readIndentedYamlScalar(block, "lastVerifiedAt");
|
|
497
|
+
const reviewAfter = readIndentedYamlScalar(block, "reviewAfter");
|
|
498
|
+
const staleAfter = readIndentedYamlScalar(block, "staleAfter");
|
|
499
|
+
const revokedAt = readIndentedYamlScalar(block, "revokedAt");
|
|
500
|
+
return {
|
|
501
|
+
persisted: true,
|
|
502
|
+
lifecycle: {
|
|
503
|
+
status: isOkfLifecycleStatus(status) ? status : defaults.status,
|
|
504
|
+
createdAt: normalizeIsoDateString(createdAt) ?? defaults.createdAt,
|
|
505
|
+
lastVerifiedAt: normalizeIsoDateString(lastVerifiedAt) ?? defaults.lastVerifiedAt,
|
|
506
|
+
reviewAfter: normalizeIsoDateString(reviewAfter) ?? defaults.reviewAfter,
|
|
507
|
+
staleAfter: normalizeIsoDateString(staleAfter) ?? defaults.staleAfter,
|
|
508
|
+
supersedes: readYamlList(block, "supersedes"),
|
|
509
|
+
supersededBy: readNullableLifecycleString(readIndentedYamlScalar(block, "supersededBy")),
|
|
510
|
+
revokedAt: readNullableLifecycleString(revokedAt) === null ? null : normalizeIsoDateString(revokedAt),
|
|
511
|
+
revokedReason: readNullableLifecycleString(readIndentedYamlScalar(block, "revokedReason"))
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
function lifecycleStatusFromReviewState(reviewState) {
|
|
516
|
+
if (reviewState === "stale")
|
|
517
|
+
return "stale";
|
|
518
|
+
if (reviewState === "deprecated")
|
|
519
|
+
return "deprecated";
|
|
520
|
+
if (reviewState === "revoked")
|
|
521
|
+
return "revoked";
|
|
522
|
+
if (reviewState === "superseded")
|
|
523
|
+
return "superseded";
|
|
524
|
+
return "active";
|
|
525
|
+
}
|
|
526
|
+
function resolveOkfLifecyclePolicy(input) {
|
|
527
|
+
const comparable = `${input.type} ${input.path} ${input.tags.join(" ")} ${input.title}`.toLowerCase();
|
|
528
|
+
if (/\bverification\b/u.test(comparable))
|
|
529
|
+
return { reviewAfterDays: 120, staleAfterDays: 240 };
|
|
530
|
+
if (/\bworkflow\b/u.test(comparable))
|
|
531
|
+
return { reviewAfterDays: 60, staleAfterDays: 120 };
|
|
532
|
+
return { reviewAfterDays: 90, staleAfterDays: 180 };
|
|
533
|
+
}
|
|
534
|
+
function isOkfLifecycleStatus(value) {
|
|
535
|
+
return OKF_LIFECYCLE_STATUSES.includes(value);
|
|
536
|
+
}
|
|
537
|
+
function normalizeIsoDateString(value) {
|
|
538
|
+
if (value === undefined || value === null || value === "" || value === "null")
|
|
539
|
+
return null;
|
|
540
|
+
const time = Date.parse(value);
|
|
541
|
+
if (!Number.isFinite(time))
|
|
542
|
+
return null;
|
|
543
|
+
return new Date(time).toISOString();
|
|
544
|
+
}
|
|
545
|
+
function addDaysIso(value, days) {
|
|
546
|
+
const date = new Date(value);
|
|
547
|
+
date.setUTCDate(date.getUTCDate() + days);
|
|
548
|
+
return date.toISOString();
|
|
549
|
+
}
|
|
550
|
+
function readNullableLifecycleString(value) {
|
|
551
|
+
if (value === null)
|
|
552
|
+
return null;
|
|
553
|
+
const normalized = sanitizeOkfText(value);
|
|
554
|
+
return normalized === "" || normalized === "null" ? null : normalized;
|
|
555
|
+
}
|
|
556
|
+
function yamlString(value) {
|
|
557
|
+
return JSON.stringify(value);
|
|
558
|
+
}
|
|
559
|
+
function extractFrontmatter(content) {
|
|
560
|
+
if (!content.startsWith(`---
|
|
561
|
+
`))
|
|
562
|
+
return null;
|
|
563
|
+
const end = content.indexOf(`
|
|
564
|
+
---`, 4);
|
|
565
|
+
if (end < 0)
|
|
566
|
+
return null;
|
|
567
|
+
const frontmatter = content.slice(4, end).trim();
|
|
568
|
+
const body = content.slice(end + 4).replace(/^\n/u, "");
|
|
569
|
+
return { frontmatter, body };
|
|
570
|
+
}
|
|
571
|
+
function extractNestedYamlBlock(frontmatter, rootKey, childKey) {
|
|
572
|
+
const lines = frontmatter.split(`
|
|
573
|
+
`);
|
|
574
|
+
const rootIndex = lines.findIndex((line) => line.trim() === `${rootKey}:`);
|
|
575
|
+
if (rootIndex < 0)
|
|
576
|
+
return null;
|
|
577
|
+
const rootEnd = findYamlBlockEnd(lines, rootIndex, 0);
|
|
578
|
+
const childIndex = lines.findIndex((line, index) => index > rootIndex && index < rootEnd && line.startsWith(" ") && line.trim() === `${childKey}:`);
|
|
579
|
+
if (childIndex < 0)
|
|
580
|
+
return null;
|
|
581
|
+
const childEnd = findYamlBlockEnd(lines, childIndex, 2);
|
|
582
|
+
return lines.slice(childIndex + 1, childEnd).join(`
|
|
583
|
+
`);
|
|
584
|
+
}
|
|
585
|
+
function findYamlBlockEnd(lines, startIndex, parentIndent) {
|
|
586
|
+
for (let index = startIndex + 1;index < lines.length; index += 1) {
|
|
587
|
+
const line = lines[index] ?? "";
|
|
588
|
+
if (line.trim() === "")
|
|
589
|
+
continue;
|
|
590
|
+
const indent = line.length - line.trimStart().length;
|
|
591
|
+
if (indent <= parentIndent)
|
|
592
|
+
return index;
|
|
593
|
+
}
|
|
594
|
+
return lines.length;
|
|
595
|
+
}
|
|
596
|
+
function readYamlScalar(frontmatter, key) {
|
|
597
|
+
const match = frontmatter.match(new RegExp(`^${escapeRegExp(key)}:\\s*(.+?)\\s*$`, "m"));
|
|
598
|
+
if (match?.[1] === undefined)
|
|
599
|
+
return null;
|
|
600
|
+
return parseYamlValue(match[1]);
|
|
601
|
+
}
|
|
602
|
+
function readIndentedYamlScalar(frontmatter, key) {
|
|
603
|
+
const match = frontmatter.match(new RegExp(`^\\s*${escapeRegExp(key)}:\\s*(.+?)\\s*$`, "m"));
|
|
604
|
+
if (match?.[1] === undefined)
|
|
605
|
+
return null;
|
|
606
|
+
return parseYamlValue(match[1]);
|
|
607
|
+
}
|
|
608
|
+
function parseOkfReviewState(value) {
|
|
609
|
+
return OKF_REVIEW_STATES.includes(value) ? value : "auto-stored/unreviewed";
|
|
610
|
+
}
|
|
611
|
+
function readYamlList(frontmatter, key) {
|
|
612
|
+
const inline = frontmatter.match(new RegExp(`^\\s*${escapeRegExp(key)}:\\s*\\[(.*?)\\]\\s*$`, "m"));
|
|
613
|
+
if (inline?.[1] !== undefined) {
|
|
614
|
+
return inline[1].split(",").map((item) => parseYamlValue(item.trim())).filter((item) => item !== "");
|
|
615
|
+
}
|
|
616
|
+
const lines = frontmatter.split(`
|
|
617
|
+
`);
|
|
618
|
+
const values = [];
|
|
619
|
+
for (let index = 0;index < lines.length; index += 1) {
|
|
620
|
+
const line = lines[index] ?? "";
|
|
621
|
+
if (!line.trim().startsWith(`${key}:`))
|
|
622
|
+
continue;
|
|
623
|
+
for (let next = index + 1;next < lines.length; next += 1) {
|
|
624
|
+
const candidate = lines[next] ?? "";
|
|
625
|
+
if (!/^\s+-\s+/u.test(candidate))
|
|
626
|
+
break;
|
|
627
|
+
values.push(parseYamlValue(candidate.replace(/^\s+-\s+/u, "")));
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return [...new Set(values.filter((value) => value !== ""))];
|
|
631
|
+
}
|
|
632
|
+
function parseYamlValue(value) {
|
|
633
|
+
const trimmed = value.trim();
|
|
634
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
635
|
+
try {
|
|
636
|
+
return JSON.parse(trimmed);
|
|
637
|
+
} catch {
|
|
638
|
+
return trimmed.slice(1, -1);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return trimmed.replace(/^['"]|['"]$/gu, "");
|
|
642
|
+
}
|
|
643
|
+
async function listMarkdownFiles(root) {
|
|
644
|
+
if (!await pathExists(root))
|
|
645
|
+
return [];
|
|
646
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
647
|
+
const files = [];
|
|
648
|
+
for (const entry of entries) {
|
|
649
|
+
const path = join(root, entry.name);
|
|
650
|
+
if (entry.isDirectory()) {
|
|
651
|
+
files.push(...await listMarkdownFiles(path));
|
|
652
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
653
|
+
files.push({ path, name: entry.name });
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return files;
|
|
657
|
+
}
|
|
658
|
+
function groupConceptsByTag(concepts, field) {
|
|
659
|
+
const groups = new Map;
|
|
660
|
+
for (const concept of concepts) {
|
|
661
|
+
for (const id of concept[field]) {
|
|
662
|
+
groups.set(id, [
|
|
663
|
+
...groups.get(id) ?? [],
|
|
664
|
+
{ id: concept.id, title: concept.title, sourceLink: concept.sourceLink }
|
|
665
|
+
]);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return [...groups.entries()].map(([id, groupedConcepts]) => ({ id, concepts: groupedConcepts }));
|
|
669
|
+
}
|
|
670
|
+
function resolveOkfTargetPath(okfDir, targetPath) {
|
|
671
|
+
const clean = targetPath.replace(/^\/+/u, "");
|
|
672
|
+
if (clean.split("/").some((segment) => segment === ".." || segment === "." || segment === "")) {
|
|
673
|
+
throw new Error(`Unsafe OKF target path: ${targetPath}`);
|
|
674
|
+
}
|
|
675
|
+
const resolved = join(okfDir, clean);
|
|
676
|
+
const rel = relative(okfDir, resolved);
|
|
677
|
+
if (rel.startsWith("..") || rel === "")
|
|
678
|
+
throw new Error(`Unsafe OKF target path: ${targetPath}`);
|
|
679
|
+
return resolved;
|
|
680
|
+
}
|
|
681
|
+
function toOkfRelativePath(okfDir, path) {
|
|
682
|
+
return relative(okfDir, path).replace(/\\/gu, "/");
|
|
683
|
+
}
|
|
684
|
+
function sanitizeSlug(value) {
|
|
685
|
+
const slug = value.trim().toLowerCase().replace(/[^a-z0-9._/-]+/gu, "-").replace(/\/+/gu, "/").replace(/^-+|-+$/gu, "");
|
|
686
|
+
return slug === "" ? "unknown" : slug;
|
|
687
|
+
}
|
|
688
|
+
function titleFromSlug(value) {
|
|
689
|
+
return value.replace(/\.md$/u, "").split(/[/-]/u).filter(Boolean).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
690
|
+
}
|
|
691
|
+
function escapeRegExp(value) {
|
|
692
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
693
|
+
}
|
|
694
|
+
function todayIsoDate() {
|
|
695
|
+
return new Date().toISOString().slice(0, 10);
|
|
696
|
+
}
|
|
697
|
+
async function writeJson(path, value, options = {}) {
|
|
698
|
+
await mkdir(dirname(path), { recursive: true });
|
|
699
|
+
const flag = options.overwrite === true ? "w" : "wx";
|
|
700
|
+
await writeFile(path, `${JSON.stringify(value, null, 2)}
|
|
701
|
+
`, { encoding: "utf8", flag });
|
|
702
|
+
}
|
|
703
|
+
async function pathExists(path) {
|
|
704
|
+
try {
|
|
705
|
+
await stat(path);
|
|
706
|
+
return true;
|
|
707
|
+
} catch (error) {
|
|
708
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
709
|
+
return false;
|
|
710
|
+
throw error;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// packages/core/src/evolution/index.ts
|
|
715
|
+
var PROCESS_LOCK_STALE_MS = 5 * 60 * 1000;
|
|
716
|
+
var FORBIDDEN_RAW_KEYS = new Set([
|
|
717
|
+
"commandhistory",
|
|
718
|
+
"commandoutput",
|
|
719
|
+
"credential",
|
|
720
|
+
"credentials",
|
|
721
|
+
"env",
|
|
722
|
+
"fullsource",
|
|
723
|
+
"memorybody",
|
|
724
|
+
"password",
|
|
725
|
+
"privatekey",
|
|
726
|
+
"prompt",
|
|
727
|
+
"promptbody",
|
|
728
|
+
"prompttext",
|
|
729
|
+
"rawcommand",
|
|
730
|
+
"rawcommandoutput",
|
|
731
|
+
"rawlog",
|
|
732
|
+
"rawlogs",
|
|
733
|
+
"rawoutput",
|
|
734
|
+
"rawpayload",
|
|
735
|
+
"rawprompt",
|
|
736
|
+
"secret",
|
|
737
|
+
"secretvalue",
|
|
738
|
+
"source",
|
|
739
|
+
"sourcebody",
|
|
740
|
+
"sourcecode",
|
|
741
|
+
"sourcecontent",
|
|
742
|
+
"sourcetext",
|
|
743
|
+
"stderr",
|
|
744
|
+
"stdout",
|
|
745
|
+
"token",
|
|
746
|
+
"transcript",
|
|
747
|
+
"transcriptbody",
|
|
748
|
+
"transcripttext"
|
|
749
|
+
]);
|
|
750
|
+
|
|
101
751
|
// packages/core/src/task/index.ts
|
|
102
752
|
var FORBIDDEN_TASK_WRITE_SEGMENTS = new Set([".claude", ".codex"]);
|
|
103
753
|
var FORBIDDEN_PROJECT_ASSET_SEGMENTS = new Set(["packages", "src"]);
|
|
104
754
|
var FORBIDDEN_TASK_WRITE_FILES = new Set(["agents.md", "claude.md", "package.json", "readme.md"]);
|
|
105
|
-
var
|
|
755
|
+
var FORBIDDEN_RAW_KEYS2 = new Set([
|
|
106
756
|
"rawoutput",
|
|
107
757
|
"raw_output",
|
|
108
758
|
"stdout",
|
|
@@ -134,6 +784,71 @@ var ALLOWED_VERIFICATION_KEYS = new Set([
|
|
|
134
784
|
"type"
|
|
135
785
|
]);
|
|
136
786
|
|
|
787
|
+
// packages/core/src/team/prompts.ts
|
|
788
|
+
var TEAM_ROLE_STARTUP_PROMPT_TEMPLATE = [
|
|
789
|
+
"You are an EvoDev managed role agent.",
|
|
790
|
+
"Team run: {{runId}}",
|
|
791
|
+
"Repository: {{repoRoot}}",
|
|
792
|
+
"Role id: {{roleId}}",
|
|
793
|
+
"Role name: {{roleName}}",
|
|
794
|
+
"Runtime: {{runtime}}",
|
|
795
|
+
"Native Code Agent binding: {{nativeAgentBinding}}",
|
|
796
|
+
"Model: {{model}}",
|
|
797
|
+
"Thinking level: {{thinkingLevel}}",
|
|
798
|
+
"Write mode: {{writeMode}}",
|
|
799
|
+
"Transcript recording: {{transcriptRecording}}",
|
|
800
|
+
"",
|
|
801
|
+
"Current known agents:",
|
|
802
|
+
"{{roster}}",
|
|
803
|
+
"",
|
|
804
|
+
"EvoDev team runtime control contract:",
|
|
805
|
+
"This run is already inside the EvoDev-managed team runtime.",
|
|
806
|
+
"For EvoDev role-agent lifecycle, use the current EvoDev run control plane.",
|
|
807
|
+
"Unprefixed user requests such as 'start the team', 'execute team', 'create agents', or 'spawn roles' mean: use the current EvoDev run control plane.",
|
|
808
|
+
"Do not answer those requests with only a role plan when a role agent should be created.",
|
|
809
|
+
"",
|
|
810
|
+
"Use Teams MCP as the primary control plane:",
|
|
811
|
+
"- list_agents: discover current EvoDev role agents.",
|
|
812
|
+
"- spawn_role: create or reuse exactly one EvoDev role agent.",
|
|
813
|
+
"- send_message: communicate through the EvoDev broker.",
|
|
814
|
+
"- stop_role: stop a role agent when allowed.",
|
|
815
|
+
"If Teams MCP is unavailable, fall back to the EvoDev CLI from this repository:",
|
|
816
|
+
"- evodev team spawn --role <roleId>",
|
|
817
|
+
"- evodev team send --to <roleId> --message <text>",
|
|
818
|
+
"- evodev team status",
|
|
819
|
+
"Teams MCP defaults are inherited from the environment:",
|
|
820
|
+
"EVODEV_TEAM_RUN_ID={{runId}}",
|
|
821
|
+
"EVODEV_TEAM_ROLE_ID={{roleId}}",
|
|
822
|
+
"When calling Teams MCP tools, let the MCP server-bound environment identify this run and role.",
|
|
823
|
+
"Do not operate tmux directly for role lifecycle; let EvoDev create and track panes.",
|
|
824
|
+
"Any server-bound role may request role lifecycle changes; EvoDev records and tracks panes but does not use role policy to stop execution.",
|
|
825
|
+
"{{roleGuidance}}",
|
|
826
|
+
"{{nativeAgentInstruction}}",
|
|
827
|
+
"Team messages are durably queued and delivered at hook safe points, not pasted into a live prompt. cc values are audit context; they are not an instruction for main to immediately forward or act.",
|
|
828
|
+
"{{scopedContext}}",
|
|
829
|
+
"",
|
|
830
|
+
"{{rolePrompt}}"
|
|
831
|
+
].join(`
|
|
832
|
+
`);
|
|
833
|
+
var MAIN_ROLE_GUIDANCE = [
|
|
834
|
+
"As main, you are the planner and delegator for complex work, not a standby worker.",
|
|
835
|
+
"On each user prompt or hook-delivered inbox message, decide whether to answer directly, ask for clarification, or use team execution.",
|
|
836
|
+
"Use team execution only when role separation improves correctness, coverage, safety, or latency.",
|
|
837
|
+
"When team execution is needed, create an upfront task plan with required role ids, role-specific assignments, dependencies, and runnable batches.",
|
|
838
|
+
"Spawn or reuse all roles needed for the first runnable batch and send each role a self-contained task message.",
|
|
839
|
+
"After all currently runnable tasks are delegated, finish your current turn immediately; do not call sleep, wait idly, poll list_agents/status, or keep the turn alive to watch progress.",
|
|
840
|
+
"Use list_agents only for one-time roster discovery when the current roster is genuinely unknown, never as a progress check.",
|
|
841
|
+
"Resume coordination only when the user sends new input or a role message is delivered by hooks; then decide whether to adjust tasks, send supplemental instructions, spawn dependent roles, synthesize completed results, or ask the user.",
|
|
842
|
+
"While delegated role work is pending, do not perform concrete implementation, testing, package research, or review work yourself."
|
|
843
|
+
].join(" ");
|
|
844
|
+
|
|
845
|
+
// packages/core/src/team/index.ts
|
|
846
|
+
var TEAM_INTERNAL_WAKE_SIGNAL = [
|
|
847
|
+
"[EvoDev internal wake signal]",
|
|
848
|
+
"No user request is included in this message. Continue only from EvoDev team inbox messages injected by hooks."
|
|
849
|
+
].join(`
|
|
850
|
+
`);
|
|
851
|
+
|
|
137
852
|
// packages/core/src/hooks/index.ts
|
|
138
853
|
var CANONICAL_HOOK_EVENT_TYPES = [
|
|
139
854
|
"SessionStart",
|
|
@@ -162,41 +877,55 @@ var CANONICAL_HOOK_EVENT_TYPES = [
|
|
|
162
877
|
"WorktreeRemove"
|
|
163
878
|
];
|
|
164
879
|
var DEFAULT_EVENT_SETTINGS = {
|
|
165
|
-
SessionStart:
|
|
166
|
-
UserPromptSubmit:
|
|
167
|
-
UserPromptExpansion:
|
|
168
|
-
PreToolUse:
|
|
169
|
-
PermissionRequest:
|
|
170
|
-
PostToolUse:
|
|
171
|
-
PostToolUseFailure:
|
|
172
|
-
PostToolBatch:
|
|
173
|
-
PermissionDenied:
|
|
174
|
-
SubagentStart:
|
|
175
|
-
Stop:
|
|
176
|
-
StopFailure:
|
|
177
|
-
TeammateIdle:
|
|
178
|
-
SubagentStop:
|
|
179
|
-
TaskCreated:
|
|
180
|
-
TaskCompleted:
|
|
181
|
-
PreCompact:
|
|
182
|
-
PostCompact:
|
|
183
|
-
SessionEnd:
|
|
184
|
-
ConfigChange:
|
|
185
|
-
CwdChanged:
|
|
186
|
-
FileChanged:
|
|
187
|
-
WorktreeCreate:
|
|
188
|
-
WorktreeRemove:
|
|
880
|
+
SessionStart: true,
|
|
881
|
+
UserPromptSubmit: true,
|
|
882
|
+
UserPromptExpansion: true,
|
|
883
|
+
PreToolUse: true,
|
|
884
|
+
PermissionRequest: true,
|
|
885
|
+
PostToolUse: true,
|
|
886
|
+
PostToolUseFailure: true,
|
|
887
|
+
PostToolBatch: true,
|
|
888
|
+
PermissionDenied: true,
|
|
889
|
+
SubagentStart: true,
|
|
890
|
+
Stop: true,
|
|
891
|
+
StopFailure: true,
|
|
892
|
+
TeammateIdle: true,
|
|
893
|
+
SubagentStop: true,
|
|
894
|
+
TaskCreated: true,
|
|
895
|
+
TaskCompleted: true,
|
|
896
|
+
PreCompact: true,
|
|
897
|
+
PostCompact: true,
|
|
898
|
+
SessionEnd: true,
|
|
899
|
+
ConfigChange: true,
|
|
900
|
+
CwdChanged: true,
|
|
901
|
+
FileChanged: true,
|
|
902
|
+
WorktreeCreate: true,
|
|
903
|
+
WorktreeRemove: true
|
|
189
904
|
};
|
|
905
|
+
var TEAM_MESSAGE_DELIVERY_EVENTS = new Set([
|
|
906
|
+
"SessionStart",
|
|
907
|
+
"UserPromptSubmit",
|
|
908
|
+
"PostToolUse",
|
|
909
|
+
"PostToolUseFailure",
|
|
910
|
+
"Stop",
|
|
911
|
+
"TeammateIdle",
|
|
912
|
+
"SubagentStop",
|
|
913
|
+
"TaskCompleted"
|
|
914
|
+
]);
|
|
915
|
+
var CODEX_STOP_EVENTS_WITHOUT_ADDITIONAL_CONTEXT = new Set([
|
|
916
|
+
"Stop",
|
|
917
|
+
"SubagentStop"
|
|
918
|
+
]);
|
|
190
919
|
function createDefaultHookSettings() {
|
|
191
920
|
return {
|
|
192
|
-
enabled:
|
|
921
|
+
enabled: true,
|
|
193
922
|
targets: {
|
|
194
923
|
claude: {
|
|
195
|
-
enabled:
|
|
924
|
+
enabled: true,
|
|
196
925
|
events: { ...DEFAULT_EVENT_SETTINGS }
|
|
197
926
|
},
|
|
198
927
|
codex: {
|
|
199
|
-
enabled:
|
|
928
|
+
enabled: true,
|
|
200
929
|
events: { ...DEFAULT_EVENT_SETTINGS }
|
|
201
930
|
}
|
|
202
931
|
},
|
|
@@ -217,6 +946,9 @@ function parseHookSettings(value) {
|
|
|
217
946
|
return defaults;
|
|
218
947
|
if (!isRecord(value))
|
|
219
948
|
throw new Error("Invalid hooks settings; expected object.");
|
|
949
|
+
const observability = isRecord(value.observability) ? value.observability : undefined;
|
|
950
|
+
optionalBoolean(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
|
|
951
|
+
optionalBoolean(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
|
|
220
952
|
return {
|
|
221
953
|
enabled: optionalBoolean(value.enabled, defaults.enabled, "hooks.enabled"),
|
|
222
954
|
targets: {
|
|
@@ -226,7 +958,7 @@ function parseHookSettings(value) {
|
|
|
226
958
|
observability: {
|
|
227
959
|
metadataOnly: true,
|
|
228
960
|
rawPayloadStorage: false,
|
|
229
|
-
appendEvents:
|
|
961
|
+
appendEvents: optionalBoolean(observability?.appendEvents, defaults.observability.appendEvents, "hooks.observability.appendEvents")
|
|
230
962
|
},
|
|
231
963
|
learning: {
|
|
232
964
|
emitCandidates: false,
|
|
@@ -286,7 +1018,26 @@ function createDefaultSettings(os = process.platform) {
|
|
|
286
1018
|
doctor: {
|
|
287
1019
|
lastRunAt: null
|
|
288
1020
|
},
|
|
289
|
-
hooks: createDefaultHookSettings()
|
|
1021
|
+
hooks: createDefaultHookSettings(),
|
|
1022
|
+
teamRuntime: createDefaultTeamRuntimeSettings(),
|
|
1023
|
+
memory: createDefaultMemorySettings()
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
function createDefaultTeamRuntimeSettings() {
|
|
1027
|
+
return {
|
|
1028
|
+
defaultRuntime: "codex",
|
|
1029
|
+
defaultModel: null,
|
|
1030
|
+
defaultThinkingLevel: null,
|
|
1031
|
+
recordTranscript: false,
|
|
1032
|
+
displayMode: "normal"
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
function createDefaultMemorySettings() {
|
|
1036
|
+
return {
|
|
1037
|
+
autoAccept: true,
|
|
1038
|
+
runtimeInjection: true,
|
|
1039
|
+
staleReview: true,
|
|
1040
|
+
lexicalIndex: true
|
|
290
1041
|
};
|
|
291
1042
|
}
|
|
292
1043
|
function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
@@ -321,10 +1072,28 @@ function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
|
321
1072
|
...defaults.doctor,
|
|
322
1073
|
...existing.doctor
|
|
323
1074
|
},
|
|
324
|
-
hooks: existing.hooks ?? defaults.hooks
|
|
1075
|
+
hooks: existing.hooks ?? defaults.hooks,
|
|
1076
|
+
teamRuntime: {
|
|
1077
|
+
...defaults.teamRuntime,
|
|
1078
|
+
...existing.teamRuntime
|
|
1079
|
+
},
|
|
1080
|
+
memory: {
|
|
1081
|
+
...defaults.memory,
|
|
1082
|
+
...existing.memory
|
|
1083
|
+
}
|
|
325
1084
|
};
|
|
326
1085
|
return parseSettings(merged);
|
|
327
1086
|
}
|
|
1087
|
+
async function readRuntimeInjectionSettings(homeDir) {
|
|
1088
|
+
const paths = resolveEvoDevPaths(homeDir);
|
|
1089
|
+
try {
|
|
1090
|
+
return parseSettings(JSON.parse(await readFile2(paths.settingsPath, "utf8"))).memory;
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
if (isNotFoundError(error))
|
|
1093
|
+
return createDefaultMemorySettings();
|
|
1094
|
+
throw error;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
328
1097
|
function parseSettings(value) {
|
|
329
1098
|
const root = expectRecord2(value, "settings");
|
|
330
1099
|
const version = root.version;
|
|
@@ -355,10 +1124,44 @@ function parseSettings(value) {
|
|
|
355
1124
|
doctor: {
|
|
356
1125
|
lastRunAt: expectNullableString(doctor.lastRunAt, "settings.doctor.lastRunAt")
|
|
357
1126
|
},
|
|
358
|
-
hooks: parseHookSettings(root.hooks)
|
|
1127
|
+
hooks: parseHookSettings(root.hooks),
|
|
1128
|
+
teamRuntime: parseTeamRuntimeSettings(root.teamRuntime ?? createDefaultTeamRuntimeSettings(), "settings.teamRuntime"),
|
|
1129
|
+
memory: parseMemorySettings(root.memory ?? createDefaultMemorySettings(), "settings.memory")
|
|
359
1130
|
};
|
|
360
1131
|
return parsed;
|
|
361
1132
|
}
|
|
1133
|
+
function parseMemorySettings(value, path) {
|
|
1134
|
+
const input = expectRecord2(value, path);
|
|
1135
|
+
const defaults = createDefaultMemorySettings();
|
|
1136
|
+
return {
|
|
1137
|
+
autoAccept: input.autoAccept === undefined ? defaults.autoAccept : expectBoolean(input.autoAccept, `${path}.autoAccept`),
|
|
1138
|
+
runtimeInjection: input.runtimeInjection === undefined ? defaults.runtimeInjection : expectBoolean(input.runtimeInjection, `${path}.runtimeInjection`),
|
|
1139
|
+
staleReview: input.staleReview === undefined ? defaults.staleReview : expectBoolean(input.staleReview, `${path}.staleReview`),
|
|
1140
|
+
lexicalIndex: input.lexicalIndex === undefined ? defaults.lexicalIndex : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`)
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
function parseTeamRuntimeSettings(value, path) {
|
|
1144
|
+
const input = expectRecord2(value, path);
|
|
1145
|
+
const defaults = createDefaultTeamRuntimeSettings();
|
|
1146
|
+
const defaultRuntime = input.defaultRuntime ?? defaults.defaultRuntime;
|
|
1147
|
+
if (defaultRuntime !== "codex" && defaultRuntime !== "claude") {
|
|
1148
|
+
throw new EvoDevConfigError(`Invalid ${path}.defaultRuntime; expected codex or claude`);
|
|
1149
|
+
}
|
|
1150
|
+
return {
|
|
1151
|
+
defaultRuntime,
|
|
1152
|
+
defaultModel: input.defaultModel === undefined ? defaults.defaultModel : expectNullableString(input.defaultModel, `${path}.defaultModel`),
|
|
1153
|
+
defaultThinkingLevel: input.defaultThinkingLevel === undefined ? defaults.defaultThinkingLevel : expectNullableString(input.defaultThinkingLevel, `${path}.defaultThinkingLevel`),
|
|
1154
|
+
recordTranscript: input.recordTranscript === undefined ? defaults.recordTranscript : expectBoolean(input.recordTranscript, `${path}.recordTranscript`),
|
|
1155
|
+
displayMode: parseTeamRuntimeDisplayMode(input.displayMode, defaults.displayMode, path)
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
function parseTeamRuntimeDisplayMode(value, fallback, path) {
|
|
1159
|
+
if (value === undefined)
|
|
1160
|
+
return fallback;
|
|
1161
|
+
if (value === "normal" || value === "development")
|
|
1162
|
+
return value;
|
|
1163
|
+
throw new EvoDevConfigError(`Invalid ${path}.displayMode; expected normal or development`);
|
|
1164
|
+
}
|
|
362
1165
|
function parsePluginSettings(value, path) {
|
|
363
1166
|
const input = expectRecord2(value, path);
|
|
364
1167
|
const parsed = {
|
|
@@ -378,6 +1181,9 @@ function expectRecord2(value, path) {
|
|
|
378
1181
|
}
|
|
379
1182
|
return value;
|
|
380
1183
|
}
|
|
1184
|
+
function isNotFoundError(error) {
|
|
1185
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1186
|
+
}
|
|
381
1187
|
function expectString2(value, path) {
|
|
382
1188
|
if (typeof value !== "string" || value.length === 0) {
|
|
383
1189
|
throw new EvoDevConfigError(`Invalid ${path}; expected non-empty string`);
|
|
@@ -477,14 +1283,23 @@ function expectNonNegativeInteger(value, path) {
|
|
|
477
1283
|
return value;
|
|
478
1284
|
}
|
|
479
1285
|
// packages/core/src/config/store.ts
|
|
480
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
481
|
-
import { dirname } from "node:path";
|
|
1286
|
+
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
1287
|
+
import { dirname as dirname2 } from "node:path";
|
|
482
1288
|
function createCoreConfigStore(homeDir) {
|
|
483
1289
|
const paths = resolveEvoDevPaths(homeDir);
|
|
484
1290
|
return {
|
|
485
1291
|
paths,
|
|
486
1292
|
async ensureBaseDirs() {
|
|
487
|
-
await
|
|
1293
|
+
await mkdir2(paths.stateDir, { recursive: true });
|
|
1294
|
+
await mkdir2(paths.logsDir, { recursive: true });
|
|
1295
|
+
await mkdir2(paths.knowledgeDir, { recursive: true });
|
|
1296
|
+
await mkdir2(paths.evosCasesDir, { recursive: true });
|
|
1297
|
+
await mkdir2(paths.roleAgentsDir, { recursive: true });
|
|
1298
|
+
await mkdir2(paths.teamsDir, { recursive: true });
|
|
1299
|
+
await mkdir2(paths.runsDir, { recursive: true });
|
|
1300
|
+
},
|
|
1301
|
+
async ensureKnowledgeBase() {
|
|
1302
|
+
await ensureKnowledgeBaseFiles(paths);
|
|
488
1303
|
},
|
|
489
1304
|
async readSettings() {
|
|
490
1305
|
return readJsonFile(paths.settingsPath, parseSettings);
|
|
@@ -521,16 +1336,88 @@ function createCoreConfigStore(homeDir) {
|
|
|
521
1336
|
async function initializeCoreConfig(homeDir) {
|
|
522
1337
|
const store = createCoreConfigStore(homeDir);
|
|
523
1338
|
await store.ensureBaseDirs();
|
|
1339
|
+
await store.ensureKnowledgeBase();
|
|
524
1340
|
await writeIfMissing(store.paths.settingsPath, createDefaultSettings());
|
|
525
1341
|
await writeIfMissing(store.paths.registryPath, createDefaultRegistry());
|
|
526
1342
|
await writeIfMissing(store.paths.installStatePath, createDefaultInstallState());
|
|
527
1343
|
await writeIfMissing(store.paths.syncStatePath, createDefaultSyncState());
|
|
528
1344
|
return store;
|
|
529
1345
|
}
|
|
1346
|
+
async function ensureKnowledgeBaseFiles(paths) {
|
|
1347
|
+
await mkdir2(paths.knowledgeDir, { recursive: true });
|
|
1348
|
+
await mkdir2(paths.evosCasesDir, { recursive: true });
|
|
1349
|
+
await ensureOkfKnowledgeBase(paths.homeDir);
|
|
1350
|
+
await writeTextIfMissing2(`${paths.knowledgeDir}/README.md`, [
|
|
1351
|
+
"# EvoDev Knowledge",
|
|
1352
|
+
"",
|
|
1353
|
+
"Local-private knowledge base for user-accepted facts, decisions, architecture notes, and reusable domain context.",
|
|
1354
|
+
"",
|
|
1355
|
+
"EvoDev must not populate this directory from source code, prompts, command output, logs, or transcripts without an explicit consent flow.",
|
|
1356
|
+
""
|
|
1357
|
+
].join(`
|
|
1358
|
+
`));
|
|
1359
|
+
await writeIndexIfMissingOrMigrate(paths.knowledgeIndexPath, "knowledge-index", {
|
|
1360
|
+
version: 1,
|
|
1361
|
+
kind: "knowledge-index",
|
|
1362
|
+
roleTags: [],
|
|
1363
|
+
entries: []
|
|
1364
|
+
});
|
|
1365
|
+
await writeTextIfMissing2(`${paths.evosDir}/README.md`, [
|
|
1366
|
+
"# EvoDev Evos",
|
|
1367
|
+
"",
|
|
1368
|
+
"Local-private evolution case library for reviewed improvement cases and reusable process changes.",
|
|
1369
|
+
"",
|
|
1370
|
+
"Cases start empty. Future automation may propose candidates, but accepted evos require explicit review before they can influence workflows or routing.",
|
|
1371
|
+
""
|
|
1372
|
+
].join(`
|
|
1373
|
+
`));
|
|
1374
|
+
await writeTextIfMissing2(`${paths.evosCasesDir}/README.md`, [
|
|
1375
|
+
"# Evolution Cases",
|
|
1376
|
+
"",
|
|
1377
|
+
"Store one reviewed evolution case per file. Do not store raw prompts, source dumps, secrets, transcripts, or raw command output here.",
|
|
1378
|
+
""
|
|
1379
|
+
].join(`
|
|
1380
|
+
`));
|
|
1381
|
+
await writeIndexIfMissingOrMigrate(paths.evosIndexPath, "evos-index", {
|
|
1382
|
+
version: 1,
|
|
1383
|
+
kind: "evos-index",
|
|
1384
|
+
roleTags: [],
|
|
1385
|
+
cases: []
|
|
1386
|
+
});
|
|
1387
|
+
await writeTextIfMissing2(`${paths.roleAgentsDir}/README.md`, [
|
|
1388
|
+
"# Role Agents",
|
|
1389
|
+
"",
|
|
1390
|
+
"Local-private role agent registry for EvoDev-managed agent roles and user-reviewed role extensions.",
|
|
1391
|
+
"",
|
|
1392
|
+
"Repository-specific role agents should be proposed first and written into a user repository only after explicit project opt-in.",
|
|
1393
|
+
""
|
|
1394
|
+
].join(`
|
|
1395
|
+
`));
|
|
1396
|
+
await writeIndexIfMissingOrMigrate(paths.roleAgentsIndexPath, "role-agent-index", {
|
|
1397
|
+
version: 1,
|
|
1398
|
+
kind: "role-agent-index",
|
|
1399
|
+
roles: [],
|
|
1400
|
+
projectExtensions: []
|
|
1401
|
+
});
|
|
1402
|
+
await writeTextIfMissing2(`${paths.teamsDir}/README.md`, [
|
|
1403
|
+
"# Agent Teams",
|
|
1404
|
+
"",
|
|
1405
|
+
"Local-private EvoHub team registry for reviewed role-agent team definitions.",
|
|
1406
|
+
"",
|
|
1407
|
+
"Teams may reference role agents and role-tagged knowledge, but they must not contain raw source, prompts, transcripts, secrets, or raw command output.",
|
|
1408
|
+
""
|
|
1409
|
+
].join(`
|
|
1410
|
+
`));
|
|
1411
|
+
await writeIndexIfMissingOrMigrate(paths.teamsIndexPath, "agent-team-index", {
|
|
1412
|
+
version: 1,
|
|
1413
|
+
kind: "agent-team-index",
|
|
1414
|
+
teams: []
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
530
1417
|
async function readJsonFile(filePath, parse) {
|
|
531
1418
|
let raw;
|
|
532
1419
|
try {
|
|
533
|
-
raw = await
|
|
1420
|
+
raw = await readFile3(filePath, "utf8");
|
|
534
1421
|
} catch (error) {
|
|
535
1422
|
throw new EvoDevConfigError(`Cannot read config file (${describeFileError(error)})`, filePath);
|
|
536
1423
|
}
|
|
@@ -561,7 +1448,7 @@ async function readJsonFileOrDefault(filePath, parse, fallback) {
|
|
|
561
1448
|
}
|
|
562
1449
|
async function writeIfMissing(filePath, value) {
|
|
563
1450
|
try {
|
|
564
|
-
await
|
|
1451
|
+
await readFile3(filePath, "utf8");
|
|
565
1452
|
} catch (error) {
|
|
566
1453
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
567
1454
|
await writeJsonFile(filePath, value);
|
|
@@ -570,9 +1457,45 @@ async function writeIfMissing(filePath, value) {
|
|
|
570
1457
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
571
1458
|
}
|
|
572
1459
|
}
|
|
1460
|
+
async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
|
|
1461
|
+
let raw;
|
|
1462
|
+
try {
|
|
1463
|
+
raw = await readFile3(filePath, "utf8");
|
|
1464
|
+
} catch (error) {
|
|
1465
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1466
|
+
await writeJsonFile(filePath, defaults);
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
1470
|
+
}
|
|
1471
|
+
let existing;
|
|
1472
|
+
try {
|
|
1473
|
+
existing = JSON.parse(raw);
|
|
1474
|
+
} catch (error) {
|
|
1475
|
+
throw new EvoDevConfigError(`Invalid bootstrap index JSON (${describeFileError(error)})`, filePath);
|
|
1476
|
+
}
|
|
1477
|
+
if (!isRecord2(existing) || existing.kind !== kind)
|
|
1478
|
+
return;
|
|
1479
|
+
const migrated = { ...defaults, ...existing };
|
|
1480
|
+
if (Object.keys(defaults).every((key) => (key in existing)))
|
|
1481
|
+
return;
|
|
1482
|
+
await writeJsonFile(filePath, migrated);
|
|
1483
|
+
}
|
|
1484
|
+
async function writeTextIfMissing2(filePath, value) {
|
|
1485
|
+
try {
|
|
1486
|
+
await readFile3(filePath, "utf8");
|
|
1487
|
+
} catch (error) {
|
|
1488
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1489
|
+
await mkdir2(dirname2(filePath), { recursive: true });
|
|
1490
|
+
await writeFile2(filePath, value, "utf8");
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
573
1496
|
async function writeJsonFile(filePath, value) {
|
|
574
|
-
await
|
|
575
|
-
await
|
|
1497
|
+
await mkdir2(dirname2(filePath), { recursive: true });
|
|
1498
|
+
await writeFile2(filePath, `${JSON.stringify(value, null, 2)}
|
|
576
1499
|
`, "utf8");
|
|
577
1500
|
}
|
|
578
1501
|
function describeFileError(error) {
|
|
@@ -584,17 +1507,23 @@ function describeFileError(error) {
|
|
|
584
1507
|
function isNodeError(error) {
|
|
585
1508
|
return error instanceof Error && "code" in error;
|
|
586
1509
|
}
|
|
1510
|
+
function isRecord2(value) {
|
|
1511
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1512
|
+
}
|
|
587
1513
|
export {
|
|
588
1514
|
resolveEvoDevPaths,
|
|
1515
|
+
readRuntimeInjectionSettings,
|
|
589
1516
|
parseSyncState,
|
|
590
1517
|
parseSettings,
|
|
591
1518
|
parseRegistry,
|
|
592
1519
|
parseInstallState,
|
|
593
1520
|
mergeSettings,
|
|
594
1521
|
initializeCoreConfig,
|
|
1522
|
+
createDefaultTeamRuntimeSettings,
|
|
595
1523
|
createDefaultSyncState,
|
|
596
1524
|
createDefaultSettings,
|
|
597
1525
|
createDefaultRegistry,
|
|
1526
|
+
createDefaultMemorySettings,
|
|
598
1527
|
createDefaultInstallState,
|
|
599
1528
|
createCoreConfigStore,
|
|
600
1529
|
EvoDevConfigError
|