@evo-dev/evodev 0.0.1-alpha.2 → 0.0.1-alpha.3

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/dist/index.js CHANGED
@@ -223,7 +223,7 @@ var require_lib = __commonJS((exports, module) => {
223
223
 
224
224
  // packages/cli/src/index.ts
225
225
  import { realpathSync } from "node:fs";
226
- import { resolve as resolve8 } from "node:path";
226
+ import { resolve as resolve9 } from "node:path";
227
227
  import { fileURLToPath as fileURLToPath4 } from "node:url";
228
228
 
229
229
  // packages/core/src/agents/index.ts
@@ -7034,7 +7034,7 @@ function isRecord6(value) {
7034
7034
  // packages/core/src/team/index.ts
7035
7035
  import { spawn } from "node:child_process";
7036
7036
  import { appendFile as appendFile2, cp, mkdir as mkdir6, readFile as readFile7, readdir as readdir5, stat as stat6, writeFile as writeFile5 } from "node:fs/promises";
7037
- import { basename as basename3, dirname as dirname6, join as join7 } from "node:path";
7037
+ import { basename as basename3, dirname as dirname6, extname, isAbsolute as isAbsolute5, join as join7, relative as relative6, resolve as resolve4 } from "node:path";
7038
7038
 
7039
7039
  // packages/core/src/team/prompts.ts
7040
7040
  var TEAM_ROLE_STARTUP_PROMPT_TEMPLATE = [
@@ -7212,6 +7212,23 @@ var BUILT_IN_ROLE_PROMPTS = {
7212
7212
  prompt: "You are the implementation executor for this EvoDev team run. Keep changes scoped, avoid taking conductor decisions, and report changed files plus verification evidence."
7213
7213
  }
7214
7214
  };
7215
+ var BUILT_IN_TEAM_DEFINITION = {
7216
+ version: 1,
7217
+ name: "builtin-minimal-team",
7218
+ description: "Built-in minimal EvoDev team fallback.",
7219
+ agents: {
7220
+ executor: "builtin:executor",
7221
+ reviewer: "builtin:reviewer",
7222
+ tester: "builtin:tester"
7223
+ },
7224
+ body: [
7225
+ "# Built-in Minimal Team",
7226
+ "",
7227
+ "Use role agents only when delegation improves correctness, coverage, safety, or latency.",
7228
+ "Spawn roles on demand and send self-contained assignments through Teams MCP."
7229
+ ].join(`
7230
+ `)
7231
+ };
7215
7232
  function createTeamRunStore(homeDir) {
7216
7233
  const paths = resolveTeamRunPaths(homeDir);
7217
7234
  return {
@@ -8215,9 +8232,188 @@ async function listTeamAgents(input = {}) {
8215
8232
  isMidTurn: isMidTurnTeamAgentStatus(agent.status)
8216
8233
  }));
8217
8234
  }
8235
+ async function resolveTeamOverlay(input) {
8236
+ const repoTeamPath = join7(input.repoRoot, ".evodev", "team", "team.md");
8237
+ if (await pathExists5(repoTeamPath)) {
8238
+ return {
8239
+ source: "repo",
8240
+ teamPath: repoTeamPath,
8241
+ definition: parseTeamDefinitionMarkdown(await readFile7(repoTeamPath, "utf8"))
8242
+ };
8243
+ }
8244
+ const globalTeamPath = resolveGlobalTeamMarkdownPath(input.homeDir);
8245
+ if (await pathExists5(globalTeamPath)) {
8246
+ return {
8247
+ source: "global",
8248
+ teamPath: globalTeamPath,
8249
+ definition: parseTeamDefinitionMarkdown(await readFile7(globalTeamPath, "utf8"))
8250
+ };
8251
+ }
8252
+ return {
8253
+ source: "builtin",
8254
+ teamPath: null,
8255
+ definition: BUILT_IN_TEAM_DEFINITION
8256
+ };
8257
+ }
8258
+ async function ensureDefaultTeamOverlay(input) {
8259
+ const assets = await listDefaultTeamOverlayAssets(input.assetsRootDir);
8260
+ const paths = resolveEvoDevPaths(input.homeDir);
8261
+ const files = [];
8262
+ for (const asset of assets) {
8263
+ const targetPath = asset.kind === "team" ? join7(paths.rootDir, "team", "team.md") : join7(paths.rootDir, "team", "agents", asset.name);
8264
+ const content = await readFile7(asset.sourcePath, "utf8");
8265
+ files.push({
8266
+ sourcePath: asset.sourcePath,
8267
+ targetPath,
8268
+ written: await writeTextFileIfMissing(targetPath, content)
8269
+ });
8270
+ }
8271
+ return { files };
8272
+ }
8273
+ function parseTeamDefinitionMarkdown(content) {
8274
+ const markdown = parseMarkdownWithFrontmatter(content);
8275
+ const frontmatter = markdown.frontmatter;
8276
+ const version = frontmatter.version;
8277
+ if (version !== 1)
8278
+ throw new Error("team.md frontmatter version must be 1.");
8279
+ const agents = parseTeamDefinitionAgents(frontmatter.agents);
8280
+ return {
8281
+ version: 1,
8282
+ name: optionalString4(frontmatter.name) ?? "evodev-team",
8283
+ description: optionalString4(frontmatter.description) ?? "EvoDev team overlay.",
8284
+ agents,
8285
+ body: markdown.body.trim()
8286
+ };
8287
+ }
8288
+ function resolveTeamAgentReference(input) {
8289
+ assertSafeId(input.roleId, "roleId");
8290
+ const reference = input.reference.trim();
8291
+ if (reference.startsWith("global:")) {
8292
+ const name = reference.slice("global:".length);
8293
+ assertSafeId(name, "global agent name");
8294
+ return {
8295
+ roleId: input.roleId,
8296
+ reference,
8297
+ sourcePath: join7(resolveEvoDevPaths(input.homeDir).rootDir, "team", "agents", `${name}.md`),
8298
+ scope: "global"
8299
+ };
8300
+ }
8301
+ if (reference.includes(":")) {
8302
+ throw new Error(`Unsupported team agent reference for ${input.roleId}: ${reference}`);
8303
+ }
8304
+ if (isAbsolute5(reference)) {
8305
+ throw new Error(`Team agent path for ${input.roleId} must be repo-relative.`);
8306
+ }
8307
+ const sourcePath = resolve4(input.repoRoot, reference);
8308
+ const relativePath = relative6(input.repoRoot, sourcePath);
8309
+ if (relativePath === "" || relativePath.startsWith("..") || isAbsolute5(relativePath) || extname(sourcePath) !== ".md") {
8310
+ throw new Error(`Team agent path for ${input.roleId} must be a repo-local Markdown file.`);
8311
+ }
8312
+ return {
8313
+ roleId: input.roleId,
8314
+ reference,
8315
+ sourcePath,
8316
+ scope: "repo"
8317
+ };
8318
+ }
8319
+ async function readTeamAgentSummary(input) {
8320
+ const reference = resolveTeamAgentReference(input);
8321
+ const markdown = await readTeamAgentMarkdown(reference);
8322
+ const parsed = parseMarkdownWithFrontmatter(markdown);
8323
+ return {
8324
+ roleId: input.roleId,
8325
+ name: optionalString4(parsed.frontmatter.name) ?? defaultRoleName(input.roleId),
8326
+ description: optionalString4(parsed.frontmatter.description) ?? `EvoDev ${input.roleId} role agent.`,
8327
+ sourcePath: reference.sourcePath
8328
+ };
8329
+ }
8330
+ async function readTeamAgentDefinition(input) {
8331
+ const reference = resolveTeamAgentReference(input);
8332
+ const markdown = await readTeamAgentMarkdown(reference);
8333
+ const parsed = parseMarkdownWithFrontmatter(markdown);
8334
+ const evodev = isRecord7(parsed.frontmatter.evodev) ? parsed.frontmatter.evodev : {};
8335
+ return {
8336
+ roleId: input.roleId,
8337
+ name: optionalString4(parsed.frontmatter.name) ?? defaultRoleName(input.roleId),
8338
+ description: optionalString4(parsed.frontmatter.description) ?? `EvoDev ${input.roleId} role agent.`,
8339
+ runtime: optionalRuntime(evodev.runtime),
8340
+ model: optionalNullableString(parsed.frontmatter.model) ?? null,
8341
+ thinkingLevel: optionalNullableString(evodev.thinking) ?? optionalNullableString(evodev.thinkingLevel) ?? null,
8342
+ writeMode: optionalWriteMode(evodev.writeMode),
8343
+ skills: parseStringList(evodev.skills),
8344
+ sourcePath: reference.sourcePath,
8345
+ markdown
8346
+ };
8347
+ }
8348
+ async function renderMainTeamOverlayContext(input) {
8349
+ const overlay = input.overlay ?? await resolveTeamOverlay(input);
8350
+ const summaries = await readTeamOverlayAgentSummaries({
8351
+ homeDir: input.homeDir,
8352
+ repoRoot: input.repoRoot,
8353
+ overlay
8354
+ });
8355
+ const roleLines = summaries.length === 0 ? ["- none declared"] : summaries.map((summary) => `- ${summary.roleId}: ${summary.name} - ${summary.description}`);
8356
+ const source = overlay.teamPath === null ? `${overlay.source} fallback` : `${overlay.source}: ${overlay.teamPath}`;
8357
+ return [
8358
+ "EvoDev team overlay:",
8359
+ `Team: ${overlay.definition.name}`,
8360
+ `Description: ${overlay.definition.description}`,
8361
+ `Source: ${source}`,
8362
+ "",
8363
+ "Team strategy:",
8364
+ overlay.definition.body || "(none)",
8365
+ "",
8366
+ "Declared role agents:",
8367
+ ...roleLines,
8368
+ "",
8369
+ "Overlay rules:",
8370
+ "- Declared role agents are spawned only on demand.",
8371
+ "- Delegate by role id; role agent Markdown is loaded only inside the spawned role."
8372
+ ].join(`
8373
+ `);
8374
+ }
8375
+ function renderRoleAgentDefinitionContext(input) {
8376
+ return [
8377
+ "EvoDev role agent Markdown definition:",
8378
+ `Source path: ${input.definition.sourcePath}`,
8379
+ "Use this Markdown as the role-specific operating definition for this role only.",
8380
+ "<evodev-agent-markdown>",
8381
+ input.definition.markdown.trimEnd(),
8382
+ "</evodev-agent-markdown>"
8383
+ ].join(`
8384
+ `);
8385
+ }
8218
8386
  async function resolveTeamRole(input) {
8219
8387
  assertSafeId(input.roleId, "roleId");
8220
8388
  const settings = await readSettingsOrDefault(input.homeDir);
8389
+ const overlay = await resolveTeamOverlay({ homeDir: input.homeDir, repoRoot: input.repoRoot });
8390
+ if (overlay.source !== "builtin" && input.roleId !== "main") {
8391
+ const reference = overlay.definition.agents[input.roleId];
8392
+ if (reference === undefined) {
8393
+ throw new Error(`Role ${input.roleId} is not declared in team overlay ${overlay.teamPath ?? overlay.source}.`);
8394
+ }
8395
+ const agent = await readTeamAgentDefinition({
8396
+ homeDir: input.homeDir,
8397
+ repoRoot: input.repoRoot,
8398
+ roleId: input.roleId,
8399
+ reference
8400
+ });
8401
+ return {
8402
+ version: 1,
8403
+ roleId: input.roleId,
8404
+ roleName: agent.name,
8405
+ description: agent.description,
8406
+ runtime: agent.runtime ?? settings.teamRuntime.defaultRuntime,
8407
+ model: agent.model ?? settings.teamRuntime.defaultModel,
8408
+ thinkingLevel: agent.thinkingLevel ?? settings.teamRuntime.defaultThinkingLevel,
8409
+ prompt: renderRoleAgentDefinitionContext({ definition: agent }),
8410
+ permissions: parseRolePermissions({ writeMode: agent.writeMode ?? undefined }, false),
8411
+ teamPolicy: parseRolePolicy(undefined, settings.teamRuntime.recordTranscript),
8412
+ source: "overlay",
8413
+ sourcePath: agent.sourcePath,
8414
+ nativeAgent: null
8415
+ };
8416
+ }
8221
8417
  const globalRolePath = join7(resolveEvoDevPaths(input.homeDir).roleAgentsDir, `${input.roleId}.json`);
8222
8418
  const candidate = await readRoleCandidate(globalRolePath, "global");
8223
8419
  const nativeAgent = await resolveTeamRoleNativeAgentBinding({
@@ -8236,11 +8432,17 @@ async function resolveTeamRole(input) {
8236
8432
  defaultThinkingLevel: settings.teamRuntime.defaultThinkingLevel,
8237
8433
  recordTranscript: settings.teamRuntime.recordTranscript
8238
8434
  });
8435
+ const prompt = input.roleId === "main" ? appendPromptBlock(parsed.prompt, await renderMainTeamOverlayContext({
8436
+ homeDir: input.homeDir,
8437
+ repoRoot: input.repoRoot,
8438
+ overlay
8439
+ })) : parsed.prompt;
8239
8440
  return {
8240
8441
  ...parsed,
8241
8442
  runtime: input.overrides?.runtime ?? nativeAgent?.target ?? parsed.runtime,
8242
8443
  model: input.overrides?.model ?? parsed.model,
8243
8444
  thinkingLevel: input.overrides?.thinkingLevel ?? parsed.thinkingLevel,
8445
+ prompt,
8244
8446
  sourcePath,
8245
8447
  nativeAgent
8246
8448
  };
@@ -8470,7 +8672,7 @@ class TmuxRuntimeAdapter {
8470
8672
 
8471
8673
  class NodeTeamRuntimeCommandRunner {
8472
8674
  async run(command, args, options = {}) {
8473
- return new Promise((resolve4, reject) => {
8675
+ return new Promise((resolve5, reject) => {
8474
8676
  const child = spawn(command, args, { stdio: ["pipe", "pipe", "pipe"] });
8475
8677
  let stdout = "";
8476
8678
  let stderr = "";
@@ -8484,7 +8686,7 @@ class NodeTeamRuntimeCommandRunner {
8484
8686
  });
8485
8687
  child.once("error", reject);
8486
8688
  child.once("close", (code) => {
8487
- resolve4({ exitCode: code ?? 1, stdout, stderr });
8689
+ resolve5({ exitCode: code ?? 1, stdout, stderr });
8488
8690
  });
8489
8691
  child.stdin.end(options.input ?? "");
8490
8692
  });
@@ -8749,6 +8951,206 @@ function createBuiltInRole(roleId, runtime) {
8749
8951
  prompt: builtin?.prompt ?? defaultRolePrompt(roleId)
8750
8952
  };
8751
8953
  }
8954
+ async function readTeamOverlayAgentSummaries(input) {
8955
+ const entries = Object.entries(input.overlay.definition.agents);
8956
+ if (input.overlay.source === "builtin") {
8957
+ return entries.map(([roleId]) => {
8958
+ const builtin = BUILT_IN_ROLE_PROMPTS[roleId];
8959
+ return {
8960
+ roleId,
8961
+ name: builtin?.roleName ?? defaultRoleName(roleId),
8962
+ description: builtin?.description ?? `EvoDev ${roleId} role agent.`,
8963
+ sourcePath: "builtin"
8964
+ };
8965
+ });
8966
+ }
8967
+ return Promise.all(entries.map(([roleId, reference]) => readTeamAgentSummary({
8968
+ homeDir: input.homeDir,
8969
+ repoRoot: input.repoRoot,
8970
+ roleId,
8971
+ reference
8972
+ })));
8973
+ }
8974
+ async function listDefaultTeamOverlayAssets(assetsRootDir) {
8975
+ const teamPath = join7(assetsRootDir, "team", "team.md");
8976
+ const agentsDir = join7(assetsRootDir, "team", "agents");
8977
+ await assertReadableFile(teamPath, "Default team asset");
8978
+ let entries;
8979
+ try {
8980
+ entries = await readdir5(agentsDir, { withFileTypes: true });
8981
+ } catch (error) {
8982
+ throw new Error(`Cannot read default team agents directory ${agentsDir}: ${describeError2(error)}`);
8983
+ }
8984
+ const agentFiles = entries.filter((entry) => entry.isFile() && extname(entry.name) === ".md").map((entry) => entry.name).sort();
8985
+ if (agentFiles.length === 0) {
8986
+ throw new Error(`Default team agents directory has no Markdown files: ${agentsDir}`);
8987
+ }
8988
+ return [
8989
+ { kind: "team", sourcePath: teamPath, name: "team.md" },
8990
+ ...agentFiles.map((name) => ({
8991
+ kind: "agent",
8992
+ sourcePath: join7(agentsDir, name),
8993
+ name
8994
+ }))
8995
+ ];
8996
+ }
8997
+ async function assertReadableFile(path, label) {
8998
+ try {
8999
+ const info = await stat6(path);
9000
+ if (!info.isFile())
9001
+ throw new Error("not a file");
9002
+ } catch (error) {
9003
+ throw new Error(`${label} is not readable at ${path}: ${describeError2(error)}`);
9004
+ }
9005
+ }
9006
+ async function writeTextFileIfMissing(path, content) {
9007
+ try {
9008
+ await readFile7(path, "utf8");
9009
+ return false;
9010
+ } catch (error) {
9011
+ if (!isNotFoundError2(error)) {
9012
+ throw new Error(`Cannot inspect ${path}: ${describeError2(error)}`);
9013
+ }
9014
+ }
9015
+ await mkdir6(dirname6(path), { recursive: true });
9016
+ await writeFile5(path, content.endsWith(`
9017
+ `) ? content : `${content}
9018
+ `, "utf8");
9019
+ return true;
9020
+ }
9021
+ function parseTeamDefinitionAgents(value) {
9022
+ if (value === undefined)
9023
+ return {};
9024
+ if (!isRecord7(value))
9025
+ throw new Error("team.md agents must be a role-id map.");
9026
+ const agents = {};
9027
+ for (const [roleId, reference] of Object.entries(value)) {
9028
+ assertSafeId(roleId, "team.md agents roleId");
9029
+ if (typeof reference !== "string" || reference.trim() === "") {
9030
+ throw new Error(`team.md agent reference for ${roleId} must be a non-empty string.`);
9031
+ }
9032
+ agents[roleId] = reference.trim();
9033
+ }
9034
+ return agents;
9035
+ }
9036
+ async function readTeamAgentMarkdown(reference) {
9037
+ if (extname(reference.sourcePath) !== ".md") {
9038
+ throw new Error(`Team agent file for ${reference.roleId} must be Markdown.`);
9039
+ }
9040
+ try {
9041
+ return await readFile7(reference.sourcePath, "utf8");
9042
+ } catch (error) {
9043
+ if (isNotFoundError2(error)) {
9044
+ throw new Error(`Team agent file not found for ${reference.roleId}: ${reference.sourcePath}`);
9045
+ }
9046
+ throw new Error(`Cannot read team agent file for ${reference.roleId}: ${reference.sourcePath}: ${describeError2(error)}`);
9047
+ }
9048
+ }
9049
+ function parseMarkdownWithFrontmatter(content) {
9050
+ const text = content.startsWith("\uFEFF") ? content.slice(1) : content;
9051
+ const lines = text.split(/\r?\n/);
9052
+ if (lines[0]?.trim() !== "---")
9053
+ return { frontmatter: {}, body: text };
9054
+ const end = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
9055
+ if (end < 0)
9056
+ throw new Error("Markdown frontmatter is not closed.");
9057
+ return {
9058
+ frontmatter: parseSimpleYaml(lines.slice(1, end).join(`
9059
+ `)),
9060
+ body: lines.slice(end + 1).join(`
9061
+ `)
9062
+ };
9063
+ }
9064
+ function parseSimpleYaml(content) {
9065
+ const root = {};
9066
+ const stack = [
9067
+ { indent: -1, value: root }
9068
+ ];
9069
+ const lines = content.split(/\r?\n/);
9070
+ for (let index = 0;index < lines.length; index += 1) {
9071
+ const rawLine = lines[index] ?? "";
9072
+ if (rawLine.trim() === "" || rawLine.trimStart().startsWith("#"))
9073
+ continue;
9074
+ const indent = rawLine.match(/^ */)?.[0].length ?? 0;
9075
+ const trimmed = rawLine.trim();
9076
+ while (stack.length > 1 && indent <= stack[stack.length - 1].indent)
9077
+ stack.pop();
9078
+ const parent = stack[stack.length - 1].value;
9079
+ if (trimmed.startsWith("- ")) {
9080
+ if (!Array.isArray(parent))
9081
+ throw new Error("Invalid YAML list item placement.");
9082
+ parent.push(parseYamlScalar(trimmed.slice(2).trim()));
9083
+ continue;
9084
+ }
9085
+ const separator = trimmed.indexOf(":");
9086
+ if (separator <= 0)
9087
+ throw new Error(`Invalid YAML line: ${trimmed}`);
9088
+ const key = trimmed.slice(0, separator).trim();
9089
+ const rawValue = trimmed.slice(separator + 1).trim();
9090
+ if (!isRecord7(parent))
9091
+ throw new Error(`Invalid YAML parent for key ${key}.`);
9092
+ if (rawValue === "") {
9093
+ const next = findNextYamlContentLine(lines, index + 1);
9094
+ const value = next !== null && next.indent > indent && next.trimmed.startsWith("- ") ? [] : {};
9095
+ parent[key] = value;
9096
+ stack.push({ indent, value });
9097
+ continue;
9098
+ }
9099
+ parent[key] = parseYamlScalar(rawValue);
9100
+ }
9101
+ return root;
9102
+ }
9103
+ function findNextYamlContentLine(lines, start) {
9104
+ for (let index = start;index < lines.length; index += 1) {
9105
+ const line = lines[index] ?? "";
9106
+ if (line.trim() === "" || line.trimStart().startsWith("#"))
9107
+ continue;
9108
+ return {
9109
+ indent: line.match(/^ */)?.[0].length ?? 0,
9110
+ trimmed: line.trim()
9111
+ };
9112
+ }
9113
+ return null;
9114
+ }
9115
+ function parseYamlScalar(value) {
9116
+ if (value === "")
9117
+ return "";
9118
+ if (value === "true")
9119
+ return true;
9120
+ if (value === "false")
9121
+ return false;
9122
+ if (value === "null" || value === "~")
9123
+ return null;
9124
+ if (/^-?\d+(\.\d+)?$/.test(value))
9125
+ return Number(value);
9126
+ if (value.startsWith("[") && value.endsWith("]")) {
9127
+ const inner = value.slice(1, -1).trim();
9128
+ if (inner === "")
9129
+ return [];
9130
+ return inner.split(",").map((item) => parseYamlScalar(item.trim()));
9131
+ }
9132
+ if (value.startsWith('"') && value.endsWith('"')) {
9133
+ try {
9134
+ return JSON.parse(value);
9135
+ } catch {
9136
+ return value.slice(1, -1);
9137
+ }
9138
+ }
9139
+ if (value.startsWith("'") && value.endsWith("'")) {
9140
+ return value.slice(1, -1).replace(/''/g, "'");
9141
+ }
9142
+ return value;
9143
+ }
9144
+ function appendPromptBlock(prompt, block) {
9145
+ if (block.trim() === "")
9146
+ return prompt;
9147
+ return `${prompt.trimEnd()}
9148
+
9149
+ ${block.trim()}`;
9150
+ }
9151
+ function resolveGlobalTeamMarkdownPath(homeDir) {
9152
+ return join7(resolveEvoDevPaths(homeDir).rootDir, "team", "team.md");
9153
+ }
8752
9154
  function parseRolePermissions(value, main) {
8753
9155
  const input = isRecord7(value) ? value : {};
8754
9156
  return {
@@ -8861,6 +9263,13 @@ function parseRuntime(value, fallback) {
8861
9263
  return value;
8862
9264
  throw new Error("Role runtime must be codex or claude.");
8863
9265
  }
9266
+ function optionalRuntime(value) {
9267
+ if (value === undefined || value === null)
9268
+ return null;
9269
+ if (value === "codex" || value === "claude")
9270
+ return value;
9271
+ throw new Error("Role evodev.runtime must be codex or claude.");
9272
+ }
8864
9273
  function parseWriteMode(value, fallback) {
8865
9274
  if (value === undefined || value === null)
8866
9275
  return fallback;
@@ -8869,6 +9278,20 @@ function parseWriteMode(value, fallback) {
8869
9278
  }
8870
9279
  throw new Error("Role writeMode is invalid.");
8871
9280
  }
9281
+ function optionalWriteMode(value) {
9282
+ if (value === undefined || value === null)
9283
+ return null;
9284
+ return parseWriteMode(value, "repo-write");
9285
+ }
9286
+ function parseStringList(value) {
9287
+ if (value === undefined || value === null)
9288
+ return [];
9289
+ if (typeof value === "string" && value.trim() !== "")
9290
+ return [value.trim()];
9291
+ if (!Array.isArray(value))
9292
+ return [];
9293
+ return value.filter((item) => typeof item === "string" && item.trim() !== "");
9294
+ }
8872
9295
  function isActiveTeamAgentStatus(status) {
8873
9296
  return status === "starting" || status === "running" || status === "busy" || status === "idle" || status === "waiting-input" || status === "recovering" || status === "recreated";
8874
9297
  }
@@ -9607,7 +10030,7 @@ async function handleUserPromptSubmit(input) {
9607
10030
  const previousBinding = await readSessionBinding(input.homeDir, input.rawPayload);
9608
10031
  const teamRuntimeContext = previousBinding?.teamRuntimeContextDeliveredAt === undefined || previousBinding.teamRuntimeContextDeliveredAt === null ? await createTeamRuntimeContextForUserPrompt(input) : null;
9609
10032
  const shouldShowDiagnostics = input.teamRuntimeDisplayMode === "development";
9610
- const teamRuntimeContextDeliveredAt = teamRuntimeContext !== null && shouldShowDiagnostics ? input.receivedAt ?? new Date().toISOString() : previousBinding?.teamRuntimeContextDeliveredAt ?? null;
10033
+ const teamRuntimeContextDeliveredAt = teamRuntimeContext !== null ? input.receivedAt ?? new Date().toISOString() : previousBinding?.teamRuntimeContextDeliveredAt ?? null;
9611
10034
  const binding = {
9612
10035
  version: 1,
9613
10036
  target: input.target,
@@ -9629,7 +10052,7 @@ async function handleUserPromptSubmit(input) {
9629
10052
  let output = visibleContext === null || !shouldShowDiagnostics ? null : hookOutput(input.event.type, {
9630
10053
  additionalContext: visibleContext
9631
10054
  });
9632
- if (teamRuntimeContext !== null && shouldShowDiagnostics) {
10055
+ if (teamRuntimeContext !== null) {
9633
10056
  output = appendAdditionalContext(output, input.event.type, teamRuntimeContext);
9634
10057
  }
9635
10058
  return createRuntimeResult(input, output, {
@@ -10852,14 +11275,14 @@ async function runDaemonForeground(input) {
10852
11275
  }));
10853
11276
  }
10854
11277
  });
10855
- await new Promise((resolve4, reject) => {
11278
+ await new Promise((resolve5, reject) => {
10856
11279
  const onError = (error) => {
10857
11280
  server.off("listening", onListening);
10858
11281
  reject(error);
10859
11282
  };
10860
11283
  const onListening = () => {
10861
11284
  server.off("error", onError);
10862
- resolve4();
11285
+ resolve5();
10863
11286
  };
10864
11287
  server.once("error", onError);
10865
11288
  server.once("listening", onListening);
@@ -10876,11 +11299,11 @@ async function runDaemonForeground(input) {
10876
11299
  processEvolutionTriggers({ homeDir: input.homeDir, limit: 20 }).then(() => clearDaemonEvolutionProcessError(input.homeDir)).catch((error) => recordDaemonEvolutionProcessError(input.homeDir, error));
10877
11300
  }, 5000);
10878
11301
  evolutionInterval.unref();
10879
- await new Promise((resolve4, reject) => {
11302
+ await new Promise((resolve5, reject) => {
10880
11303
  server.once("close", () => {
10881
11304
  clearInterval(reconcileInterval);
10882
11305
  clearInterval(evolutionInterval);
10883
- resolve4();
11306
+ resolve5();
10884
11307
  });
10885
11308
  server.once("error", reject);
10886
11309
  });
@@ -11750,7 +12173,7 @@ function isRecord10(value) {
11750
12173
  }
11751
12174
  // packages/core/src/pack/index.ts
11752
12175
  import { readFile as readFile14, readdir as readdir8, stat as stat10 } from "node:fs/promises";
11753
- import { isAbsolute as isAbsolute5, join as join12, relative as relative6, sep } from "node:path";
12176
+ import { isAbsolute as isAbsolute6, join as join12, relative as relative7, sep } from "node:path";
11754
12177
 
11755
12178
  // packages/core/src/protected-zones/index.ts
11756
12179
  var SENSITIVE_DIRECTORY_SEGMENTS = new Set([
@@ -12234,7 +12657,7 @@ async function collectPackRelativePaths(packRoot, dir = packRoot) {
12234
12657
  const paths = [];
12235
12658
  for (const entry of entries) {
12236
12659
  const absolutePath = join12(dir, entry.name);
12237
- const relativePath = normalizeRelativePath(relative6(packRoot, absolutePath));
12660
+ const relativePath = normalizeRelativePath(relative7(packRoot, absolutePath));
12238
12661
  paths.push(relativePath);
12239
12662
  if (entry.isDirectory()) {
12240
12663
  paths.push(...await collectPackRelativePaths(packRoot, absolutePath));
@@ -12249,7 +12672,7 @@ function validatePackRelativePath(path, packRoot) {
12249
12672
  if (path.includes("\x00")) {
12250
12673
  return { severity: "error", code: "path-invalid", message: "Path must not contain NUL bytes." };
12251
12674
  }
12252
- if (isAbsolute5(path) || path.startsWith("~")) {
12675
+ if (isAbsolute6(path) || path.startsWith("~")) {
12253
12676
  return {
12254
12677
  severity: "error",
12255
12678
  code: "path-absolute",
@@ -12265,8 +12688,8 @@ function validatePackRelativePath(path, packRoot) {
12265
12688
  };
12266
12689
  }
12267
12690
  const absolute = join12(packRoot, normalized);
12268
- const rel = relative6(packRoot, absolute);
12269
- if (rel === "" || rel.startsWith("..") || isAbsolute5(rel)) {
12691
+ const rel = relative7(packRoot, absolute);
12692
+ if (rel === "" || rel.startsWith("..") || isAbsolute6(rel)) {
12270
12693
  return {
12271
12694
  severity: "error",
12272
12695
  code: "path-traversal",
@@ -12601,7 +13024,7 @@ function getEnabledPluginIds(settings) {
12601
13024
  }
12602
13025
  // packages/core/src/project/index.ts
12603
13026
  import { mkdir as mkdir13, readFile as readFile16, readdir as readdir9, stat as stat11, writeFile as writeFile12 } from "node:fs/promises";
12604
- import { basename as basename5, join as join14, relative as relative7 } from "node:path";
13027
+ import { basename as basename5, join as join14, relative as relative8 } from "node:path";
12605
13028
  var PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS = [
12606
13029
  ".evodev/project.json",
12607
13030
  ".evodev/profile.md",
@@ -12808,7 +13231,7 @@ async function collectProjectFileMetadata(projectDir) {
12808
13231
  const entries = await readdir9(dir, { withFileTypes: true });
12809
13232
  for (const entry of entries) {
12810
13233
  const absolutePath = join14(dir, entry.name);
12811
- const relativePath = relative7(projectDir, absolutePath).replaceAll("\\", "/");
13234
+ const relativePath = relative8(projectDir, absolutePath).replaceAll("\\", "/");
12812
13235
  if (shouldExcludePath(relativePath, entry.isDirectory())) {
12813
13236
  continue;
12814
13237
  }
@@ -13552,7 +13975,7 @@ function getProcessArgvBin() {
13552
13975
 
13553
13976
  // node_modules/.bun/yargs-parser@22.0.0/node_modules/yargs-parser/build/lib/index.js
13554
13977
  import { format } from "util";
13555
- import { normalize as normalize2, resolve as resolve4 } from "path";
13978
+ import { normalize as normalize2, resolve as resolve5 } from "path";
13556
13979
 
13557
13980
  // node_modules/.bun/yargs-parser@22.0.0/node_modules/yargs-parser/build/lib/string-utils.js
13558
13981
  function camelCase(str) {
@@ -14510,7 +14933,7 @@ var parser = new YargsParser({
14510
14933
  },
14511
14934
  format,
14512
14935
  normalize: normalize2,
14513
- resolve: resolve4,
14936
+ resolve: resolve5,
14514
14937
  require: (path) => {
14515
14938
  if (typeof require2 !== "undefined") {
14516
14939
  return require2(path);
@@ -15298,10 +15721,10 @@ function ui(opts) {
15298
15721
  }
15299
15722
 
15300
15723
  // node_modules/.bun/escalade@3.2.0/node_modules/escalade/sync/index.mjs
15301
- import { dirname as dirname13, resolve as resolve5 } from "path";
15724
+ import { dirname as dirname13, resolve as resolve6 } from "path";
15302
15725
  import { readdirSync as readdirSync2, statSync } from "fs";
15303
15726
  function sync_default(start, callback) {
15304
- let dir = resolve5(".", start);
15727
+ let dir = resolve6(".", start);
15305
15728
  let tmp, stats = statSync(dir);
15306
15729
  if (!stats.isDirectory()) {
15307
15730
  dir = dirname13(dir);
@@ -15309,7 +15732,7 @@ function sync_default(start, callback) {
15309
15732
  while (true) {
15310
15733
  tmp = callback(dir, readdirSync2(dir));
15311
15734
  if (tmp)
15312
- return resolve5(dir, tmp);
15735
+ return resolve6(dir, tmp);
15313
15736
  dir = dirname13(tmp = dir);
15314
15737
  if (tmp === dir)
15315
15738
  break;
@@ -15319,19 +15742,19 @@ function sync_default(start, callback) {
15319
15742
  // node_modules/.bun/yargs@18.0.0/node_modules/yargs/lib/platform-shims/esm.mjs
15320
15743
  import { inspect } from "util";
15321
15744
  import { fileURLToPath } from "url";
15322
- import { basename as basename6, dirname as dirname14, extname, relative as relative8, resolve as resolve7, join as join17 } from "path";
15745
+ import { basename as basename6, dirname as dirname14, extname as extname2, relative as relative9, resolve as resolve8, join as join17 } from "path";
15323
15746
 
15324
15747
  // node_modules/.bun/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js
15325
15748
  import { readFileSync as readFileSync3, statSync as statSync2, writeFile as writeFile13 } from "fs";
15326
15749
  import { format as format2 } from "util";
15327
- import { resolve as resolve6 } from "path";
15750
+ import { resolve as resolve7 } from "path";
15328
15751
  var node_default = {
15329
15752
  fs: {
15330
15753
  readFileSync: readFileSync3,
15331
15754
  writeFile: writeFile13
15332
15755
  },
15333
15756
  format: format2,
15334
- resolve: resolve6,
15757
+ resolve: resolve7,
15335
15758
  exists: (file) => {
15336
15759
  try {
15337
15760
  return statSync2(file).isFile();
@@ -15530,9 +15953,9 @@ var esm_default = {
15530
15953
  path: {
15531
15954
  basename: basename6,
15532
15955
  dirname: dirname14,
15533
- extname,
15534
- relative: relative8,
15535
- resolve: resolve7,
15956
+ extname: extname2,
15957
+ relative: relative9,
15958
+ resolve: resolve8,
15536
15959
  join: join17
15537
15960
  },
15538
15961
  process: {
@@ -15555,7 +15978,7 @@ var esm_default = {
15555
15978
  },
15556
15979
  stringWidth,
15557
15980
  y18n: y18n_default({
15558
- directory: resolve7(__dirname2, "../../../locales"),
15981
+ directory: resolve8(__dirname2, "../../../locales"),
15559
15982
  updateFiles: false
15560
15983
  })
15561
15984
  };
@@ -17299,13 +17722,13 @@ class ScreenManager {
17299
17722
  // node_modules/.bun/@inquirer+core@11.2.1+6983e0b160ab4824/node_modules/@inquirer/core/dist/lib/promise-polyfill.js
17300
17723
  class PromisePolyfill extends Promise {
17301
17724
  static withResolver() {
17302
- let resolve8;
17725
+ let resolve9;
17303
17726
  let reject;
17304
17727
  const promise = new Promise((res, rej) => {
17305
- resolve8 = res;
17728
+ resolve9 = res;
17306
17729
  reject = rej;
17307
17730
  });
17308
- return { promise, resolve: resolve8, reject };
17731
+ return { promise, resolve: resolve9, reject };
17309
17732
  }
17310
17733
  }
17311
17734
 
@@ -17342,7 +17765,7 @@ function createPrompt(view) {
17342
17765
  });
17343
17766
  output.mute();
17344
17767
  const screen = new ScreenManager(rl);
17345
- const { promise, resolve: resolve8, reject } = PromisePolyfill.withResolver();
17768
+ const { promise, resolve: resolve9, reject } = PromisePolyfill.withResolver();
17346
17769
  const cancel = () => reject(new CancelPromptError);
17347
17770
  if (signal) {
17348
17771
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -17373,7 +17796,7 @@ function createPrompt(view) {
17373
17796
  try {
17374
17797
  const nextView = view(config2, (value) => {
17375
17798
  if (effectsSettled) {
17376
- resolve8(value);
17799
+ resolve9(value);
17377
17800
  } else {
17378
17801
  pendingDone = { value };
17379
17802
  }
@@ -17396,7 +17819,7 @@ function createPrompt(view) {
17396
17819
  if (pendingDone !== null) {
17397
17820
  const { value } = pendingDone;
17398
17821
  pendingDone = null;
17399
- resolve8(value);
17822
+ resolve9(value);
17400
17823
  }
17401
17824
  });
17402
17825
  };
@@ -17631,7 +18054,7 @@ import { dirname as dirname17 } from "node:path";
17631
18054
  // packages/plugin/hooks/command-runner.ts
17632
18055
  import { spawn as spawn2 } from "node:child_process";
17633
18056
  async function runNodeCommand(command, args) {
17634
- return new Promise((resolve8, reject) => {
18057
+ return new Promise((resolve9, reject) => {
17635
18058
  const child = spawn2(command, args, {
17636
18059
  stdio: ["ignore", "pipe", "pipe"]
17637
18060
  });
@@ -17647,7 +18070,7 @@ async function runNodeCommand(command, args) {
17647
18070
  });
17648
18071
  child.once("error", reject);
17649
18072
  child.once("close", (code) => {
17650
- resolve8({ exitCode: code ?? 1, stdout, stderr });
18073
+ resolve9({ exitCode: code ?? 1, stdout, stderr });
17651
18074
  });
17652
18075
  });
17653
18076
  }
@@ -19454,7 +19877,7 @@ function isTerminalStatus(status) {
19454
19877
  return status !== "doing";
19455
19878
  }
19456
19879
  function defaultSleep(ms) {
19457
- return new Promise((resolve8) => setTimeout(resolve8, ms));
19880
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
19458
19881
  }
19459
19882
 
19460
19883
  // packages/cli/src/init.ts
@@ -19552,6 +19975,7 @@ async function runInit(options = {}) {
19552
19975
  });
19553
19976
  await store.ensureBaseDirs();
19554
19977
  await store.ensureKnowledgeBase();
19978
+ await ensureDefaultTeamOverlay({ homeDir, assetsRootDir });
19555
19979
  emitInitProgress(options.progress, {
19556
19980
  status: "done",
19557
19981
  current: 2,
@@ -20924,17 +21348,17 @@ async function startEvolutionReviewServer(input) {
20924
21348
  response.end(error instanceof Error ? error.message : String(error));
20925
21349
  }
20926
21350
  });
20927
- await new Promise((resolve8) => {
20928
- server.listen(input.flags.port, input.flags.host, resolve8);
21351
+ await new Promise((resolve9) => {
21352
+ server.listen(input.flags.port, input.flags.host, resolve9);
20929
21353
  });
20930
21354
  const address = server.address();
20931
21355
  const port = typeof address === "object" && address !== null ? address.port : input.flags.port;
20932
21356
  input.write(`EvoDev evolution review server: http://${input.flags.host}:${port}/?token=${token}`);
20933
21357
  input.write("Mode: local-only read snapshot. Mutation actions are not implemented in this slice.");
20934
21358
  input.write("Press Ctrl+C to stop.");
20935
- return await new Promise((resolve8) => {
21359
+ return await new Promise((resolve9) => {
20936
21360
  const close = () => {
20937
- server.close(() => resolve8(0));
21361
+ server.close(() => resolve9(0));
20938
21362
  };
20939
21363
  process.once("SIGINT", close);
20940
21364
  process.once("SIGTERM", close);
@@ -22595,10 +23019,10 @@ function shouldAttachAfterStart(flags, options) {
22595
23019
 
22596
23020
  class TmuxAttachRunner {
22597
23021
  async attachSession(session) {
22598
- return new Promise((resolve8, reject) => {
23022
+ return new Promise((resolve9, reject) => {
22599
23023
  const child = spawn3("tmux", ["-u", "attach-session", "-t", session], { stdio: "inherit" });
22600
23024
  child.on("error", reject);
22601
- child.on("close", (code) => resolve8(code ?? 0));
23025
+ child.on("close", (code) => resolve9(code ?? 0));
22602
23026
  });
22603
23027
  }
22604
23028
  }
@@ -23166,7 +23590,7 @@ function getHelpText() {
23166
23590
  ].join(`
23167
23591
  `);
23168
23592
  }
23169
- var CLI_VERSION = "0.0.1-alpha.2";
23593
+ var CLI_VERSION = "0.0.1-alpha.3";
23170
23594
  function getVersionText() {
23171
23595
  return `evodev ${CLI_VERSION}`;
23172
23596
  }
@@ -23732,7 +24156,7 @@ if (isMainModule()) {
23732
24156
  process.exitCode = await run();
23733
24157
  }
23734
24158
  function isMainModule() {
23735
- return process.argv[1] !== undefined && realpathSync(fileURLToPath4(import.meta.url)) === realpathSync(resolve8(process.argv[1]));
24159
+ return process.argv[1] !== undefined && realpathSync(fileURLToPath4(import.meta.url)) === realpathSync(resolve9(process.argv[1]));
23736
24160
  }
23737
24161
  export {
23738
24162
  runWorkflowCommand,