@evo-dev/core 0.0.1-alpha.2 → 0.0.1-alpha.20
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/skills/coding/knowledge-distillation/SKILL.md +5 -3
- package/assets/team/agents/code-reviewer.md +48 -0
- package/assets/team/agents/docs-maintainer.md +51 -0
- package/assets/team/agents/implementation-engineer.md +51 -0
- package/assets/team/agents/product-scope-analyst.md +58 -0
- package/assets/team/agents/release-engineer.md +55 -0
- package/assets/team/agents/security-boundary-reviewer.md +50 -0
- package/assets/team/agents/solution-architect.md +51 -0
- package/assets/team/agents/verification-engineer.md +51 -0
- package/assets/team/team.md +102 -0
- package/dist/assets/index.js +5 -5
- package/dist/config/index.js +793 -241
- package/dist/index.js +20840 -12908
- package/dist/plugins/index.js +13 -13
- package/package.json +1 -1
- package/src/agents/index.ts +1 -265
- package/src/code-agent-traces/index.ts +11 -12
- package/src/config/index.ts +2 -0
- package/src/config/settings.ts +116 -7
- package/src/config/store.ts +1 -1
- package/src/daemon/index.ts +1 -41
- package/src/evolution/candidates/index.ts +730 -0
- package/src/evolution/control/index.ts +20 -0
- package/src/evolution/evidence/analysis.ts +533 -0
- package/src/evolution/evidence/index.ts +3 -0
- package/src/evolution/evidence/session-memory/analysis.ts +287 -0
- package/src/evolution/evidence/session-memory/constants.ts +9 -0
- package/src/evolution/evidence/session-memory/index.ts +9 -0
- package/src/evolution/evidence/session-memory/paths.ts +29 -0
- package/src/evolution/evidence/session-memory/policy.ts +39 -0
- package/src/evolution/evidence/session-memory/retention.ts +643 -0
- package/src/evolution/evidence/session-memory/segment.ts +216 -0
- package/src/evolution/evidence/session-memory/semantic-packet.ts +408 -0
- package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
- package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
- package/src/evolution/evidence/session-memory/storage.ts +744 -0
- package/src/evolution/evidence/session-memory/types.ts +296 -0
- package/src/evolution/evidence/session-memory/updater.ts +199 -0
- package/src/evolution/formatters.ts +169 -0
- package/src/evolution/imports/apply.ts +435 -0
- package/src/evolution/imports/diff.ts +472 -0
- package/src/evolution/imports/index.ts +7 -0
- package/src/evolution/imports/materialize.ts +640 -0
- package/src/evolution/imports/paths.ts +129 -0
- package/src/evolution/imports/stage.ts +414 -0
- package/src/evolution/imports/storage.ts +952 -0
- package/src/evolution/imports/types.ts +226 -0
- package/src/evolution/index.ts +19 -2827
- package/src/evolution/knowledge/change-store.ts +558 -0
- package/src/evolution/knowledge/changes.ts +459 -0
- package/src/evolution/knowledge/freshness.ts +69 -0
- package/src/{knowledge → evolution/knowledge}/index.ts +1532 -206
- package/src/evolution/knowledge/review.ts +446 -0
- package/src/evolution/knowledge/support.ts +135 -0
- package/src/evolution/paths.ts +44 -0
- package/src/evolution/processor/distillation.ts +518 -0
- package/src/evolution/processor/index.ts +3 -0
- package/src/evolution/processor/process.ts +594 -0
- package/src/{learning → evolution/review}/index.ts +10 -14
- package/src/evolution/schema.ts +639 -0
- package/src/evolution/shared.ts +1053 -0
- package/src/evolution/triggers/classification.ts +102 -0
- package/src/evolution/triggers/index.ts +295 -0
- package/src/hooks/index.ts +281 -197
- package/src/index.ts +15 -4
- package/src/projects/index.ts +934 -0
- package/src/runtime-logs/index.ts +100 -13
- package/src/team/index.ts +582 -3
- package/src/utils/errors.ts +13 -0
- package/src/utils/fs.ts +40 -0
- package/src/utils/hash.ts +9 -0
- package/src/utils/ids.ts +12 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/parsing.ts +11 -0
- package/src/utils/text.ts +18 -0
- package/src/utils/time.ts +5 -0
- package/src/workflow/index.ts +3 -21
- package/src/project/index.ts +0 -507
- package/src/task/index.ts +0 -840
package/dist/config/index.js
CHANGED
|
@@ -117,9 +117,164 @@ function expectString(value, path) {
|
|
|
117
117
|
return value;
|
|
118
118
|
}
|
|
119
119
|
// packages/core/src/config/settings.ts
|
|
120
|
-
import { readFile as
|
|
120
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
121
|
+
|
|
122
|
+
// packages/core/src/utils/errors.ts
|
|
123
|
+
function isNotFoundError(error) {
|
|
124
|
+
return error instanceof Error && (("code" in error) && error.code === "ENOENT" || error.message.includes("ENOENT"));
|
|
125
|
+
}
|
|
126
|
+
// packages/core/src/utils/hash.ts
|
|
127
|
+
import { createHash } from "node:crypto";
|
|
128
|
+
function sha256Hex(value) {
|
|
129
|
+
return createHash("sha256").update(value).digest("hex");
|
|
130
|
+
}
|
|
131
|
+
function sha256Short(value, length = 16) {
|
|
132
|
+
return sha256Hex(value).slice(0, length);
|
|
133
|
+
}
|
|
134
|
+
// packages/core/src/utils/ids.ts
|
|
135
|
+
function sanitizeStorageId(value, fallbackPrefix) {
|
|
136
|
+
const sanitized = value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120);
|
|
137
|
+
return sanitized === "" || sanitized === "." || sanitized === ".." ? `${fallbackPrefix}-local` : sanitized;
|
|
138
|
+
}
|
|
139
|
+
// packages/core/src/utils/parsing.ts
|
|
140
|
+
function optionalBoolean(value, fallback) {
|
|
141
|
+
return typeof value === "boolean" ? value : fallback;
|
|
142
|
+
}
|
|
143
|
+
function positiveInteger(value, fallback) {
|
|
144
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : fallback;
|
|
145
|
+
}
|
|
146
|
+
// packages/core/src/evolution/evidence/session-memory/sensitivity.ts
|
|
147
|
+
var SESSION_MEMORY_CREDENTIAL_REDACTION = "[credential-redacted]";
|
|
148
|
+
var CREDENTIAL_FIELD_KEYS = new Set([
|
|
149
|
+
"accesstoken",
|
|
150
|
+
"apikey",
|
|
151
|
+
"auth",
|
|
152
|
+
"authtoken",
|
|
153
|
+
"authorization",
|
|
154
|
+
"clientsecret",
|
|
155
|
+
"cookie",
|
|
156
|
+
"credential",
|
|
157
|
+
"credentials",
|
|
158
|
+
"idtoken",
|
|
159
|
+
"password",
|
|
160
|
+
"passwd",
|
|
161
|
+
"privatekey",
|
|
162
|
+
"proxyauthorization",
|
|
163
|
+
"refreshtoken",
|
|
164
|
+
"secret",
|
|
165
|
+
"secretvalue",
|
|
166
|
+
"sessiontoken",
|
|
167
|
+
"setcookie",
|
|
168
|
+
"signingkey",
|
|
169
|
+
"token"
|
|
170
|
+
]);
|
|
171
|
+
var CREDENTIAL_KEY_PATTERN = String.raw`(?:access[_-]?token|api[_-]?key|auth(?:orization)?|client[_-]?secret|cookie|credential(?:s)?|id[_-]?token|password|passwd|private[_-]?key|proxy[_-]?authorization|refresh[_-]?token|secret(?:[_-]?value)?|session[_-]?token|set[_-]?cookie|signing[_-]?key|token)`;
|
|
172
|
+
var CREDENTIAL_SHAPE_PATTERNS = [
|
|
173
|
+
/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/i,
|
|
174
|
+
/\bAKIA[0-9A-Z]{16}\b/,
|
|
175
|
+
/\bgh[pousr]_[A-Za-z0-9]{20,}\b/,
|
|
176
|
+
/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/,
|
|
177
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]+/i,
|
|
178
|
+
/\bBasic\s+[A-Za-z0-9+/]+={0,2}/i,
|
|
179
|
+
new RegExp(String.raw`(?:^|[^A-Za-z0-9_])["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*["']?[A-Za-z0-9][A-Za-z0-9._~+/=-]*`, "i"),
|
|
180
|
+
new RegExp(String.raw`(?:^|[^A-Za-z0-9_])["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*["'](?!\[credential-redacted\]["'])[^"'\r\n]+["']`, "i")
|
|
181
|
+
];
|
|
182
|
+
var PRIVATE_KEY_BLOCK_PATTERN = /-----BEGIN ([A-Z0-9 ]*PRIVATE KEY)-----[\s\S]*?-----END \1-----/giu;
|
|
183
|
+
var AUTHORIZATION_HEADER_PATTERN = /(^|[\r\n])(\s*(?:authorization|proxy-authorization)\s*:\s*)(?:Bearer|Basic)\s+[^\r\n]+/gimu;
|
|
184
|
+
var COOKIE_HEADER_PATTERN = /(^|[\r\n])(\s*(?:cookie|set-cookie)\s*:\s*)[^\r\n]+/gimu;
|
|
185
|
+
var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
|
|
186
|
+
var BASIC_PATTERN = /\bBasic\s+[A-Za-z0-9+/]+={0,2}/giu;
|
|
187
|
+
var AWS_ACCESS_KEY_PATTERN = /\bAKIA[0-9A-Z]{16}\b/gu;
|
|
188
|
+
var GITHUB_TOKEN_PATTERN = /\bgh[pousr]_[A-Za-z0-9]{20,}\b/gu;
|
|
189
|
+
var SLACK_TOKEN_PATTERN = /\bxox[baprs]-[A-Za-z0-9-]{16,}\b/gu;
|
|
190
|
+
var QUOTED_SERIALIZED_CREDENTIAL_PATTERN = new RegExp(String.raw`(^|[^A-Za-z0-9_])(["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*)(["'])([^"'\r\n]+)(\3)`, "gimu");
|
|
191
|
+
var SERIALIZED_CREDENTIAL_PATTERN = new RegExp(String.raw`(^|[^A-Za-z0-9_])(["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*)(["']?)([A-Za-z0-9][A-Za-z0-9._~+/=-]*)(\3)`, "gimu");
|
|
192
|
+
var URL_USERINFO_PATTERN = /(https?:\/\/)[^@\s/"']+@/giu;
|
|
193
|
+
var URL_CREDENTIAL_PARAMETER_PATTERN = new RegExp(String.raw`([?&#]["']?${CREDENTIAL_KEY_PATTERN}["']?=)[^&#\s"'<>]+`, "giu");
|
|
194
|
+
function redactSessionMemoryCredentialText(value) {
|
|
195
|
+
let redacted = value.replace(PRIVATE_KEY_BLOCK_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(AUTHORIZATION_HEADER_PATTERN, (_, boundary, prefix) => {
|
|
196
|
+
return `${boundary}${prefix}${SESSION_MEMORY_CREDENTIAL_REDACTION}`;
|
|
197
|
+
}).replace(COOKIE_HEADER_PATTERN, (_, boundary, prefix) => {
|
|
198
|
+
return `${boundary}${prefix}${SESSION_MEMORY_CREDENTIAL_REDACTION}`;
|
|
199
|
+
}).replace(BEARER_PATTERN, `Bearer ${SESSION_MEMORY_CREDENTIAL_REDACTION}`).replace(BASIC_PATTERN, `Basic ${SESSION_MEMORY_CREDENTIAL_REDACTION}`).replace(AWS_ACCESS_KEY_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(GITHUB_TOKEN_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(SLACK_TOKEN_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(QUOTED_SERIALIZED_CREDENTIAL_PATTERN, (_, boundary, prefix, quote) => `${boundary}${prefix}${quote}${SESSION_MEMORY_CREDENTIAL_REDACTION}${quote}`).replace(SERIALIZED_CREDENTIAL_PATTERN, (_, boundary, prefix, quote, credentialValue) => {
|
|
200
|
+
const trailingPunctuation = quote === "" ? credentialValue.match(/[.,;!?]+$/u)?.[0] ?? "" : "";
|
|
201
|
+
return `${boundary}${prefix}${quote}${SESSION_MEMORY_CREDENTIAL_REDACTION}${quote}${trailingPunctuation}`;
|
|
202
|
+
}).replace(URL_CREDENTIAL_PARAMETER_PATTERN, (_, prefix) => `${prefix}${SESSION_MEMORY_CREDENTIAL_REDACTION}`).replace(URL_USERINFO_PATTERN, (_, protocol) => protocol);
|
|
203
|
+
if (redacted === "")
|
|
204
|
+
redacted = value;
|
|
205
|
+
return { value: redacted, redacted: redacted !== value };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// packages/core/src/evolution/shared.ts
|
|
209
|
+
var MAX_PROPOSED_CHANGE_LENGTH = 16 * 1024;
|
|
210
|
+
var PROCESS_LOCK_STALE_MS = 5 * 60 * 1000;
|
|
211
|
+
var FORBIDDEN_RAW_KEYS = new Set([
|
|
212
|
+
"commandhistory",
|
|
213
|
+
"commandoutput",
|
|
214
|
+
"credential",
|
|
215
|
+
"credentials",
|
|
216
|
+
"env",
|
|
217
|
+
"fullsource",
|
|
218
|
+
"memorybody",
|
|
219
|
+
"password",
|
|
220
|
+
"privatekey",
|
|
221
|
+
"prompt",
|
|
222
|
+
"promptbody",
|
|
223
|
+
"prompttext",
|
|
224
|
+
"rawcommand",
|
|
225
|
+
"rawcommandoutput",
|
|
226
|
+
"rawlog",
|
|
227
|
+
"rawlogs",
|
|
228
|
+
"rawoutput",
|
|
229
|
+
"rawpayload",
|
|
230
|
+
"rawprompt",
|
|
231
|
+
"secret",
|
|
232
|
+
"secretvalue",
|
|
233
|
+
"source",
|
|
234
|
+
"sourcebody",
|
|
235
|
+
"sourcecode",
|
|
236
|
+
"sourcecontent",
|
|
237
|
+
"sourcetext",
|
|
238
|
+
"stderr",
|
|
239
|
+
"stdout",
|
|
240
|
+
"token",
|
|
241
|
+
"transcript",
|
|
242
|
+
"transcriptbody",
|
|
243
|
+
"transcripttext"
|
|
244
|
+
]);
|
|
245
|
+
// packages/core/src/evolution/evidence/session-memory/policy.ts
|
|
246
|
+
function createDefaultSessionMemoryPolicy() {
|
|
247
|
+
return {
|
|
248
|
+
enabled: true,
|
|
249
|
+
storeRawSegments: true,
|
|
250
|
+
maxRawSegmentBytes: 200000,
|
|
251
|
+
retentionDays: 30,
|
|
252
|
+
minimumMessageTokensToInit: 1e4,
|
|
253
|
+
minimumTokensBetweenUpdate: 5000,
|
|
254
|
+
toolCallsBetweenUpdates: 9
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function parseSessionMemoryPolicy(value) {
|
|
258
|
+
const defaults = createDefaultSessionMemoryPolicy();
|
|
259
|
+
if (value === undefined)
|
|
260
|
+
return defaults;
|
|
261
|
+
return {
|
|
262
|
+
enabled: optionalBoolean(value.enabled, defaults.enabled),
|
|
263
|
+
storeRawSegments: optionalBoolean(value.storeRawSegments, defaults.storeRawSegments),
|
|
264
|
+
maxRawSegmentBytes: positiveInteger(value.maxRawSegmentBytes, defaults.maxRawSegmentBytes),
|
|
265
|
+
retentionDays: positiveInteger(value.retentionDays, defaults.retentionDays),
|
|
266
|
+
minimumMessageTokensToInit: positiveInteger(value.minimumMessageTokensToInit, defaults.minimumMessageTokensToInit),
|
|
267
|
+
minimumTokensBetweenUpdate: positiveInteger(value.minimumTokensBetweenUpdate, defaults.minimumTokensBetweenUpdate),
|
|
268
|
+
toolCallsBetweenUpdates: positiveInteger(value.toolCallsBetweenUpdates, defaults.toolCallsBetweenUpdates)
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// packages/core/src/projects/index.ts
|
|
272
|
+
import { lstat, readFile, readdir, realpath, stat } from "node:fs/promises";
|
|
273
|
+
import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute2, join as join2, parse } from "node:path";
|
|
121
274
|
|
|
122
275
|
// packages/core/src/runtime-logs/index.ts
|
|
276
|
+
import { lstatSync, readFileSync, realpathSync } from "node:fs";
|
|
277
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
123
278
|
var SAFE_EXECUTION_METADATA_KEYS = new Set([
|
|
124
279
|
"phase",
|
|
125
280
|
"runtimeSurface",
|
|
@@ -135,6 +290,7 @@ var SAFE_EXECUTION_METADATA_KEYS = new Set([
|
|
|
135
290
|
"redactionLabels",
|
|
136
291
|
"normalizedEventType"
|
|
137
292
|
]);
|
|
293
|
+
var SENSITIVE_EVENT_TEXT_PATTERN = /https?:\/\/\S+|(^|[^a-z0-9])(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|stdout|stderr|transcript|formattedresponse|additionalcontext)([^a-z0-9]|$)|raw[\s_-]?(payload|prompt|output|source)|source[\s_-]?dump/i;
|
|
138
294
|
var SAFE_REDACTION_LABELS = new Set([
|
|
139
295
|
"raw-command",
|
|
140
296
|
"raw-command-output",
|
|
@@ -142,26 +298,341 @@ var SAFE_REDACTION_LABELS = new Set([
|
|
|
142
298
|
"sensitive-command",
|
|
143
299
|
"sensitive-text"
|
|
144
300
|
]);
|
|
301
|
+
function resolveProjectLogIdentity(homeDir, repoRoot) {
|
|
302
|
+
const identityHomeDir = realpathDirectoryOrFallback(homeDir);
|
|
303
|
+
const workspaceRoot = realpathDirectoryOrFallback(repoRoot);
|
|
304
|
+
const workspaceKey = resolvePathProjectLogKey(identityHomeDir, workspaceRoot);
|
|
305
|
+
const gitCommonDir = resolveGitCommonDir(workspaceRoot);
|
|
306
|
+
if (gitCommonDir === null) {
|
|
307
|
+
return {
|
|
308
|
+
projectKey: workspaceKey,
|
|
309
|
+
workspaceKey,
|
|
310
|
+
projectRoot: workspaceRoot,
|
|
311
|
+
workspaceRoot,
|
|
312
|
+
gitCommonDir: null,
|
|
313
|
+
linkedWorktree: false
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const commonDirOwnsWorktree = basename(gitCommonDir) === ".git";
|
|
317
|
+
const projectIdentityPath = commonDirOwnsWorktree ? dirname(gitCommonDir) : gitCommonDir;
|
|
318
|
+
const projectRoot = commonDirOwnsWorktree ? projectIdentityPath : workspaceRoot;
|
|
319
|
+
return {
|
|
320
|
+
projectKey: resolvePathProjectLogKey(identityHomeDir, projectIdentityPath),
|
|
321
|
+
workspaceKey,
|
|
322
|
+
projectRoot,
|
|
323
|
+
workspaceRoot,
|
|
324
|
+
gitCommonDir,
|
|
325
|
+
linkedWorktree: workspaceKey !== resolvePathProjectLogKey(identityHomeDir, projectIdentityPath)
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function resolvePathProjectLogKey(homeDir, repoRoot) {
|
|
329
|
+
const trimmedHome = stripTrailingSlash2(homeDir);
|
|
330
|
+
const trimmedRepo = stripTrailingSlash2(repoRoot);
|
|
331
|
+
const relativePath = relative(trimmedHome, trimmedRepo);
|
|
332
|
+
const source = relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath) ? relativePath : trimmedRepo.replace(/^[/\\]+/, "");
|
|
333
|
+
const projectKey = source.split(/[/\\]+/).filter(Boolean).map((part) => sanitizePathSegment(part)).join("-") || "project-local";
|
|
334
|
+
return sanitizePersistentIdentifier(projectKey, "project");
|
|
335
|
+
}
|
|
336
|
+
function realpathDirectoryOrFallback(path) {
|
|
337
|
+
try {
|
|
338
|
+
return realpathSync(path);
|
|
339
|
+
} catch {
|
|
340
|
+
if (!isAbsolute(path))
|
|
341
|
+
return stripTrailingSlash2(path);
|
|
342
|
+
const missingSegments = [];
|
|
343
|
+
let current = stripTrailingSlash2(path);
|
|
344
|
+
for (;; ) {
|
|
345
|
+
const parent = dirname(current);
|
|
346
|
+
if (parent === current)
|
|
347
|
+
return stripTrailingSlash2(path);
|
|
348
|
+
missingSegments.unshift(basename(current));
|
|
349
|
+
current = parent;
|
|
350
|
+
try {
|
|
351
|
+
return join(realpathSync(current), ...missingSegments);
|
|
352
|
+
} catch {}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function resolveGitCommonDir(workspaceRoot) {
|
|
357
|
+
const markerPath = join(workspaceRoot, ".git");
|
|
358
|
+
let gitDir;
|
|
359
|
+
try {
|
|
360
|
+
const marker = lstatSync(markerPath);
|
|
361
|
+
if (marker.isDirectory()) {
|
|
362
|
+
gitDir = realpathSync(markerPath);
|
|
363
|
+
} else if (marker.isFile()) {
|
|
364
|
+
const value = readFileSync(markerPath, "utf8").trim();
|
|
365
|
+
const match = value.match(/^gitdir:\s*(.+)$/u);
|
|
366
|
+
if (match?.[1] === undefined || match[1].includes("\x00"))
|
|
367
|
+
return null;
|
|
368
|
+
gitDir = realpathSync(isAbsolute(match[1]) ? match[1] : resolve(workspaceRoot, match[1]));
|
|
369
|
+
} else {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
} catch {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
const commonDirValue = readFileSync(join(gitDir, "commondir"), "utf8").trim();
|
|
377
|
+
if (commonDirValue === "" || commonDirValue.includes("\x00"))
|
|
378
|
+
return gitDir;
|
|
379
|
+
return realpathSync(isAbsolute(commonDirValue) ? commonDirValue : resolve(gitDir, commonDirValue));
|
|
380
|
+
} catch {
|
|
381
|
+
return gitDir;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function sanitizePathSegment(value) {
|
|
385
|
+
return value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "session-local";
|
|
386
|
+
}
|
|
387
|
+
function sanitizePersistentIdentifier(value, prefix) {
|
|
388
|
+
const pathSafe = value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || `${prefix}-local`;
|
|
389
|
+
if (!SENSITIVE_EVENT_TEXT_PATTERN.test(value) && !SENSITIVE_EVENT_TEXT_PATTERN.test(pathSafe)) {
|
|
390
|
+
return pathSafe;
|
|
391
|
+
}
|
|
392
|
+
return `${prefix}-${sha256Short(value)}`;
|
|
393
|
+
}
|
|
394
|
+
function stripTrailingSlash2(path) {
|
|
395
|
+
if (path === "/" || /^[A-Za-z]:[\\/]?$/.test(path))
|
|
396
|
+
return path;
|
|
397
|
+
return path.replace(/[/\\]+$/, "");
|
|
398
|
+
}
|
|
145
399
|
|
|
146
|
-
// packages/core/src/
|
|
147
|
-
|
|
148
|
-
|
|
400
|
+
// packages/core/src/projects/index.ts
|
|
401
|
+
class ProjectRegistrationError extends Error {
|
|
402
|
+
code;
|
|
403
|
+
constructor(code, message) {
|
|
404
|
+
super(message);
|
|
405
|
+
this.name = "ProjectRegistrationError";
|
|
406
|
+
this.code = code;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function resolveProjectRegistryPaths(homeDir) {
|
|
410
|
+
const paths = resolveEvoDevPaths(homeDir);
|
|
411
|
+
const discoveredDir = join2(paths.stateDir, "projects", "discovered");
|
|
412
|
+
const registeredDir = join2(paths.rootDir, "projects");
|
|
413
|
+
const workspaceDir = join2(paths.stateDir, "projects", "workspaces");
|
|
414
|
+
const aliasDir = join2(paths.stateDir, "projects", "aliases");
|
|
415
|
+
return {
|
|
416
|
+
discoveredDir,
|
|
417
|
+
registeredDir,
|
|
418
|
+
workspaceDir,
|
|
419
|
+
aliasDir,
|
|
420
|
+
discoveredPath: (projectKey) => join2(discoveredDir, `${projectKey}.json`),
|
|
421
|
+
registeredPath: (projectKey) => join2(registeredDir, projectKey, "workspace.json"),
|
|
422
|
+
workspacePath: (workspaceKey) => join2(workspaceDir, `${workspaceKey}.json`),
|
|
423
|
+
aliasPath: (aliasProjectKey) => join2(aliasDir, `${aliasProjectKey}.json`)
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
async function resolveProjectWorkspaceFromCwd(input) {
|
|
427
|
+
if (!isAbsolute2(input.cwd))
|
|
428
|
+
return null;
|
|
429
|
+
let cwd;
|
|
430
|
+
try {
|
|
431
|
+
const info = await stat(input.cwd);
|
|
432
|
+
if (!info.isDirectory())
|
|
433
|
+
return null;
|
|
434
|
+
cwd = await realpath(input.cwd);
|
|
435
|
+
} catch (error) {
|
|
436
|
+
if (isNotFoundError(error))
|
|
437
|
+
return null;
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
const gitRoot = await findNearestGitRoot(cwd);
|
|
441
|
+
const workspaceRoot = gitRoot ?? cwd;
|
|
442
|
+
const identity = resolveProjectLogIdentity(input.homeDir, workspaceRoot);
|
|
443
|
+
return {
|
|
444
|
+
projectKey: sanitizeStorageId(identity.projectKey, "project"),
|
|
445
|
+
workspaceKey: sanitizeStorageId(identity.workspaceKey, "workspace"),
|
|
446
|
+
displayName: basename2(identity.projectRoot) || parse(identity.projectRoot).root,
|
|
447
|
+
projectRoot: identity.projectRoot,
|
|
448
|
+
workspaceRoot,
|
|
449
|
+
workspaceKind: gitRoot === null ? "directory" : "git",
|
|
450
|
+
gitCommonDir: identity.gitCommonDir,
|
|
451
|
+
linkedWorktree: identity.linkedWorktree,
|
|
452
|
+
cwd
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
async function listProjectAliases(input) {
|
|
456
|
+
const paths = resolveProjectRegistryPaths(input.homeDir);
|
|
457
|
+
const aliases = {};
|
|
458
|
+
for (const path of await listJsonFilePaths(paths.aliasDir)) {
|
|
459
|
+
const record = await readProjectAlias(path);
|
|
460
|
+
if (record !== null)
|
|
461
|
+
aliases[record.aliasProjectKey] = record.canonicalProjectKey;
|
|
462
|
+
}
|
|
463
|
+
for (const path of await listJsonFilePaths(paths.discoveredDir)) {
|
|
464
|
+
const record = await readDiscoveredProject(path);
|
|
465
|
+
if (record !== null) {
|
|
466
|
+
await collectAvailableProjectAlias(input.homeDir, record, aliases);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
for (const projectKey of await listDirectoryNames2(paths.registeredDir)) {
|
|
470
|
+
const record = await readRegisteredProject(join2(paths.registeredDir, projectKey, "workspace.json"));
|
|
471
|
+
if (record !== null) {
|
|
472
|
+
await collectAvailableProjectAlias(input.homeDir, record, aliases);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return normalizeProjectAliases(aliases);
|
|
476
|
+
}
|
|
477
|
+
function canonicalizeProjectKey(projectKey, aliases) {
|
|
478
|
+
let current = projectKey;
|
|
479
|
+
const seen = new Set;
|
|
480
|
+
while (!seen.has(current)) {
|
|
481
|
+
seen.add(current);
|
|
482
|
+
const next = aliases[current];
|
|
483
|
+
if (next === undefined || next === current)
|
|
484
|
+
return current;
|
|
485
|
+
current = next;
|
|
486
|
+
}
|
|
487
|
+
return projectKey;
|
|
488
|
+
}
|
|
489
|
+
async function listEquivalentProjectKeys(input) {
|
|
490
|
+
const aliases = await listProjectAliases({ homeDir: input.homeDir });
|
|
491
|
+
const canonical = canonicalizeProjectKey(input.projectKey, aliases);
|
|
492
|
+
return [
|
|
493
|
+
...new Set([
|
|
494
|
+
canonical,
|
|
495
|
+
input.projectKey,
|
|
496
|
+
...Object.keys(aliases).filter((alias) => canonicalizeProjectKey(alias, aliases) === canonical)
|
|
497
|
+
])
|
|
498
|
+
].sort();
|
|
499
|
+
}
|
|
500
|
+
async function collectAvailableProjectAlias(homeDir, record, aliases) {
|
|
501
|
+
const workspace = await resolveProjectWorkspaceFromCwd({
|
|
502
|
+
homeDir,
|
|
503
|
+
cwd: record.workspaceRoot
|
|
504
|
+
}).catch(() => null);
|
|
505
|
+
if (workspace === null)
|
|
506
|
+
return;
|
|
507
|
+
if (record.projectKey !== workspace.projectKey) {
|
|
508
|
+
aliases[record.projectKey] = workspace.projectKey;
|
|
509
|
+
}
|
|
510
|
+
if (workspace.workspaceKey !== workspace.projectKey) {
|
|
511
|
+
aliases[workspace.workspaceKey] = workspace.projectKey;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
function normalizeProjectAliases(aliases) {
|
|
515
|
+
return Object.fromEntries(Object.keys(aliases).sort().flatMap((alias) => {
|
|
516
|
+
const canonical = canonicalizeProjectKey(alias, aliases);
|
|
517
|
+
return canonical === alias ? [] : [[alias, canonical]];
|
|
518
|
+
}));
|
|
519
|
+
}
|
|
520
|
+
async function findNearestGitRoot(cwd) {
|
|
521
|
+
let current = cwd;
|
|
522
|
+
for (;; ) {
|
|
523
|
+
try {
|
|
524
|
+
const marker = await lstat(join2(current, ".git"));
|
|
525
|
+
if (marker.isDirectory() || marker.isFile())
|
|
526
|
+
return current;
|
|
527
|
+
} catch (error) {
|
|
528
|
+
if (!isNotFoundError(error))
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
531
|
+
const parent = dirname2(current);
|
|
532
|
+
if (parent === current)
|
|
533
|
+
return null;
|
|
534
|
+
current = parent;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
async function readDiscoveredProject(path) {
|
|
538
|
+
try {
|
|
539
|
+
return parseDiscoveredProject(JSON.parse(await readFile(path, "utf8")));
|
|
540
|
+
} catch (error) {
|
|
541
|
+
if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
|
|
542
|
+
return null;
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
async function readRegisteredProject(path) {
|
|
547
|
+
try {
|
|
548
|
+
return parseRegisteredProject(JSON.parse(await readFile(path, "utf8")));
|
|
549
|
+
} catch (error) {
|
|
550
|
+
if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
|
|
551
|
+
return null;
|
|
552
|
+
throw error;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
async function readProjectAlias(path) {
|
|
556
|
+
try {
|
|
557
|
+
return parseProjectAlias(JSON.parse(await readFile(path, "utf8")));
|
|
558
|
+
} catch (error) {
|
|
559
|
+
if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
|
|
560
|
+
return null;
|
|
561
|
+
throw error;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
function parseDiscoveredProject(value) {
|
|
565
|
+
const record = requireRecord(value);
|
|
566
|
+
if (record.schemaVersion !== 1 || record.kind !== "discovered-project" || !isProjectKey(record.projectKey) || !isNonEmptyString(record.displayName) || !isAbsoluteString(record.workspaceRoot) || !isAbsoluteString(record.lastCwd) || !isWorkspaceKind(record.workspaceKind) || !isDiscoveryTargetArray(record.sourceTargets) || !(record.lastSessionKey === null || isNonEmptyString(record.lastSessionKey)) || !isNonEmptyString(record.firstSeenAt) || !isNonEmptyString(record.lastSeenAt) || record.localOnly !== true || record.sourceContentStored !== false) {
|
|
567
|
+
throw new ProjectRegistrationError("invalid", "Discovered project record is invalid.");
|
|
568
|
+
}
|
|
569
|
+
return record;
|
|
570
|
+
}
|
|
571
|
+
function parseRegisteredProject(value) {
|
|
572
|
+
const record = requireRecord(value);
|
|
573
|
+
if (record.schemaVersion !== 1 || record.kind !== "registered-project" || !isProjectKey(record.projectKey) || !isNonEmptyString(record.displayName) || !isAbsoluteString(record.workspaceRoot) || !isWorkspaceKind(record.workspaceKind) || !isNonEmptyString(record.registeredAt) || !isNonEmptyString(record.lastSeenAt) || record.localOnly !== true || record.sourceContentStored !== false) {
|
|
574
|
+
throw new ProjectRegistrationError("invalid", "Registered project record is invalid.");
|
|
575
|
+
}
|
|
576
|
+
return record;
|
|
577
|
+
}
|
|
578
|
+
function parseProjectAlias(value) {
|
|
579
|
+
const record = requireRecord(value);
|
|
580
|
+
if (record.schemaVersion !== 1 || record.kind !== "project-alias" || !isProjectKey(record.aliasProjectKey) || !isProjectKey(record.canonicalProjectKey) || record.aliasProjectKey === record.canonicalProjectKey || !isAbsoluteString(record.workspaceRoot) || !isNonEmptyString(record.createdAt) || !isNonEmptyString(record.updatedAt) || record.localOnly !== true || record.sourceContentStored !== false) {
|
|
581
|
+
throw new ProjectRegistrationError("invalid", "Project alias record is invalid.");
|
|
582
|
+
}
|
|
583
|
+
return record;
|
|
584
|
+
}
|
|
585
|
+
async function listJsonFilePaths(path) {
|
|
586
|
+
try {
|
|
587
|
+
return (await readdir(path, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => join2(path, entry.name)).sort();
|
|
588
|
+
} catch (error) {
|
|
589
|
+
if (isNotFoundError(error))
|
|
590
|
+
return [];
|
|
591
|
+
throw error;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
async function listDirectoryNames2(path) {
|
|
595
|
+
try {
|
|
596
|
+
return (await readdir(path, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
597
|
+
} catch (error) {
|
|
598
|
+
if (isNotFoundError(error))
|
|
599
|
+
return [];
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function isProjectKey(value) {
|
|
604
|
+
return typeof value === "string" && value !== "." && value !== ".." && /^[A-Za-z0-9._-]{1,120}$/.test(value);
|
|
605
|
+
}
|
|
606
|
+
function isNonEmptyString(value) {
|
|
607
|
+
return typeof value === "string" && value.trim() !== "";
|
|
608
|
+
}
|
|
609
|
+
function isAbsoluteString(value) {
|
|
610
|
+
return isNonEmptyString(value) && isAbsolute2(value);
|
|
611
|
+
}
|
|
612
|
+
function isWorkspaceKind(value) {
|
|
613
|
+
return value === "git" || value === "directory";
|
|
614
|
+
}
|
|
615
|
+
function isDiscoveryTargetArray(value) {
|
|
616
|
+
return Array.isArray(value) && value.length > 0 && value.every((item) => item === "claude" || item === "codex");
|
|
617
|
+
}
|
|
618
|
+
function requireRecord(value) {
|
|
619
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
620
|
+
throw new ProjectRegistrationError("invalid", "Project record must be an object.");
|
|
621
|
+
}
|
|
622
|
+
return value;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// packages/core/src/evolution/evidence/session-memory/constants.ts
|
|
626
|
+
var DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
|
|
627
|
+
// packages/core/src/evolution/knowledge/index.ts
|
|
628
|
+
import { mkdir, readFile as readFile2, readdir as readdir2, rename, rm, stat as stat2, writeFile } from "node:fs/promises";
|
|
629
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join3, relative as relative2, resolve as resolve2 } from "node:path";
|
|
630
|
+
|
|
631
|
+
// packages/core/src/evolution/knowledge/change-store.ts
|
|
632
|
+
var KNOWLEDGE_CHANGE_LOCK_STALE_MS = 5 * 60 * 1000;
|
|
633
|
+
|
|
634
|
+
// packages/core/src/evolution/knowledge/index.ts
|
|
149
635
|
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
636
|
var ACTIVE_OKF_REVIEW_STATES = ["accepted", "auto-accepted"];
|
|
166
637
|
var OKF_REVIEW_STATES = [
|
|
167
638
|
"auto-accepted",
|
|
@@ -192,19 +663,19 @@ var BEHAVIOR_CHANGE_KINDS = new Set([
|
|
|
192
663
|
"repo-asset-suggestion"
|
|
193
664
|
]);
|
|
194
665
|
function resolveOkfKnowledgePaths(homeDir) {
|
|
195
|
-
const
|
|
666
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
196
667
|
return {
|
|
197
|
-
knowledgeDir:
|
|
198
|
-
okfDir:
|
|
199
|
-
indexesDir:
|
|
200
|
-
tmpDir:
|
|
668
|
+
knowledgeDir: paths2.knowledgeDir,
|
|
669
|
+
okfDir: join3(paths2.knowledgeDir, "okf"),
|
|
670
|
+
indexesDir: join3(paths2.knowledgeDir, "indexes"),
|
|
671
|
+
tmpDir: join3(paths2.knowledgeDir, "tmp")
|
|
201
672
|
};
|
|
202
673
|
}
|
|
203
674
|
async function ensureOkfKnowledgeBase(homeDir) {
|
|
204
|
-
const
|
|
205
|
-
await ensureLocalKnowledgeGitRepository(
|
|
206
|
-
await mkdir(
|
|
207
|
-
await mkdir(
|
|
675
|
+
const paths2 = resolveOkfKnowledgePaths(homeDir);
|
|
676
|
+
await ensureLocalKnowledgeGitRepository(paths2.knowledgeDir);
|
|
677
|
+
await mkdir(paths2.indexesDir, { recursive: true });
|
|
678
|
+
await mkdir(paths2.tmpDir, { recursive: true });
|
|
208
679
|
const directories = [
|
|
209
680
|
{
|
|
210
681
|
path: "",
|
|
@@ -234,13 +705,47 @@ async function ensureOkfKnowledgeBase(homeDir) {
|
|
|
234
705
|
{ path: "references", title: "References", description: "Cited references." }
|
|
235
706
|
];
|
|
236
707
|
for (const directory of directories) {
|
|
237
|
-
await ensureOkfDirectory(
|
|
708
|
+
await ensureOkfDirectory(paths2.okfDir, directory.path, directory.title, directory.description);
|
|
238
709
|
}
|
|
239
710
|
await rebuildOkfKnowledgeIndexes({ homeDir });
|
|
240
711
|
}
|
|
712
|
+
function normalizeKnowledgeSupportRef(value, path) {
|
|
713
|
+
const input = assertRecordValue(value, path);
|
|
714
|
+
const kind = readRequiredString(input.kind, `${path}.kind`);
|
|
715
|
+
if (kind !== "user-declaration" && kind !== "repo-policy" && kind !== "state-observation" && kind !== "verified-outcome" && kind !== "semantic-inference") {
|
|
716
|
+
throw new Error(`${path}.kind is invalid.`);
|
|
717
|
+
}
|
|
718
|
+
const observedAt = readRequiredString(input.observedAt, `${path}.observedAt`);
|
|
719
|
+
if (!Number.isFinite(Date.parse(observedAt)))
|
|
720
|
+
throw new Error(`${path}.observedAt is invalid.`);
|
|
721
|
+
const subjectFingerprint = input.subjectFingerprint === null ? null : sanitizeOkfText(readRequiredString(input.subjectFingerprint, `${path}.subjectFingerprint`));
|
|
722
|
+
return {
|
|
723
|
+
id: sanitizeOkfText(readRequiredString(input.id, `${path}.id`)),
|
|
724
|
+
kind,
|
|
725
|
+
sourceRefId: sanitizeOkfText(readRequiredString(input.sourceRefId, `${path}.sourceRefId`)),
|
|
726
|
+
subjectFingerprint,
|
|
727
|
+
observedAt: new Date(observedAt).toISOString()
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
function assertRecordValue(value, path) {
|
|
731
|
+
if (!isRecord(value))
|
|
732
|
+
throw new Error(`${path} must be an object.`);
|
|
733
|
+
return value;
|
|
734
|
+
}
|
|
735
|
+
function readRequiredString(value, path) {
|
|
736
|
+
if (!isNonEmptyString2(value))
|
|
737
|
+
throw new Error(`${path} must be a non-empty string.`);
|
|
738
|
+
return value;
|
|
739
|
+
}
|
|
740
|
+
function isRecord(value) {
|
|
741
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
742
|
+
}
|
|
743
|
+
function isNonEmptyString2(value) {
|
|
744
|
+
return typeof value === "string" && value.trim() !== "";
|
|
745
|
+
}
|
|
241
746
|
async function rebuildOkfKnowledgeIndexes(input) {
|
|
242
|
-
const
|
|
243
|
-
await mkdir(
|
|
747
|
+
const paths2 = resolveOkfKnowledgePaths(input.homeDir);
|
|
748
|
+
await mkdir(paths2.indexesDir, { recursive: true });
|
|
244
749
|
const concepts = (await listOkfKnowledgeConcepts({ homeDir: input.homeDir })).filter(isActiveOkfConcept);
|
|
245
750
|
const conceptSummaries = concepts.map((concept) => ({
|
|
246
751
|
id: concept.id,
|
|
@@ -257,34 +762,34 @@ async function rebuildOkfKnowledgeIndexes(input) {
|
|
|
257
762
|
pathScopes: concept.pathScopes
|
|
258
763
|
}));
|
|
259
764
|
const pathsWritten = [
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
765
|
+
join3(paths2.indexesDir, "index.json"),
|
|
766
|
+
join3(paths2.indexesDir, "concepts.json"),
|
|
767
|
+
join3(paths2.indexesDir, "repos.json"),
|
|
768
|
+
join3(paths2.indexesDir, "roles.json"),
|
|
769
|
+
join3(paths2.indexesDir, "workflows.json")
|
|
265
770
|
];
|
|
266
|
-
await
|
|
771
|
+
await writeJson2(pathsWritten[0], {
|
|
267
772
|
schemaVersion: 1,
|
|
268
773
|
kind: "okf-knowledge-index",
|
|
269
774
|
conceptCount: concepts.length,
|
|
270
775
|
updatedAt: new Date().toISOString()
|
|
271
776
|
}, { overwrite: true });
|
|
272
|
-
await
|
|
777
|
+
await writeJson2(pathsWritten[1], {
|
|
273
778
|
schemaVersion: 1,
|
|
274
779
|
kind: "okf-concepts-index",
|
|
275
780
|
concepts: conceptSummaries
|
|
276
781
|
}, { overwrite: true });
|
|
277
|
-
await
|
|
782
|
+
await writeJson2(pathsWritten[2], {
|
|
278
783
|
schemaVersion: 1,
|
|
279
784
|
kind: "okf-repos-index",
|
|
280
785
|
repos: groupConceptsByTag(concepts, "repoTags")
|
|
281
786
|
}, { overwrite: true });
|
|
282
|
-
await
|
|
787
|
+
await writeJson2(pathsWritten[3], {
|
|
283
788
|
schemaVersion: 1,
|
|
284
789
|
kind: "okf-roles-index",
|
|
285
790
|
roles: groupConceptsByTag(concepts, "roleTags")
|
|
286
791
|
}, { overwrite: true });
|
|
287
|
-
await
|
|
792
|
+
await writeJson2(pathsWritten[4], {
|
|
288
793
|
schemaVersion: 1,
|
|
289
794
|
kind: "okf-workflows-index",
|
|
290
795
|
workflows: groupConceptsByTag(concepts, "workflowTags")
|
|
@@ -293,33 +798,37 @@ async function rebuildOkfKnowledgeIndexes(input) {
|
|
|
293
798
|
}
|
|
294
799
|
async function listOkfKnowledgeConcepts(input) {
|
|
295
800
|
const okfDir = resolveOkfKnowledgePaths(input.homeDir).okfDir;
|
|
296
|
-
if (!await
|
|
801
|
+
if (!await pathExists2(okfDir))
|
|
297
802
|
return [];
|
|
803
|
+
const equivalentProjectKeys = input.projectKey === undefined ? undefined : await listEquivalentProjectKeys({
|
|
804
|
+
homeDir: input.homeDir,
|
|
805
|
+
projectKey: input.projectKey
|
|
806
|
+
});
|
|
298
807
|
const files = await listMarkdownFiles(okfDir);
|
|
299
808
|
const concepts = [];
|
|
300
809
|
for (const file of files) {
|
|
301
810
|
if (RESERVED_OKF_FILENAMES.has(file.name))
|
|
302
811
|
continue;
|
|
303
|
-
const content = await
|
|
812
|
+
const content = await readFile2(file.path, "utf8");
|
|
304
813
|
const parsed = parseOkfConceptFile(okfDir, file.path, content);
|
|
305
814
|
if (parsed !== null)
|
|
306
815
|
concepts.push(parsed);
|
|
307
816
|
}
|
|
308
|
-
return concepts.filter((concept) => matchesConceptFilters(concept, input)).sort((left, right) => left.id.localeCompare(right.id));
|
|
817
|
+
return concepts.filter((concept) => matchesConceptFilters(concept, input, equivalentProjectKeys)).sort((left, right) => left.id.localeCompare(right.id));
|
|
309
818
|
}
|
|
310
819
|
async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
|
|
311
820
|
await mkdir(knowledgeDir, { recursive: true });
|
|
312
|
-
const gitDir =
|
|
313
|
-
if (await
|
|
821
|
+
const gitDir = join3(knowledgeDir, ".git");
|
|
822
|
+
if (await pathExists2(gitDir))
|
|
314
823
|
return;
|
|
315
|
-
await mkdir(
|
|
316
|
-
await mkdir(
|
|
317
|
-
await mkdir(
|
|
318
|
-
await mkdir(
|
|
319
|
-
await mkdir(
|
|
320
|
-
await writeTextIfMissing(
|
|
824
|
+
await mkdir(join3(gitDir, "objects", "info"), { recursive: true });
|
|
825
|
+
await mkdir(join3(gitDir, "objects", "pack"), { recursive: true });
|
|
826
|
+
await mkdir(join3(gitDir, "refs", "heads"), { recursive: true });
|
|
827
|
+
await mkdir(join3(gitDir, "refs", "tags"), { recursive: true });
|
|
828
|
+
await mkdir(join3(gitDir, "info"), { recursive: true });
|
|
829
|
+
await writeTextIfMissing(join3(gitDir, "HEAD"), `ref: refs/heads/main
|
|
321
830
|
`);
|
|
322
|
-
await writeTextIfMissing(
|
|
831
|
+
await writeTextIfMissing(join3(gitDir, "config"), [
|
|
323
832
|
"[core]",
|
|
324
833
|
"\trepositoryformatversion = 0",
|
|
325
834
|
"\tfilemode = true",
|
|
@@ -328,7 +837,7 @@ async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
|
|
|
328
837
|
""
|
|
329
838
|
].join(`
|
|
330
839
|
`));
|
|
331
|
-
await writeTextIfMissing(
|
|
840
|
+
await writeTextIfMissing(join3(gitDir, "info", "exclude"), [
|
|
332
841
|
"# EvoDev user-local knowledge git repository.",
|
|
333
842
|
"# No remote is configured by default.",
|
|
334
843
|
""
|
|
@@ -336,20 +845,20 @@ async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
|
|
|
336
845
|
`));
|
|
337
846
|
}
|
|
338
847
|
async function writeTextIfMissing(path, value) {
|
|
339
|
-
if (await
|
|
848
|
+
if (await pathExists2(path))
|
|
340
849
|
return;
|
|
341
|
-
await mkdir(
|
|
850
|
+
await mkdir(dirname3(path), { recursive: true });
|
|
342
851
|
await writeFile(path, value, { encoding: "utf8", flag: "wx" });
|
|
343
852
|
}
|
|
344
853
|
function sanitizeOkfText(value) {
|
|
345
|
-
return value
|
|
854
|
+
return redactSessionMemoryCredentialText(value).value.replace(/\s+/gu, " ").trim().slice(0, 800);
|
|
346
855
|
}
|
|
347
856
|
async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
|
|
348
857
|
const dir = relativeDir === "" || relativeDir === "." ? okfDir : resolveOkfTargetPath(okfDir, relativeDir);
|
|
349
858
|
await mkdir(dir, { recursive: true });
|
|
350
859
|
const isRoot = dir === okfDir;
|
|
351
|
-
const indexPath =
|
|
352
|
-
if (!await
|
|
860
|
+
const indexPath = join3(dir, "index.md");
|
|
861
|
+
if (!await pathExists2(indexPath)) {
|
|
353
862
|
await writeFile(indexPath, isRoot ? [
|
|
354
863
|
"---",
|
|
355
864
|
`okf_version: ${yamlString("0.1")}`,
|
|
@@ -365,8 +874,8 @@ async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
|
|
|
365
874
|
`) : [`# ${title}`, "", description, ""].join(`
|
|
366
875
|
`), "utf8");
|
|
367
876
|
}
|
|
368
|
-
const logPath =
|
|
369
|
-
if (!await
|
|
877
|
+
const logPath = join3(dir, "log.md");
|
|
878
|
+
if (!await pathExists2(logPath)) {
|
|
370
879
|
await writeFile(logPath, [
|
|
371
880
|
"# Directory Update Log",
|
|
372
881
|
"",
|
|
@@ -411,6 +920,8 @@ function parseOkfConceptFile(okfDir, filePath, content) {
|
|
|
411
920
|
reviewState,
|
|
412
921
|
lifecycle: lifecycleParsed.lifecycle,
|
|
413
922
|
lifecyclePersisted: lifecycleParsed.persisted,
|
|
923
|
+
verificationSnapshot: parseOkfVerificationSnapshot(frontmatter),
|
|
924
|
+
supportRef: parseOkfKnowledgeSupportRef(frontmatter),
|
|
414
925
|
title,
|
|
415
926
|
description,
|
|
416
927
|
tags,
|
|
@@ -421,8 +932,40 @@ function parseOkfConceptFile(okfDir, filePath, content) {
|
|
|
421
932
|
body: parsed.body
|
|
422
933
|
};
|
|
423
934
|
}
|
|
424
|
-
function
|
|
425
|
-
|
|
935
|
+
function parseOkfKnowledgeSupportRef(frontmatter) {
|
|
936
|
+
const block = extractNestedYamlBlock(frontmatter, "evodev", "supportRef");
|
|
937
|
+
if (block === null)
|
|
938
|
+
return null;
|
|
939
|
+
try {
|
|
940
|
+
return normalizeKnowledgeSupportRef({
|
|
941
|
+
id: readIndentedYamlScalar(block, "id"),
|
|
942
|
+
kind: readIndentedYamlScalar(block, "kind"),
|
|
943
|
+
sourceRefId: readIndentedYamlScalar(block, "sourceRefId"),
|
|
944
|
+
subjectFingerprint: readNullableLifecycleString(readIndentedYamlScalar(block, "subjectFingerprint")),
|
|
945
|
+
observedAt: readIndentedYamlScalar(block, "observedAt")
|
|
946
|
+
}, "evodev.supportRef");
|
|
947
|
+
} catch {
|
|
948
|
+
return null;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
function parseOkfVerificationSnapshot(frontmatter) {
|
|
952
|
+
const block = extractNestedYamlBlock(frontmatter, "evodev", "verificationSnapshot");
|
|
953
|
+
if (block === null)
|
|
954
|
+
return null;
|
|
955
|
+
const schemaVersion = readIndentedYamlScalar(block, "schemaVersion");
|
|
956
|
+
const verifiedAt = normalizeIsoDateString(readIndentedYamlScalar(block, "verifiedAt"));
|
|
957
|
+
if (schemaVersion !== "1" || verifiedAt === null)
|
|
958
|
+
return null;
|
|
959
|
+
return {
|
|
960
|
+
schemaVersion: 1,
|
|
961
|
+
verifiedAt,
|
|
962
|
+
evidenceRefs: readYamlList(block, "evidenceRefs"),
|
|
963
|
+
repository: null
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
function matchesConceptFilters(concept, input, equivalentProjectKeys) {
|
|
967
|
+
const projectKeys = (equivalentProjectKeys ?? []).map(sanitizeSlug);
|
|
968
|
+
if (input.projectKey !== undefined && concept.repoTags.length > 0 && ![sanitizeSlug(input.projectKey), ...projectKeys].some((projectKey) => concept.repoTags.includes(projectKey) || concept.tags.includes(`repo:${projectKey}`))) {
|
|
426
969
|
return false;
|
|
427
970
|
}
|
|
428
971
|
if (input.roleId !== undefined && concept.roleTags.length > 0 && !concept.roleTags.includes(sanitizeSlug(input.roleId)) && !concept.tags.includes(`role:${sanitizeSlug(input.roleId)}`)) {
|
|
@@ -473,13 +1016,13 @@ function isLifecycleDateDue(value, now) {
|
|
|
473
1016
|
}
|
|
474
1017
|
function createDefaultOkfLifecycle(input) {
|
|
475
1018
|
const createdAt = normalizeIsoDateString(input.createdAt) ?? "1970-01-01T00:00:00.000Z";
|
|
476
|
-
const
|
|
1019
|
+
const policy2 = resolveOkfLifecyclePolicy(input);
|
|
477
1020
|
return {
|
|
478
1021
|
status: lifecycleStatusFromReviewState(input.reviewState),
|
|
479
1022
|
createdAt,
|
|
480
1023
|
lastVerifiedAt: createdAt,
|
|
481
|
-
reviewAfter: addDaysIso(createdAt,
|
|
482
|
-
staleAfter: addDaysIso(createdAt,
|
|
1024
|
+
reviewAfter: addDaysIso(createdAt, policy2.reviewAfterDays),
|
|
1025
|
+
staleAfter: addDaysIso(createdAt, policy2.staleAfterDays),
|
|
483
1026
|
supersedes: [],
|
|
484
1027
|
supersededBy: null,
|
|
485
1028
|
revokedAt: null,
|
|
@@ -537,10 +1080,10 @@ function isOkfLifecycleStatus(value) {
|
|
|
537
1080
|
function normalizeIsoDateString(value) {
|
|
538
1081
|
if (value === undefined || value === null || value === "" || value === "null")
|
|
539
1082
|
return null;
|
|
540
|
-
const
|
|
541
|
-
if (!Number.isFinite(
|
|
1083
|
+
const time2 = Date.parse(value);
|
|
1084
|
+
if (!Number.isFinite(time2))
|
|
542
1085
|
return null;
|
|
543
|
-
return new Date(
|
|
1086
|
+
return new Date(time2).toISOString();
|
|
544
1087
|
}
|
|
545
1088
|
function addDaysIso(value, days) {
|
|
546
1089
|
const date = new Date(value);
|
|
@@ -641,12 +1184,12 @@ function parseYamlValue(value) {
|
|
|
641
1184
|
return trimmed.replace(/^['"]|['"]$/gu, "");
|
|
642
1185
|
}
|
|
643
1186
|
async function listMarkdownFiles(root) {
|
|
644
|
-
if (!await
|
|
1187
|
+
if (!await pathExists2(root))
|
|
645
1188
|
return [];
|
|
646
|
-
const entries = await
|
|
1189
|
+
const entries = await readdir2(root, { withFileTypes: true });
|
|
647
1190
|
const files = [];
|
|
648
1191
|
for (const entry of entries) {
|
|
649
|
-
const path =
|
|
1192
|
+
const path = join3(root, entry.name);
|
|
650
1193
|
if (entry.isDirectory()) {
|
|
651
1194
|
files.push(...await listMarkdownFiles(path));
|
|
652
1195
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -672,14 +1215,14 @@ function resolveOkfTargetPath(okfDir, targetPath) {
|
|
|
672
1215
|
if (clean.split("/").some((segment) => segment === ".." || segment === "." || segment === "")) {
|
|
673
1216
|
throw new Error(`Unsafe OKF target path: ${targetPath}`);
|
|
674
1217
|
}
|
|
675
|
-
const resolved =
|
|
676
|
-
const rel =
|
|
1218
|
+
const resolved = join3(okfDir, clean);
|
|
1219
|
+
const rel = relative2(okfDir, resolved);
|
|
677
1220
|
if (rel.startsWith("..") || rel === "")
|
|
678
1221
|
throw new Error(`Unsafe OKF target path: ${targetPath}`);
|
|
679
1222
|
return resolved;
|
|
680
1223
|
}
|
|
681
1224
|
function toOkfRelativePath(okfDir, path) {
|
|
682
|
-
return
|
|
1225
|
+
return relative2(okfDir, path).replace(/\\/gu, "/");
|
|
683
1226
|
}
|
|
684
1227
|
function sanitizeSlug(value) {
|
|
685
1228
|
const slug = value.trim().toLowerCase().replace(/[^a-z0-9._/-]+/gu, "-").replace(/\/+/gu, "/").replace(/^-+|-+$/gu, "");
|
|
@@ -694,15 +1237,15 @@ function escapeRegExp(value) {
|
|
|
694
1237
|
function todayIsoDate() {
|
|
695
1238
|
return new Date().toISOString().slice(0, 10);
|
|
696
1239
|
}
|
|
697
|
-
async function
|
|
698
|
-
await mkdir(
|
|
1240
|
+
async function writeJson2(path, value, options = {}) {
|
|
1241
|
+
await mkdir(dirname3(path), { recursive: true });
|
|
699
1242
|
const flag = options.overwrite === true ? "w" : "wx";
|
|
700
1243
|
await writeFile(path, `${JSON.stringify(value, null, 2)}
|
|
701
1244
|
`, { encoding: "utf8", flag });
|
|
702
1245
|
}
|
|
703
|
-
async function
|
|
1246
|
+
async function pathExists2(path) {
|
|
704
1247
|
try {
|
|
705
|
-
await
|
|
1248
|
+
await stat2(path);
|
|
706
1249
|
return true;
|
|
707
1250
|
} catch (error) {
|
|
708
1251
|
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
@@ -711,79 +1254,6 @@ async function pathExists(path) {
|
|
|
711
1254
|
}
|
|
712
1255
|
}
|
|
713
1256
|
|
|
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
|
-
|
|
751
|
-
// packages/core/src/task/index.ts
|
|
752
|
-
var FORBIDDEN_TASK_WRITE_SEGMENTS = new Set([".claude", ".codex"]);
|
|
753
|
-
var FORBIDDEN_PROJECT_ASSET_SEGMENTS = new Set(["packages", "src"]);
|
|
754
|
-
var FORBIDDEN_TASK_WRITE_FILES = new Set(["agents.md", "claude.md", "package.json", "readme.md"]);
|
|
755
|
-
var FORBIDDEN_RAW_KEYS2 = new Set([
|
|
756
|
-
"rawoutput",
|
|
757
|
-
"raw_output",
|
|
758
|
-
"stdout",
|
|
759
|
-
"stderr",
|
|
760
|
-
"source",
|
|
761
|
-
"sourcecontent",
|
|
762
|
-
"source_content",
|
|
763
|
-
"sourcetext",
|
|
764
|
-
"source_text",
|
|
765
|
-
"prompt",
|
|
766
|
-
"prompttext",
|
|
767
|
-
"prompt_text",
|
|
768
|
-
"transcript",
|
|
769
|
-
"transcripttext",
|
|
770
|
-
"transcript_text",
|
|
771
|
-
"secret",
|
|
772
|
-
"secretvalue",
|
|
773
|
-
"secret_value"
|
|
774
|
-
]);
|
|
775
|
-
var ALLOWED_VERIFICATION_KEYS = new Set([
|
|
776
|
-
"acceptanceResults",
|
|
777
|
-
"antiCriteriaResults",
|
|
778
|
-
"commands",
|
|
779
|
-
"evidence",
|
|
780
|
-
"exitCode",
|
|
781
|
-
"id",
|
|
782
|
-
"status",
|
|
783
|
-
"summary",
|
|
784
|
-
"type"
|
|
785
|
-
]);
|
|
786
|
-
|
|
787
1257
|
// packages/core/src/team/prompts.ts
|
|
788
1258
|
var TEAM_ROLE_STARTUP_PROMPT_TEMPLATE = [
|
|
789
1259
|
"You are an EvoDev managed role agent.",
|
|
@@ -848,6 +1318,23 @@ var TEAM_INTERNAL_WAKE_SIGNAL = [
|
|
|
848
1318
|
"No user request is included in this message. Continue only from EvoDev team inbox messages injected by hooks."
|
|
849
1319
|
].join(`
|
|
850
1320
|
`);
|
|
1321
|
+
var BUILT_IN_TEAM_DEFINITION = {
|
|
1322
|
+
version: 1,
|
|
1323
|
+
name: "builtin-minimal-team",
|
|
1324
|
+
description: "Built-in minimal EvoDev team fallback.",
|
|
1325
|
+
agents: {
|
|
1326
|
+
executor: "builtin:executor",
|
|
1327
|
+
reviewer: "builtin:reviewer",
|
|
1328
|
+
tester: "builtin:tester"
|
|
1329
|
+
},
|
|
1330
|
+
body: [
|
|
1331
|
+
"# Built-in Minimal Team",
|
|
1332
|
+
"",
|
|
1333
|
+
"Use role agents only when delegation improves correctness, coverage, safety, or latency.",
|
|
1334
|
+
"Spawn roles on demand and send self-contained assignments through Teams MCP."
|
|
1335
|
+
].join(`
|
|
1336
|
+
`)
|
|
1337
|
+
};
|
|
851
1338
|
|
|
852
1339
|
// packages/core/src/hooks/index.ts
|
|
853
1340
|
var CANONICAL_HOOK_EVENT_TYPES = [
|
|
@@ -916,6 +1403,12 @@ var CODEX_STOP_EVENTS_WITHOUT_ADDITIONAL_CONTEXT = new Set([
|
|
|
916
1403
|
"Stop",
|
|
917
1404
|
"SubagentStop"
|
|
918
1405
|
]);
|
|
1406
|
+
var COMPLETION_EVENTS_WITHOUT_DEVELOPMENT_DIAGNOSTICS = new Set([
|
|
1407
|
+
"Stop",
|
|
1408
|
+
"SubagentStop",
|
|
1409
|
+
"TaskCompleted",
|
|
1410
|
+
"TeammateIdle"
|
|
1411
|
+
]);
|
|
919
1412
|
function createDefaultHookSettings() {
|
|
920
1413
|
return {
|
|
921
1414
|
enabled: true,
|
|
@@ -944,13 +1437,13 @@ function parseHookSettings(value) {
|
|
|
944
1437
|
const defaults = createDefaultHookSettings();
|
|
945
1438
|
if (value === undefined || value === null)
|
|
946
1439
|
return defaults;
|
|
947
|
-
if (!
|
|
1440
|
+
if (!isRecord2(value))
|
|
948
1441
|
throw new Error("Invalid hooks settings; expected object.");
|
|
949
|
-
const observability =
|
|
950
|
-
|
|
951
|
-
|
|
1442
|
+
const observability = isRecord2(value.observability) ? value.observability : undefined;
|
|
1443
|
+
optionalBoolean2(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
|
|
1444
|
+
optionalBoolean2(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
|
|
952
1445
|
return {
|
|
953
|
-
enabled:
|
|
1446
|
+
enabled: optionalBoolean2(value.enabled, defaults.enabled, "hooks.enabled"),
|
|
954
1447
|
targets: {
|
|
955
1448
|
claude: parseHookTargetSettings(value.targets, defaults.targets.claude, "claude"),
|
|
956
1449
|
codex: parseHookTargetSettings(value.targets, defaults.targets.codex, "codex")
|
|
@@ -958,7 +1451,7 @@ function parseHookSettings(value) {
|
|
|
958
1451
|
observability: {
|
|
959
1452
|
metadataOnly: true,
|
|
960
1453
|
rawPayloadStorage: false,
|
|
961
|
-
appendEvents:
|
|
1454
|
+
appendEvents: optionalBoolean2(observability?.appendEvents, defaults.observability.appendEvents, "hooks.observability.appendEvents")
|
|
962
1455
|
},
|
|
963
1456
|
learning: {
|
|
964
1457
|
emitCandidates: false,
|
|
@@ -967,26 +1460,26 @@ function parseHookSettings(value) {
|
|
|
967
1460
|
};
|
|
968
1461
|
}
|
|
969
1462
|
function parseHookTargetSettings(value, defaults, target) {
|
|
970
|
-
const targets =
|
|
971
|
-
const targetSettings =
|
|
972
|
-
const events =
|
|
1463
|
+
const targets = isRecord2(value) ? value : {};
|
|
1464
|
+
const targetSettings = isRecord2(targets[target]) ? targets[target] : {};
|
|
1465
|
+
const events = isRecord2(targetSettings.events) ? targetSettings.events : {};
|
|
973
1466
|
const parsedEvents = { ...defaults.events };
|
|
974
1467
|
for (const eventType of CANONICAL_HOOK_EVENT_TYPES) {
|
|
975
|
-
parsedEvents[eventType] =
|
|
1468
|
+
parsedEvents[eventType] = optionalBoolean2(events[eventType], defaults.events[eventType], `hooks.targets.${target}.events.${eventType}`);
|
|
976
1469
|
}
|
|
977
1470
|
return {
|
|
978
|
-
enabled:
|
|
1471
|
+
enabled: optionalBoolean2(targetSettings.enabled, defaults.enabled, `hooks.targets.${target}.enabled`),
|
|
979
1472
|
events: parsedEvents
|
|
980
1473
|
};
|
|
981
1474
|
}
|
|
982
|
-
function
|
|
1475
|
+
function optionalBoolean2(value, fallback, path) {
|
|
983
1476
|
if (value === undefined)
|
|
984
1477
|
return fallback;
|
|
985
1478
|
if (typeof value !== "boolean")
|
|
986
1479
|
throw new Error(`Invalid ${path}; expected boolean.`);
|
|
987
1480
|
return value;
|
|
988
1481
|
}
|
|
989
|
-
function
|
|
1482
|
+
function isRecord2(value) {
|
|
990
1483
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
991
1484
|
}
|
|
992
1485
|
|
|
@@ -1020,7 +1513,8 @@ function createDefaultSettings(os = process.platform) {
|
|
|
1020
1513
|
},
|
|
1021
1514
|
hooks: createDefaultHookSettings(),
|
|
1022
1515
|
teamRuntime: createDefaultTeamRuntimeSettings(),
|
|
1023
|
-
memory: createDefaultMemorySettings()
|
|
1516
|
+
memory: createDefaultMemorySettings(),
|
|
1517
|
+
evolution: createDefaultEvolutionSettings()
|
|
1024
1518
|
};
|
|
1025
1519
|
}
|
|
1026
1520
|
function createDefaultTeamRuntimeSettings() {
|
|
@@ -1034,10 +1528,23 @@ function createDefaultTeamRuntimeSettings() {
|
|
|
1034
1528
|
}
|
|
1035
1529
|
function createDefaultMemorySettings() {
|
|
1036
1530
|
return {
|
|
1037
|
-
|
|
1531
|
+
reviewKnowledgeUpdates: true,
|
|
1038
1532
|
runtimeInjection: true,
|
|
1039
1533
|
staleReview: true,
|
|
1040
|
-
lexicalIndex: true
|
|
1534
|
+
lexicalIndex: true,
|
|
1535
|
+
sessionMemory: createDefaultSessionMemoryPolicy()
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
function createDefaultEvolutionSettings() {
|
|
1539
|
+
return {
|
|
1540
|
+
schedule: {
|
|
1541
|
+
dailyTime: "02:00"
|
|
1542
|
+
},
|
|
1543
|
+
automation: {
|
|
1544
|
+
knowledge: true,
|
|
1545
|
+
semanticKnowledge: false,
|
|
1546
|
+
recommendations: false
|
|
1547
|
+
}
|
|
1041
1548
|
};
|
|
1042
1549
|
}
|
|
1043
1550
|
function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
@@ -1080,16 +1587,28 @@ function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
|
1080
1587
|
memory: {
|
|
1081
1588
|
...defaults.memory,
|
|
1082
1589
|
...existing.memory
|
|
1590
|
+
},
|
|
1591
|
+
evolution: {
|
|
1592
|
+
...defaults.evolution,
|
|
1593
|
+
...existing.evolution,
|
|
1594
|
+
schedule: {
|
|
1595
|
+
...defaults.evolution.schedule,
|
|
1596
|
+
...existing.evolution?.schedule
|
|
1597
|
+
},
|
|
1598
|
+
automation: {
|
|
1599
|
+
...defaults.evolution.automation,
|
|
1600
|
+
...existing.evolution?.automation
|
|
1601
|
+
}
|
|
1083
1602
|
}
|
|
1084
1603
|
};
|
|
1085
1604
|
return parseSettings(merged);
|
|
1086
1605
|
}
|
|
1087
1606
|
async function readRuntimeInjectionSettings(homeDir) {
|
|
1088
|
-
const
|
|
1607
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
1089
1608
|
try {
|
|
1090
|
-
return parseSettings(JSON.parse(await
|
|
1609
|
+
return parseSettings(JSON.parse(await readFile3(paths2.settingsPath, "utf8"))).memory;
|
|
1091
1610
|
} catch (error) {
|
|
1092
|
-
if (
|
|
1611
|
+
if (isNotFoundError2(error))
|
|
1093
1612
|
return createDefaultMemorySettings();
|
|
1094
1613
|
throw error;
|
|
1095
1614
|
}
|
|
@@ -1126,18 +1645,47 @@ function parseSettings(value) {
|
|
|
1126
1645
|
},
|
|
1127
1646
|
hooks: parseHookSettings(root.hooks),
|
|
1128
1647
|
teamRuntime: parseTeamRuntimeSettings(root.teamRuntime ?? createDefaultTeamRuntimeSettings(), "settings.teamRuntime"),
|
|
1129
|
-
memory: parseMemorySettings(root.memory ?? createDefaultMemorySettings(), "settings.memory")
|
|
1648
|
+
memory: parseMemorySettings(root.memory ?? createDefaultMemorySettings(), "settings.memory"),
|
|
1649
|
+
evolution: parseEvolutionSettings(root.evolution ?? createDefaultEvolutionSettings(), "settings.evolution")
|
|
1130
1650
|
};
|
|
1131
1651
|
return parsed;
|
|
1132
1652
|
}
|
|
1653
|
+
function parseEvolutionSettings(value, path) {
|
|
1654
|
+
const input = expectRecord2(value, path);
|
|
1655
|
+
const defaults = createDefaultEvolutionSettings();
|
|
1656
|
+
const schedule = expectRecord2(input.schedule ?? defaults.schedule, `${path}.schedule`);
|
|
1657
|
+
const automation = expectRecord2(input.automation ?? defaults.automation, `${path}.automation`);
|
|
1658
|
+
return {
|
|
1659
|
+
schedule: {
|
|
1660
|
+
dailyTime: parseDailyTime(schedule.dailyTime ?? defaults.schedule.dailyTime, `${path}.schedule.dailyTime`)
|
|
1661
|
+
},
|
|
1662
|
+
automation: {
|
|
1663
|
+
knowledge: automation.knowledge === undefined ? defaults.automation.knowledge : expectBoolean(automation.knowledge, `${path}.automation.knowledge`),
|
|
1664
|
+
semanticKnowledge: automation.semanticKnowledge === undefined ? defaults.automation.semanticKnowledge : expectBoolean(automation.semanticKnowledge, `${path}.automation.semanticKnowledge`),
|
|
1665
|
+
recommendations: automation.recommendations === undefined ? defaults.automation.recommendations : expectBoolean(automation.recommendations, `${path}.automation.recommendations`)
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
function parseDailyTime(value, path) {
|
|
1670
|
+
const dailyTime = expectString2(value, path);
|
|
1671
|
+
const match = /^(\d{2}):(\d{2})$/u.exec(dailyTime);
|
|
1672
|
+
if (match === null || Number(match[1]) > 23 || Number(match[2]) > 59) {
|
|
1673
|
+
throw new EvoDevConfigError(`Invalid ${path}; expected a 24-hour HH:MM time`);
|
|
1674
|
+
}
|
|
1675
|
+
return dailyTime;
|
|
1676
|
+
}
|
|
1133
1677
|
function parseMemorySettings(value, path) {
|
|
1134
1678
|
const input = expectRecord2(value, path);
|
|
1135
1679
|
const defaults = createDefaultMemorySettings();
|
|
1680
|
+
if (input.autoAccept !== undefined) {
|
|
1681
|
+
expectBoolean(input.autoAccept, `${path}.autoAccept`);
|
|
1682
|
+
}
|
|
1136
1683
|
return {
|
|
1137
|
-
|
|
1684
|
+
reviewKnowledgeUpdates: input.reviewKnowledgeUpdates === undefined ? defaults.reviewKnowledgeUpdates : expectBoolean(input.reviewKnowledgeUpdates, `${path}.reviewKnowledgeUpdates`),
|
|
1138
1685
|
runtimeInjection: input.runtimeInjection === undefined ? defaults.runtimeInjection : expectBoolean(input.runtimeInjection, `${path}.runtimeInjection`),
|
|
1139
1686
|
staleReview: input.staleReview === undefined ? defaults.staleReview : expectBoolean(input.staleReview, `${path}.staleReview`),
|
|
1140
|
-
lexicalIndex: input.lexicalIndex === undefined ? defaults.lexicalIndex : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`)
|
|
1687
|
+
lexicalIndex: input.lexicalIndex === undefined ? defaults.lexicalIndex : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`),
|
|
1688
|
+
sessionMemory: parseSessionMemoryPolicy(isPlainRecord(input.sessionMemory) ? input.sessionMemory : defaults.sessionMemory)
|
|
1141
1689
|
};
|
|
1142
1690
|
}
|
|
1143
1691
|
function parseTeamRuntimeSettings(value, path) {
|
|
@@ -1181,7 +1729,10 @@ function expectRecord2(value, path) {
|
|
|
1181
1729
|
}
|
|
1182
1730
|
return value;
|
|
1183
1731
|
}
|
|
1184
|
-
function
|
|
1732
|
+
function isPlainRecord(value) {
|
|
1733
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1734
|
+
}
|
|
1735
|
+
function isNotFoundError2(error) {
|
|
1185
1736
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1186
1737
|
}
|
|
1187
1738
|
function expectString2(value, path) {
|
|
@@ -1283,53 +1834,53 @@ function expectNonNegativeInteger(value, path) {
|
|
|
1283
1834
|
return value;
|
|
1284
1835
|
}
|
|
1285
1836
|
// packages/core/src/config/store.ts
|
|
1286
|
-
import { mkdir as mkdir2, readFile as
|
|
1287
|
-
import { dirname as
|
|
1837
|
+
import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
1838
|
+
import { dirname as dirname4 } from "node:path";
|
|
1288
1839
|
function createCoreConfigStore(homeDir) {
|
|
1289
|
-
const
|
|
1840
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
1290
1841
|
return {
|
|
1291
|
-
paths,
|
|
1842
|
+
paths: paths2,
|
|
1292
1843
|
async ensureBaseDirs() {
|
|
1293
|
-
await mkdir2(
|
|
1294
|
-
await mkdir2(
|
|
1295
|
-
await mkdir2(
|
|
1296
|
-
await mkdir2(
|
|
1297
|
-
await mkdir2(
|
|
1298
|
-
await mkdir2(
|
|
1299
|
-
await mkdir2(
|
|
1844
|
+
await mkdir2(paths2.stateDir, { recursive: true });
|
|
1845
|
+
await mkdir2(paths2.logsDir, { recursive: true });
|
|
1846
|
+
await mkdir2(paths2.knowledgeDir, { recursive: true });
|
|
1847
|
+
await mkdir2(paths2.evosCasesDir, { recursive: true });
|
|
1848
|
+
await mkdir2(paths2.roleAgentsDir, { recursive: true });
|
|
1849
|
+
await mkdir2(paths2.teamsDir, { recursive: true });
|
|
1850
|
+
await mkdir2(paths2.runsDir, { recursive: true });
|
|
1300
1851
|
},
|
|
1301
1852
|
async ensureKnowledgeBase() {
|
|
1302
|
-
await ensureKnowledgeBaseFiles(
|
|
1853
|
+
await ensureKnowledgeBaseFiles(paths2);
|
|
1303
1854
|
},
|
|
1304
1855
|
async readSettings() {
|
|
1305
|
-
return readJsonFile(
|
|
1856
|
+
return readJsonFile(paths2.settingsPath, parseSettings);
|
|
1306
1857
|
},
|
|
1307
1858
|
async writeSettings(settings) {
|
|
1308
|
-
await
|
|
1859
|
+
await writeJsonFile2(paths2.settingsPath, parseSettings(settings));
|
|
1309
1860
|
},
|
|
1310
1861
|
async mergeAndWriteSettings(input) {
|
|
1311
|
-
const current = await readJsonFileOrDefault(
|
|
1862
|
+
const current = await readJsonFileOrDefault(paths2.settingsPath, parseSettings, createDefaultSettings());
|
|
1312
1863
|
const merged = mergeSettings(input, current);
|
|
1313
|
-
await
|
|
1864
|
+
await writeJsonFile2(paths2.settingsPath, merged);
|
|
1314
1865
|
return merged;
|
|
1315
1866
|
},
|
|
1316
1867
|
async readRegistry() {
|
|
1317
|
-
return readJsonFile(
|
|
1868
|
+
return readJsonFile(paths2.registryPath, parseRegistry);
|
|
1318
1869
|
},
|
|
1319
1870
|
async writeRegistry(registry) {
|
|
1320
|
-
await
|
|
1871
|
+
await writeJsonFile2(paths2.registryPath, parseRegistry(registry));
|
|
1321
1872
|
},
|
|
1322
1873
|
async readInstallState() {
|
|
1323
|
-
return readJsonFile(
|
|
1874
|
+
return readJsonFile(paths2.installStatePath, parseInstallState);
|
|
1324
1875
|
},
|
|
1325
1876
|
async writeInstallState(state) {
|
|
1326
|
-
await
|
|
1877
|
+
await writeJsonFile2(paths2.installStatePath, parseInstallState(state));
|
|
1327
1878
|
},
|
|
1328
1879
|
async readSyncState() {
|
|
1329
|
-
return readJsonFile(
|
|
1880
|
+
return readJsonFile(paths2.syncStatePath, parseSyncState);
|
|
1330
1881
|
},
|
|
1331
1882
|
async writeSyncState(state) {
|
|
1332
|
-
await
|
|
1883
|
+
await writeJsonFile2(paths2.syncStatePath, parseSyncState(state));
|
|
1333
1884
|
}
|
|
1334
1885
|
};
|
|
1335
1886
|
}
|
|
@@ -1343,11 +1894,11 @@ async function initializeCoreConfig(homeDir) {
|
|
|
1343
1894
|
await writeIfMissing(store.paths.syncStatePath, createDefaultSyncState());
|
|
1344
1895
|
return store;
|
|
1345
1896
|
}
|
|
1346
|
-
async function ensureKnowledgeBaseFiles(
|
|
1347
|
-
await mkdir2(
|
|
1348
|
-
await mkdir2(
|
|
1349
|
-
await ensureOkfKnowledgeBase(
|
|
1350
|
-
await writeTextIfMissing2(`${
|
|
1897
|
+
async function ensureKnowledgeBaseFiles(paths2) {
|
|
1898
|
+
await mkdir2(paths2.knowledgeDir, { recursive: true });
|
|
1899
|
+
await mkdir2(paths2.evosCasesDir, { recursive: true });
|
|
1900
|
+
await ensureOkfKnowledgeBase(paths2.homeDir);
|
|
1901
|
+
await writeTextIfMissing2(`${paths2.knowledgeDir}/README.md`, [
|
|
1351
1902
|
"# EvoDev Knowledge",
|
|
1352
1903
|
"",
|
|
1353
1904
|
"Local-private knowledge base for user-accepted facts, decisions, architecture notes, and reusable domain context.",
|
|
@@ -1356,13 +1907,13 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1356
1907
|
""
|
|
1357
1908
|
].join(`
|
|
1358
1909
|
`));
|
|
1359
|
-
await writeIndexIfMissingOrMigrate(
|
|
1910
|
+
await writeIndexIfMissingOrMigrate(paths2.knowledgeIndexPath, "knowledge-index", {
|
|
1360
1911
|
version: 1,
|
|
1361
1912
|
kind: "knowledge-index",
|
|
1362
1913
|
roleTags: [],
|
|
1363
1914
|
entries: []
|
|
1364
1915
|
});
|
|
1365
|
-
await writeTextIfMissing2(`${
|
|
1916
|
+
await writeTextIfMissing2(`${paths2.evosDir}/README.md`, [
|
|
1366
1917
|
"# EvoDev Evos",
|
|
1367
1918
|
"",
|
|
1368
1919
|
"Local-private evolution case library for reviewed improvement cases and reusable process changes.",
|
|
@@ -1371,20 +1922,20 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1371
1922
|
""
|
|
1372
1923
|
].join(`
|
|
1373
1924
|
`));
|
|
1374
|
-
await writeTextIfMissing2(`${
|
|
1925
|
+
await writeTextIfMissing2(`${paths2.evosCasesDir}/README.md`, [
|
|
1375
1926
|
"# Evolution Cases",
|
|
1376
1927
|
"",
|
|
1377
1928
|
"Store one reviewed evolution case per file. Do not store raw prompts, source dumps, secrets, transcripts, or raw command output here.",
|
|
1378
1929
|
""
|
|
1379
1930
|
].join(`
|
|
1380
1931
|
`));
|
|
1381
|
-
await writeIndexIfMissingOrMigrate(
|
|
1932
|
+
await writeIndexIfMissingOrMigrate(paths2.evosIndexPath, "evos-index", {
|
|
1382
1933
|
version: 1,
|
|
1383
1934
|
kind: "evos-index",
|
|
1384
1935
|
roleTags: [],
|
|
1385
1936
|
cases: []
|
|
1386
1937
|
});
|
|
1387
|
-
await writeTextIfMissing2(`${
|
|
1938
|
+
await writeTextIfMissing2(`${paths2.roleAgentsDir}/README.md`, [
|
|
1388
1939
|
"# Role Agents",
|
|
1389
1940
|
"",
|
|
1390
1941
|
"Local-private role agent registry for EvoDev-managed agent roles and user-reviewed role extensions.",
|
|
@@ -1393,13 +1944,13 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1393
1944
|
""
|
|
1394
1945
|
].join(`
|
|
1395
1946
|
`));
|
|
1396
|
-
await writeIndexIfMissingOrMigrate(
|
|
1947
|
+
await writeIndexIfMissingOrMigrate(paths2.roleAgentsIndexPath, "role-agent-index", {
|
|
1397
1948
|
version: 1,
|
|
1398
1949
|
kind: "role-agent-index",
|
|
1399
1950
|
roles: [],
|
|
1400
1951
|
projectExtensions: []
|
|
1401
1952
|
});
|
|
1402
|
-
await writeTextIfMissing2(`${
|
|
1953
|
+
await writeTextIfMissing2(`${paths2.teamsDir}/README.md`, [
|
|
1403
1954
|
"# Agent Teams",
|
|
1404
1955
|
"",
|
|
1405
1956
|
"Local-private EvoHub team registry for reviewed role-agent team definitions.",
|
|
@@ -1408,16 +1959,16 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1408
1959
|
""
|
|
1409
1960
|
].join(`
|
|
1410
1961
|
`));
|
|
1411
|
-
await writeIndexIfMissingOrMigrate(
|
|
1962
|
+
await writeIndexIfMissingOrMigrate(paths2.teamsIndexPath, "agent-team-index", {
|
|
1412
1963
|
version: 1,
|
|
1413
1964
|
kind: "agent-team-index",
|
|
1414
1965
|
teams: []
|
|
1415
1966
|
});
|
|
1416
1967
|
}
|
|
1417
|
-
async function readJsonFile(filePath,
|
|
1968
|
+
async function readJsonFile(filePath, parse2) {
|
|
1418
1969
|
let raw;
|
|
1419
1970
|
try {
|
|
1420
|
-
raw = await
|
|
1971
|
+
raw = await readFile4(filePath, "utf8");
|
|
1421
1972
|
} catch (error) {
|
|
1422
1973
|
throw new EvoDevConfigError(`Cannot read config file (${describeFileError(error)})`, filePath);
|
|
1423
1974
|
}
|
|
@@ -1428,7 +1979,7 @@ async function readJsonFile(filePath, parse) {
|
|
|
1428
1979
|
throw new EvoDevConfigError(`Invalid JSON (${describeFileError(error)})`, filePath);
|
|
1429
1980
|
}
|
|
1430
1981
|
try {
|
|
1431
|
-
return
|
|
1982
|
+
return parse2(json);
|
|
1432
1983
|
} catch (error) {
|
|
1433
1984
|
if (error instanceof EvoDevConfigError) {
|
|
1434
1985
|
throw new EvoDevConfigError(error.message, filePath);
|
|
@@ -1436,9 +1987,9 @@ async function readJsonFile(filePath, parse) {
|
|
|
1436
1987
|
throw error;
|
|
1437
1988
|
}
|
|
1438
1989
|
}
|
|
1439
|
-
async function readJsonFileOrDefault(filePath,
|
|
1990
|
+
async function readJsonFileOrDefault(filePath, parse2, fallback) {
|
|
1440
1991
|
try {
|
|
1441
|
-
return await readJsonFile(filePath,
|
|
1992
|
+
return await readJsonFile(filePath, parse2);
|
|
1442
1993
|
} catch (error) {
|
|
1443
1994
|
if (error instanceof EvoDevConfigError && error.message.includes("ENOENT")) {
|
|
1444
1995
|
return fallback;
|
|
@@ -1448,10 +1999,10 @@ async function readJsonFileOrDefault(filePath, parse, fallback) {
|
|
|
1448
1999
|
}
|
|
1449
2000
|
async function writeIfMissing(filePath, value) {
|
|
1450
2001
|
try {
|
|
1451
|
-
await
|
|
2002
|
+
await readFile4(filePath, "utf8");
|
|
1452
2003
|
} catch (error) {
|
|
1453
2004
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1454
|
-
await
|
|
2005
|
+
await writeJsonFile2(filePath, value);
|
|
1455
2006
|
return;
|
|
1456
2007
|
}
|
|
1457
2008
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
@@ -1460,10 +2011,10 @@ async function writeIfMissing(filePath, value) {
|
|
|
1460
2011
|
async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
|
|
1461
2012
|
let raw;
|
|
1462
2013
|
try {
|
|
1463
|
-
raw = await
|
|
2014
|
+
raw = await readFile4(filePath, "utf8");
|
|
1464
2015
|
} catch (error) {
|
|
1465
2016
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1466
|
-
await
|
|
2017
|
+
await writeJsonFile2(filePath, defaults);
|
|
1467
2018
|
return;
|
|
1468
2019
|
}
|
|
1469
2020
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
@@ -1474,27 +2025,27 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
|
|
|
1474
2025
|
} catch (error) {
|
|
1475
2026
|
throw new EvoDevConfigError(`Invalid bootstrap index JSON (${describeFileError(error)})`, filePath);
|
|
1476
2027
|
}
|
|
1477
|
-
if (!
|
|
2028
|
+
if (!isRecord3(existing) || existing.kind !== kind)
|
|
1478
2029
|
return;
|
|
1479
2030
|
const migrated = { ...defaults, ...existing };
|
|
1480
2031
|
if (Object.keys(defaults).every((key) => (key in existing)))
|
|
1481
2032
|
return;
|
|
1482
|
-
await
|
|
2033
|
+
await writeJsonFile2(filePath, migrated);
|
|
1483
2034
|
}
|
|
1484
2035
|
async function writeTextIfMissing2(filePath, value) {
|
|
1485
2036
|
try {
|
|
1486
|
-
await
|
|
2037
|
+
await readFile4(filePath, "utf8");
|
|
1487
2038
|
} catch (error) {
|
|
1488
2039
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1489
|
-
await mkdir2(
|
|
2040
|
+
await mkdir2(dirname4(filePath), { recursive: true });
|
|
1490
2041
|
await writeFile2(filePath, value, "utf8");
|
|
1491
2042
|
return;
|
|
1492
2043
|
}
|
|
1493
2044
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
1494
2045
|
}
|
|
1495
2046
|
}
|
|
1496
|
-
async function
|
|
1497
|
-
await mkdir2(
|
|
2047
|
+
async function writeJsonFile2(filePath, value) {
|
|
2048
|
+
await mkdir2(dirname4(filePath), { recursive: true });
|
|
1498
2049
|
await writeFile2(filePath, `${JSON.stringify(value, null, 2)}
|
|
1499
2050
|
`, "utf8");
|
|
1500
2051
|
}
|
|
@@ -1507,24 +2058,25 @@ function describeFileError(error) {
|
|
|
1507
2058
|
function isNodeError(error) {
|
|
1508
2059
|
return error instanceof Error && "code" in error;
|
|
1509
2060
|
}
|
|
1510
|
-
function
|
|
2061
|
+
function isRecord3(value) {
|
|
1511
2062
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1512
2063
|
}
|
|
1513
2064
|
export {
|
|
1514
|
-
|
|
1515
|
-
readRuntimeInjectionSettings,
|
|
1516
|
-
parseSyncState,
|
|
1517
|
-
parseSettings,
|
|
1518
|
-
parseRegistry,
|
|
1519
|
-
parseInstallState,
|
|
1520
|
-
mergeSettings,
|
|
1521
|
-
initializeCoreConfig,
|
|
1522
|
-
createDefaultTeamRuntimeSettings,
|
|
1523
|
-
createDefaultSyncState,
|
|
1524
|
-
createDefaultSettings,
|
|
1525
|
-
createDefaultRegistry,
|
|
1526
|
-
createDefaultMemorySettings,
|
|
1527
|
-
createDefaultInstallState,
|
|
2065
|
+
EvoDevConfigError,
|
|
1528
2066
|
createCoreConfigStore,
|
|
1529
|
-
|
|
2067
|
+
createDefaultEvolutionSettings,
|
|
2068
|
+
createDefaultInstallState,
|
|
2069
|
+
createDefaultMemorySettings,
|
|
2070
|
+
createDefaultRegistry,
|
|
2071
|
+
createDefaultSettings,
|
|
2072
|
+
createDefaultSyncState,
|
|
2073
|
+
createDefaultTeamRuntimeSettings,
|
|
2074
|
+
initializeCoreConfig,
|
|
2075
|
+
mergeSettings,
|
|
2076
|
+
parseInstallState,
|
|
2077
|
+
parseRegistry,
|
|
2078
|
+
parseSettings,
|
|
2079
|
+
parseSyncState,
|
|
2080
|
+
readRuntimeInjectionSettings,
|
|
2081
|
+
resolveEvoDevPaths
|
|
1530
2082
|
};
|