@elizaos/autonomous 2.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/package.json +270 -0
- package/src/actions/emote.ts +101 -0
- package/src/actions/restart.ts +101 -0
- package/src/actions/send-message.ts +168 -0
- package/src/actions/stream-control.ts +439 -0
- package/src/actions/switch-stream-source.ts +126 -0
- package/src/actions/terminal.ts +186 -0
- package/src/api/agent-admin-routes.ts +178 -0
- package/src/api/agent-lifecycle-routes.ts +129 -0
- package/src/api/agent-model.ts +143 -0
- package/src/api/agent-transfer-routes.ts +211 -0
- package/src/api/apps-routes.ts +210 -0
- package/src/api/auth-routes.ts +90 -0
- package/src/api/bsc-trade.ts +736 -0
- package/src/api/bug-report-routes.ts +161 -0
- package/src/api/character-routes.ts +421 -0
- package/src/api/cloud-billing-routes.ts +598 -0
- package/src/api/cloud-compat-routes.ts +192 -0
- package/src/api/cloud-routes.ts +529 -0
- package/src/api/cloud-status-routes.ts +234 -0
- package/src/api/compat-utils.ts +154 -0
- package/src/api/connector-health.ts +135 -0
- package/src/api/coordinator-wiring.ts +179 -0
- package/src/api/credit-detection.ts +47 -0
- package/src/api/database.ts +1357 -0
- package/src/api/diagnostics-routes.ts +389 -0
- package/src/api/drop-service.ts +205 -0
- package/src/api/early-logs.ts +111 -0
- package/src/api/http-helpers.ts +252 -0
- package/src/api/index.ts +85 -0
- package/src/api/knowledge-routes.ts +1189 -0
- package/src/api/knowledge-service-loader.ts +92 -0
- package/src/api/memory-bounds.ts +121 -0
- package/src/api/memory-routes.ts +349 -0
- package/src/api/merkle-tree.ts +239 -0
- package/src/api/models-routes.ts +72 -0
- package/src/api/nfa-routes.ts +169 -0
- package/src/api/nft-verify.ts +188 -0
- package/src/api/og-tracker.ts +72 -0
- package/src/api/parse-action-block.ts +145 -0
- package/src/api/permissions-routes.ts +222 -0
- package/src/api/plugin-validation.ts +355 -0
- package/src/api/provider-switch-config.ts +455 -0
- package/src/api/registry-routes.ts +165 -0
- package/src/api/registry-service.ts +292 -0
- package/src/api/route-helpers.ts +21 -0
- package/src/api/sandbox-routes.ts +1480 -0
- package/src/api/server.ts +17674 -0
- package/src/api/signal-routes.ts +265 -0
- package/src/api/stream-persistence.ts +297 -0
- package/src/api/stream-route-state.ts +48 -0
- package/src/api/stream-routes.ts +1046 -0
- package/src/api/stream-voice-routes.ts +208 -0
- package/src/api/streaming-text.ts +129 -0
- package/src/api/streaming-types.ts +23 -0
- package/src/api/subscription-routes.ts +283 -0
- package/src/api/terminal-run-limits.ts +31 -0
- package/src/api/training-backend-check.ts +40 -0
- package/src/api/training-routes.ts +314 -0
- package/src/api/training-service-like.ts +46 -0
- package/src/api/trajectory-routes.ts +714 -0
- package/src/api/trigger-routes.ts +438 -0
- package/src/api/twitter-verify.ts +226 -0
- package/src/api/tx-service.ts +193 -0
- package/src/api/wallet-dex-prices.ts +206 -0
- package/src/api/wallet-evm-balance.ts +989 -0
- package/src/api/wallet-routes.ts +505 -0
- package/src/api/wallet-rpc.ts +523 -0
- package/src/api/wallet-trading-profile.ts +694 -0
- package/src/api/wallet.ts +745 -0
- package/src/api/whatsapp-routes.ts +282 -0
- package/src/api/zip-utils.ts +130 -0
- package/src/auth/anthropic.ts +63 -0
- package/src/auth/apply-stealth.ts +38 -0
- package/src/auth/claude-code-stealth.ts +141 -0
- package/src/auth/credentials.ts +226 -0
- package/src/auth/index.ts +18 -0
- package/src/auth/openai-codex.ts +94 -0
- package/src/auth/types.ts +24 -0
- package/src/awareness/registry.ts +220 -0
- package/src/bin.ts +10 -0
- package/src/cli/index.ts +36 -0
- package/src/cli/parse-duration.ts +43 -0
- package/src/cloud/auth.test.ts +370 -0
- package/src/cloud/auth.ts +176 -0
- package/src/cloud/backup.test.ts +150 -0
- package/src/cloud/backup.ts +50 -0
- package/src/cloud/base-url.ts +45 -0
- package/src/cloud/bridge-client.test.ts +481 -0
- package/src/cloud/bridge-client.ts +307 -0
- package/src/cloud/cloud-manager.test.ts +223 -0
- package/src/cloud/cloud-manager.ts +151 -0
- package/src/cloud/cloud-proxy.test.ts +122 -0
- package/src/cloud/cloud-proxy.ts +52 -0
- package/src/cloud/index.ts +23 -0
- package/src/cloud/reconnect.test.ts +178 -0
- package/src/cloud/reconnect.ts +108 -0
- package/src/cloud/validate-url.test.ts +147 -0
- package/src/cloud/validate-url.ts +176 -0
- package/src/config/character-schema.ts +44 -0
- package/src/config/config.ts +149 -0
- package/src/config/env-vars.ts +86 -0
- package/src/config/includes.ts +196 -0
- package/src/config/index.ts +15 -0
- package/src/config/object-utils.ts +10 -0
- package/src/config/paths.ts +92 -0
- package/src/config/plugin-auto-enable.ts +520 -0
- package/src/config/schema.ts +1342 -0
- package/src/config/telegram-custom-commands.ts +99 -0
- package/src/config/types.agent-defaults.ts +342 -0
- package/src/config/types.agents.ts +112 -0
- package/src/config/types.gateway.ts +243 -0
- package/src/config/types.hooks.ts +124 -0
- package/src/config/types.messages.ts +201 -0
- package/src/config/types.milady.ts +791 -0
- package/src/config/types.tools.ts +416 -0
- package/src/config/types.ts +7 -0
- package/src/config/zod-schema.agent-runtime.ts +777 -0
- package/src/config/zod-schema.core.ts +778 -0
- package/src/config/zod-schema.hooks.ts +139 -0
- package/src/config/zod-schema.providers-core.ts +1126 -0
- package/src/config/zod-schema.session.ts +98 -0
- package/src/config/zod-schema.ts +865 -0
- package/src/contracts/apps.ts +46 -0
- package/src/contracts/awareness.ts +56 -0
- package/src/contracts/config.ts +172 -0
- package/src/contracts/drop.ts +21 -0
- package/src/contracts/index.ts +8 -0
- package/src/contracts/onboarding.ts +592 -0
- package/src/contracts/permissions.ts +52 -0
- package/src/contracts/verification.ts +9 -0
- package/src/contracts/wallet.ts +503 -0
- package/src/diagnostics/integration-observability.ts +132 -0
- package/src/emotes/catalog.ts +655 -0
- package/src/external-modules.d.ts +7 -0
- package/src/hooks/discovery.test.ts +357 -0
- package/src/hooks/discovery.ts +231 -0
- package/src/hooks/eligibility.ts +146 -0
- package/src/hooks/hooks.test.ts +320 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/loader.test.ts +418 -0
- package/src/hooks/loader.ts +256 -0
- package/src/hooks/registry.test.ts +168 -0
- package/src/hooks/registry.ts +74 -0
- package/src/hooks/types.ts +121 -0
- package/src/index.ts +19 -0
- package/src/onboarding-presets.ts +828 -0
- package/src/plugins/custom-rtmp/index.ts +40 -0
- package/src/providers/admin-trust.ts +76 -0
- package/src/providers/session-bridge.ts +143 -0
- package/src/providers/session-utils.ts +42 -0
- package/src/providers/simple-mode.ts +113 -0
- package/src/providers/ui-catalog.ts +135 -0
- package/src/providers/workspace-provider.ts +213 -0
- package/src/providers/workspace.ts +497 -0
- package/src/runtime/agent-event-service.ts +57 -0
- package/src/runtime/cloud-onboarding.test.ts +489 -0
- package/src/runtime/cloud-onboarding.ts +408 -0
- package/src/runtime/core-plugins.ts +53 -0
- package/src/runtime/custom-actions.ts +605 -0
- package/src/runtime/eliza.ts +4941 -0
- package/src/runtime/embedding-presets.ts +73 -0
- package/src/runtime/index.ts +8 -0
- package/src/runtime/milady-plugin.ts +180 -0
- package/src/runtime/onboarding-names.ts +76 -0
- package/src/runtime/release-plugin-policy.ts +119 -0
- package/src/runtime/restart.ts +59 -0
- package/src/runtime/trajectory-persistence.ts +2584 -0
- package/src/runtime/version.ts +6 -0
- package/src/security/audit-log.ts +222 -0
- package/src/security/network-policy.ts +91 -0
- package/src/server/index.ts +6 -0
- package/src/services/agent-export.ts +976 -0
- package/src/services/app-manager.ts +755 -0
- package/src/services/browser-capture.ts +215 -0
- package/src/services/coding-agent-context.ts +355 -0
- package/src/services/fallback-training-service.ts +196 -0
- package/src/services/index.ts +17 -0
- package/src/services/mcp-marketplace.ts +327 -0
- package/src/services/plugin-manager-types.ts +185 -0
- package/src/services/privy-wallets.ts +352 -0
- package/src/services/registry-client-app-meta.ts +201 -0
- package/src/services/registry-client-endpoints.ts +253 -0
- package/src/services/registry-client-local.ts +485 -0
- package/src/services/registry-client-network.ts +173 -0
- package/src/services/registry-client-queries.ts +176 -0
- package/src/services/registry-client-types.ts +104 -0
- package/src/services/registry-client.ts +366 -0
- package/src/services/remote-signing-service.ts +261 -0
- package/src/services/sandbox-engine.ts +753 -0
- package/src/services/sandbox-manager.ts +503 -0
- package/src/services/self-updater.ts +213 -0
- package/src/services/signal-pairing.ts +189 -0
- package/src/services/signing-policy.ts +230 -0
- package/src/services/skill-catalog-client.ts +195 -0
- package/src/services/skill-marketplace.ts +909 -0
- package/src/services/stream-manager.ts +707 -0
- package/src/services/tts-stream-bridge.ts +465 -0
- package/src/services/update-checker.ts +163 -0
- package/src/services/version-compat.ts +367 -0
- package/src/services/whatsapp-pairing.ts +279 -0
- package/src/shared/ui-catalog-prompt.ts +1158 -0
- package/src/test-support/process-helpers.ts +35 -0
- package/src/test-support/route-test-helpers.ts +113 -0
- package/src/test-support/test-helpers.ts +304 -0
- package/src/testing/index.ts +3 -0
- package/src/triggers/action.ts +342 -0
- package/src/triggers/runtime.ts +432 -0
- package/src/triggers/scheduling.ts +472 -0
- package/src/triggers/types.ts +133 -0
- package/src/types/app-hyperscape-routes-shim.d.ts +29 -0
- package/src/types/external-modules.d.ts +7 -0
- package/src/utils/exec-safety.ts +23 -0
- package/src/utils/number-parsing.ts +112 -0
- package/src/utils/spoken-text.ts +65 -0
- package/src/version-resolver.ts +60 -0
- package/test/api/agent-admin-routes.test.ts +160 -0
- package/test/api/agent-lifecycle-routes.test.ts +164 -0
- package/test/api/agent-transfer-routes.test.ts +136 -0
- package/test/api/apps-routes.test.ts +140 -0
- package/test/api/auth-routes.test.ts +160 -0
- package/test/api/bug-report-routes.test.ts +88 -0
- package/test/api/knowledge-routes.test.ts +73 -0
- package/test/api/lifecycle.test.ts +342 -0
- package/test/api/memory-routes.test.ts +74 -0
- package/test/api/models-routes.test.ts +112 -0
- package/test/api/nfa-routes.test.ts +78 -0
- package/test/api/permissions-routes.test.ts +185 -0
- package/test/api/registry-routes.test.ts +157 -0
- package/test/api/signal-routes.test.ts +113 -0
- package/test/api/subscription-routes.test.ts +90 -0
- package/test/api/trigger-routes.test.ts +87 -0
- package/test/api/wallet-routes.observability.test.ts +191 -0
- package/test/api/wallet-routes.test.ts +502 -0
- package/test/diagnostics/integration-observability.test.ts +135 -0
- package/test/security/audit-log.test.ts +229 -0
- package/test/security/network-policy.test.ts +143 -0
- package/test/services/version-compat.test.ts +127 -0
- package/tsconfig.build.json +21 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads workspace bootstrap files and injects them into agent context.
|
|
3
|
+
*
|
|
4
|
+
* Also provides coding agent context enrichment: when coding-agent metadata
|
|
5
|
+
* is present on the inbound message, the provider appends a summary of the
|
|
6
|
+
* current coding session state (active iteration, recent errors, pending
|
|
7
|
+
* feedback) so the LLM has full awareness during the autonomous coding loop.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
ChannelType,
|
|
12
|
+
type IAgentRuntime,
|
|
13
|
+
logger,
|
|
14
|
+
type Memory,
|
|
15
|
+
type Provider,
|
|
16
|
+
type ProviderResult,
|
|
17
|
+
type State,
|
|
18
|
+
} from "@elizaos/core";
|
|
19
|
+
import type { CodingAgentContext } from "../services/coding-agent-context";
|
|
20
|
+
import {
|
|
21
|
+
DEFAULT_AGENT_WORKSPACE_DIR,
|
|
22
|
+
filterBootstrapFilesForSession,
|
|
23
|
+
loadWorkspaceBootstrapFiles,
|
|
24
|
+
type WorkspaceBootstrapFile,
|
|
25
|
+
} from "./workspace";
|
|
26
|
+
|
|
27
|
+
const DEFAULT_MAX_CHARS = 20_000;
|
|
28
|
+
/** Hard cap on total workspace context to prevent prompt explosion. */
|
|
29
|
+
const MAX_TOTAL_WORKSPACE_CHARS = 100_000;
|
|
30
|
+
const CACHE_TTL_MS = 60_000;
|
|
31
|
+
|
|
32
|
+
// Per-workspace cache so multi-agent doesn't thrash.
|
|
33
|
+
const cache = new Map<
|
|
34
|
+
string,
|
|
35
|
+
{ files: WorkspaceBootstrapFile[]; at: number }
|
|
36
|
+
>();
|
|
37
|
+
/** Maximum number of workspace directories to cache simultaneously. */
|
|
38
|
+
const MAX_CACHE_ENTRIES = 20;
|
|
39
|
+
|
|
40
|
+
async function getFiles(dir: string): Promise<WorkspaceBootstrapFile[]> {
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const entry = cache.get(dir);
|
|
43
|
+
if (entry && now - entry.at < CACHE_TTL_MS) return entry.files;
|
|
44
|
+
|
|
45
|
+
// Evict expired entries and enforce size cap before inserting
|
|
46
|
+
for (const [key, val] of cache) {
|
|
47
|
+
if (now - val.at >= CACHE_TTL_MS) cache.delete(key);
|
|
48
|
+
}
|
|
49
|
+
if (cache.size >= MAX_CACHE_ENTRIES) {
|
|
50
|
+
// Remove the oldest entry
|
|
51
|
+
const oldest = cache.keys().next().value;
|
|
52
|
+
if (oldest) cache.delete(oldest);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const files = await loadWorkspaceBootstrapFiles(dir);
|
|
56
|
+
cache.set(dir, { files, at: now });
|
|
57
|
+
return files;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @internal Exported for testing. */
|
|
61
|
+
export function truncate(content: string, max: number): string {
|
|
62
|
+
if (content.length <= max) return content;
|
|
63
|
+
return `${content.slice(0, max)}\n\n[... truncated at ${max.toLocaleString()} chars]`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** @internal Exported for testing. */
|
|
67
|
+
export function buildContext(
|
|
68
|
+
files: WorkspaceBootstrapFile[],
|
|
69
|
+
maxChars: number,
|
|
70
|
+
): string {
|
|
71
|
+
const sections: string[] = [];
|
|
72
|
+
let totalChars = 0;
|
|
73
|
+
for (const f of files) {
|
|
74
|
+
if (f.missing || !f.content?.trim()) continue;
|
|
75
|
+
const trimmed = f.content.trim();
|
|
76
|
+
// Per-file truncation
|
|
77
|
+
const text = truncate(trimmed, maxChars);
|
|
78
|
+
const tag = text.length > trimmed.length ? " [TRUNCATED]" : "";
|
|
79
|
+
const section = `### ${f.name}${tag}\n\n${text}`;
|
|
80
|
+
// Stop adding files if the total would exceed the hard cap
|
|
81
|
+
if (
|
|
82
|
+
totalChars + section.length > MAX_TOTAL_WORKSPACE_CHARS &&
|
|
83
|
+
sections.length > 0
|
|
84
|
+
) {
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
sections.push(section);
|
|
88
|
+
totalChars += section.length;
|
|
89
|
+
}
|
|
90
|
+
if (sections.length === 0) return "";
|
|
91
|
+
return `## Project Context (Workspace)\n\n${sections.join("\n\n---\n\n")}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @internal Exported for testing. Builds a summary of the coding agent session. */
|
|
95
|
+
export function buildCodingAgentSummary(ctx: CodingAgentContext): string {
|
|
96
|
+
const lines: string[] = [];
|
|
97
|
+
|
|
98
|
+
lines.push("## Coding Agent Session");
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push(`**Task:** ${ctx.taskDescription}`);
|
|
101
|
+
lines.push(`**Working Directory:** ${ctx.workingDirectory}`);
|
|
102
|
+
lines.push(`**Connector:** ${ctx.connector.type}`);
|
|
103
|
+
lines.push(`**Mode:** ${ctx.interactionMode}`);
|
|
104
|
+
lines.push(`**Active:** ${ctx.active ? "yes" : "no"}`);
|
|
105
|
+
|
|
106
|
+
if (!ctx.connector.available) {
|
|
107
|
+
lines.push(`**Connector Status:** unavailable`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Errors from the last iteration
|
|
111
|
+
const lastIteration = ctx.iterations[ctx.iterations.length - 1];
|
|
112
|
+
if (lastIteration && lastIteration.errors.length > 0) {
|
|
113
|
+
lines.push("");
|
|
114
|
+
lines.push("### Errors to Resolve");
|
|
115
|
+
for (const err of lastIteration.errors) {
|
|
116
|
+
const loc = err.filePath
|
|
117
|
+
? err.line
|
|
118
|
+
? ` (${err.filePath}:${err.line})`
|
|
119
|
+
: ` (${err.filePath})`
|
|
120
|
+
: "";
|
|
121
|
+
lines.push(`- [${err.category}]${loc}: ${err.message}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Human feedback
|
|
126
|
+
const pendingFeedback = ctx.allFeedback.filter(
|
|
127
|
+
(fb) => !fb.iterationRef || fb.iterationRef >= ctx.iterations.length - 1,
|
|
128
|
+
);
|
|
129
|
+
if (pendingFeedback.length > 0) {
|
|
130
|
+
lines.push("");
|
|
131
|
+
lines.push("### Human Feedback");
|
|
132
|
+
for (const fb of pendingFeedback) {
|
|
133
|
+
lines.push(`- [${fb.type}]: ${fb.text}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Recent commands from the last iteration
|
|
138
|
+
if (lastIteration && lastIteration.commandResults.length > 0) {
|
|
139
|
+
lines.push("");
|
|
140
|
+
lines.push("### Recent Commands");
|
|
141
|
+
for (const cmd of lastIteration.commandResults.slice(-5)) {
|
|
142
|
+
const status = cmd.success ? "OK" : `FAIL(${cmd.exitCode})`;
|
|
143
|
+
lines.push(`- \`${cmd.command}\` → ${status}`);
|
|
144
|
+
if (cmd.stdout?.trim()) {
|
|
145
|
+
lines.push(` stdout: ${truncate(cmd.stdout.trim(), 200)}`);
|
|
146
|
+
}
|
|
147
|
+
if (cmd.stderr?.trim()) {
|
|
148
|
+
lines.push(` stderr: ${truncate(cmd.stderr.trim(), 200)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return lines.join("\n");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function createWorkspaceProvider(options?: {
|
|
157
|
+
workspaceDir?: string;
|
|
158
|
+
maxCharsPerFile?: number;
|
|
159
|
+
}): Provider {
|
|
160
|
+
const dir = options?.workspaceDir ?? DEFAULT_AGENT_WORKSPACE_DIR;
|
|
161
|
+
const maxChars = options?.maxCharsPerFile ?? DEFAULT_MAX_CHARS;
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
name: "workspaceContext",
|
|
165
|
+
description:
|
|
166
|
+
"Workspace bootstrap files (AGENTS.md, TOOLS.md, IDENTITY.md, etc.) and coding agent context",
|
|
167
|
+
position: 10,
|
|
168
|
+
|
|
169
|
+
async get(
|
|
170
|
+
_runtime: IAgentRuntime,
|
|
171
|
+
message: Memory,
|
|
172
|
+
_state: State,
|
|
173
|
+
): Promise<ProviderResult> {
|
|
174
|
+
const channelType = message.content?.channelType;
|
|
175
|
+
if (
|
|
176
|
+
channelType === ChannelType.VOICE_DM ||
|
|
177
|
+
channelType === ChannelType.VOICE_GROUP
|
|
178
|
+
) {
|
|
179
|
+
return {
|
|
180
|
+
text: "",
|
|
181
|
+
data: {
|
|
182
|
+
workspaceDir: dir,
|
|
183
|
+
skipped: "voice_channel",
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const allFiles = await getFiles(dir);
|
|
190
|
+
const meta = message.metadata as Record<string, unknown> | undefined;
|
|
191
|
+
const sessionKey =
|
|
192
|
+
typeof meta?.sessionKey === "string" ? meta.sessionKey : undefined;
|
|
193
|
+
const files = filterBootstrapFilesForSession(allFiles, sessionKey);
|
|
194
|
+
const text = buildContext(files, maxChars);
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
text,
|
|
198
|
+
data: {
|
|
199
|
+
workspaceDir: dir,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
} catch (err) {
|
|
203
|
+
logger.warn(
|
|
204
|
+
`[workspace-provider] Failed to load workspace context: ${err instanceof Error ? err.message : err}`,
|
|
205
|
+
);
|
|
206
|
+
return {
|
|
207
|
+
text: `[Workspace context unavailable: ${err instanceof Error ? err.message : err}]`,
|
|
208
|
+
data: {},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import * as elizaCore from "@elizaos/core";
|
|
6
|
+
import { resolveUserPath } from "../config/paths";
|
|
7
|
+
|
|
8
|
+
export interface RunCommandResult {
|
|
9
|
+
code: number;
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface RunCommandOptions {
|
|
15
|
+
cwd?: string;
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Runs a command with an optional timeout.
|
|
22
|
+
* Returns { code, stdout, stderr }.
|
|
23
|
+
* Rejects if the process cannot be spawned or the timeout fires.
|
|
24
|
+
*/
|
|
25
|
+
export function runCommandWithTimeout(
|
|
26
|
+
argv: string[],
|
|
27
|
+
opts: RunCommandOptions = {},
|
|
28
|
+
): Promise<RunCommandResult> {
|
|
29
|
+
const [cmd, ...args] = argv;
|
|
30
|
+
if (!cmd) {
|
|
31
|
+
return Promise.reject(new Error("runCommandWithTimeout: empty argv"));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return new Promise<RunCommandResult>((resolve, reject) => {
|
|
35
|
+
const child = spawn(cmd, args, {
|
|
36
|
+
cwd: opts.cwd,
|
|
37
|
+
env: opts.env ?? process.env,
|
|
38
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const stdoutChunks: Buffer[] = [];
|
|
42
|
+
const stderrChunks: Buffer[] = [];
|
|
43
|
+
|
|
44
|
+
child.stdout.on("data", (chunk: Buffer) => stdoutChunks.push(chunk));
|
|
45
|
+
child.stderr.on("data", (chunk: Buffer) => stderrChunks.push(chunk));
|
|
46
|
+
|
|
47
|
+
let timedOut = false;
|
|
48
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
49
|
+
|
|
50
|
+
if (opts.timeoutMs && opts.timeoutMs > 0) {
|
|
51
|
+
timer = setTimeout(() => {
|
|
52
|
+
timedOut = true;
|
|
53
|
+
child.kill("SIGKILL");
|
|
54
|
+
}, opts.timeoutMs);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
child.on("error", (err) => {
|
|
58
|
+
if (timer) clearTimeout(timer);
|
|
59
|
+
reject(err);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
child.on("close", (exitCode) => {
|
|
63
|
+
if (timer) clearTimeout(timer);
|
|
64
|
+
|
|
65
|
+
if (timedOut) {
|
|
66
|
+
reject(
|
|
67
|
+
new Error(
|
|
68
|
+
`Command timed out after ${opts.timeoutMs}ms: ${argv.join(" ")}`,
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
resolve({
|
|
75
|
+
code: exitCode ?? 1,
|
|
76
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
77
|
+
stderr: Buffer.concat(stderrChunks).toString("utf-8"),
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function resolveDefaultAgentWorkspaceDir(
|
|
84
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
85
|
+
homedir: () => string = os.homedir,
|
|
86
|
+
): string {
|
|
87
|
+
const profile = env.MILADY_PROFILE?.trim();
|
|
88
|
+
if (profile && profile.toLowerCase() !== "default") {
|
|
89
|
+
return path.join(homedir(), ".milady", `workspace-${profile}`);
|
|
90
|
+
}
|
|
91
|
+
return path.join(homedir(), ".milady", "workspace");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const DEFAULT_AGENT_WORKSPACE_DIR = resolveDefaultAgentWorkspaceDir();
|
|
95
|
+
const DEFAULT_AGENTS_FILENAME = "AGENTS.md";
|
|
96
|
+
const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
|
|
97
|
+
const DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
|
|
98
|
+
const DEFAULT_USER_FILENAME = "USER.md";
|
|
99
|
+
const DEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";
|
|
100
|
+
const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
|
|
101
|
+
const DEFAULT_MEMORY_FILENAME = "MEMORY.md";
|
|
102
|
+
const DEFAULT_MEMORY_ALT_FILENAME = "memory.md";
|
|
103
|
+
|
|
104
|
+
/** Inline workspace bootstrap templates — no external files needed. */
|
|
105
|
+
const WORKSPACE_TEMPLATES: Record<string, string> = {
|
|
106
|
+
[DEFAULT_AGENTS_FILENAME]: `# Agents
|
|
107
|
+
|
|
108
|
+
You are an autonomous AI agent powered by elizaOS.
|
|
109
|
+
|
|
110
|
+
## Capabilities
|
|
111
|
+
|
|
112
|
+
- Respond to user messages conversationally
|
|
113
|
+
- Execute actions and use available tools
|
|
114
|
+
- Access and manage knowledge from your workspace
|
|
115
|
+
- Maintain context across conversations
|
|
116
|
+
|
|
117
|
+
## Guidelines
|
|
118
|
+
|
|
119
|
+
- Be helpful, concise, and accurate
|
|
120
|
+
- Ask for clarification when instructions are ambiguous
|
|
121
|
+
- Use tools when they would help accomplish the user's goal
|
|
122
|
+
- Respect the user's preferences and communication style
|
|
123
|
+
`,
|
|
124
|
+
[DEFAULT_TOOLS_FILENAME]: `# Tools
|
|
125
|
+
|
|
126
|
+
Available tools and capabilities for the agent.
|
|
127
|
+
|
|
128
|
+
## Built-in Tools
|
|
129
|
+
|
|
130
|
+
The agent has access to tools provided by enabled plugins.
|
|
131
|
+
Each plugin may register actions, providers, and evaluators
|
|
132
|
+
that extend the agent's capabilities.
|
|
133
|
+
|
|
134
|
+
## Usage
|
|
135
|
+
|
|
136
|
+
Tools are invoked automatically when the agent determines
|
|
137
|
+
they would help accomplish the user's goal. No manual
|
|
138
|
+
configuration is required.
|
|
139
|
+
`,
|
|
140
|
+
[DEFAULT_IDENTITY_FILENAME]: `# Identity
|
|
141
|
+
|
|
142
|
+
Your character and personality settings.
|
|
143
|
+
|
|
144
|
+
Customize this file to define your agent's personality,
|
|
145
|
+
tone, and behavior style.
|
|
146
|
+
`,
|
|
147
|
+
[DEFAULT_USER_FILENAME]: `# User
|
|
148
|
+
|
|
149
|
+
User context and preferences.
|
|
150
|
+
|
|
151
|
+
This file stores information about the user to help
|
|
152
|
+
personalize interactions.
|
|
153
|
+
`,
|
|
154
|
+
[DEFAULT_HEARTBEAT_FILENAME]: `# Heartbeat
|
|
155
|
+
|
|
156
|
+
The heartbeat system enables autonomous agent behavior.
|
|
157
|
+
|
|
158
|
+
## Scheduling
|
|
159
|
+
|
|
160
|
+
When autonomy is enabled, the agent periodically evaluates
|
|
161
|
+
whether to take proactive actions based on its goals,
|
|
162
|
+
pending tasks, and environmental changes.
|
|
163
|
+
|
|
164
|
+
## Triggers
|
|
165
|
+
|
|
166
|
+
- Scheduled intervals (configurable)
|
|
167
|
+
- External events from connected channels
|
|
168
|
+
- System notifications and alerts
|
|
169
|
+
`,
|
|
170
|
+
[DEFAULT_BOOTSTRAP_FILENAME]: `# Bootstrap
|
|
171
|
+
|
|
172
|
+
Initial workspace setup for a new agent.
|
|
173
|
+
|
|
174
|
+
## Getting Started
|
|
175
|
+
|
|
176
|
+
This workspace was automatically created for your agent.
|
|
177
|
+
You can customize it by editing the markdown files in this
|
|
178
|
+
directory:
|
|
179
|
+
|
|
180
|
+
- **AGENTS.md** — Agent behavior and capabilities
|
|
181
|
+
- **TOOLS.md** — Available tools and plugins
|
|
182
|
+
- **IDENTITY.md** — Character and personality
|
|
183
|
+
- **USER.md** — User context and preferences
|
|
184
|
+
- **HEARTBEAT.md** — Autonomous behavior settings
|
|
185
|
+
|
|
186
|
+
## Configuration
|
|
187
|
+
|
|
188
|
+
Agent configuration is managed through \`~/.milady/milady.json\`
|
|
189
|
+
or the Milady Control UI.
|
|
190
|
+
`,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export type WorkspaceBootstrapFileName =
|
|
194
|
+
| typeof DEFAULT_AGENTS_FILENAME
|
|
195
|
+
| typeof DEFAULT_TOOLS_FILENAME
|
|
196
|
+
| typeof DEFAULT_IDENTITY_FILENAME
|
|
197
|
+
| typeof DEFAULT_USER_FILENAME
|
|
198
|
+
| typeof DEFAULT_HEARTBEAT_FILENAME
|
|
199
|
+
| typeof DEFAULT_BOOTSTRAP_FILENAME
|
|
200
|
+
| typeof DEFAULT_MEMORY_FILENAME
|
|
201
|
+
| typeof DEFAULT_MEMORY_ALT_FILENAME;
|
|
202
|
+
|
|
203
|
+
export type WorkspaceBootstrapFile = {
|
|
204
|
+
name: WorkspaceBootstrapFileName;
|
|
205
|
+
path: string;
|
|
206
|
+
content?: string;
|
|
207
|
+
missing: boolean;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
type ElizaCoreWorkspaceHelpers = {
|
|
211
|
+
isSubagentSessionKey?: (key: string) => boolean;
|
|
212
|
+
logger?: {
|
|
213
|
+
warn: (message: string) => void;
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const coreWorkspaceHelpers = elizaCore as ElizaCoreWorkspaceHelpers;
|
|
218
|
+
|
|
219
|
+
function isSubagentSessionKey(sessionKey: string): boolean {
|
|
220
|
+
if (typeof coreWorkspaceHelpers.isSubagentSessionKey === "function") {
|
|
221
|
+
return coreWorkspaceHelpers.isSubagentSessionKey(sessionKey);
|
|
222
|
+
}
|
|
223
|
+
// Older @elizaos/core versions do not expose subagent helpers.
|
|
224
|
+
// Treat all sessions as primary sessions in that case.
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function logWarn(message: string): void {
|
|
229
|
+
if (
|
|
230
|
+
coreWorkspaceHelpers.logger &&
|
|
231
|
+
typeof coreWorkspaceHelpers.logger.warn === "function"
|
|
232
|
+
) {
|
|
233
|
+
coreWorkspaceHelpers.logger.warn(message);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
console.warn(message);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function writeFileIfMissing(filePath: string, content: string) {
|
|
240
|
+
try {
|
|
241
|
+
await fs.writeFile(filePath, content, {
|
|
242
|
+
encoding: "utf-8",
|
|
243
|
+
flag: "wx",
|
|
244
|
+
});
|
|
245
|
+
} catch (err) {
|
|
246
|
+
if ((err as NodeJS.ErrnoException).code !== "EEXIST") {
|
|
247
|
+
throw err;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function hasGitRepo(dir: string): Promise<boolean> {
|
|
253
|
+
try {
|
|
254
|
+
await fs.stat(path.join(dir, ".git"));
|
|
255
|
+
return true;
|
|
256
|
+
} catch (err) {
|
|
257
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function isGitAvailable(): Promise<boolean> {
|
|
265
|
+
try {
|
|
266
|
+
const result = await runCommandWithTimeout(["git", "--version"], {
|
|
267
|
+
timeoutMs: 2_000,
|
|
268
|
+
});
|
|
269
|
+
return result.code === 0;
|
|
270
|
+
} catch {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function ensureGitRepo(dir: string, isBrandNewWorkspace: boolean) {
|
|
276
|
+
if (!isBrandNewWorkspace) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (await hasGitRepo(dir)) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (!(await isGitAvailable())) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
await runCommandWithTimeout(["git", "init"], {
|
|
287
|
+
cwd: dir,
|
|
288
|
+
timeoutMs: 10_000,
|
|
289
|
+
});
|
|
290
|
+
} catch (err) {
|
|
291
|
+
logWarn(
|
|
292
|
+
`[workspace] git init failed: ${err instanceof Error ? err.message : err}`,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export async function ensureAgentWorkspace(params?: {
|
|
298
|
+
dir?: string;
|
|
299
|
+
ensureBootstrapFiles?: boolean;
|
|
300
|
+
}): Promise<{
|
|
301
|
+
dir: string;
|
|
302
|
+
agentsPath?: string;
|
|
303
|
+
toolsPath?: string;
|
|
304
|
+
identityPath?: string;
|
|
305
|
+
userPath?: string;
|
|
306
|
+
heartbeatPath?: string;
|
|
307
|
+
bootstrapPath?: string;
|
|
308
|
+
}> {
|
|
309
|
+
const rawDir = params?.dir?.trim()
|
|
310
|
+
? params.dir.trim()
|
|
311
|
+
: DEFAULT_AGENT_WORKSPACE_DIR;
|
|
312
|
+
const dir = resolveUserPath(rawDir);
|
|
313
|
+
await fs.mkdir(dir, { recursive: true });
|
|
314
|
+
|
|
315
|
+
if (!params?.ensureBootstrapFiles) {
|
|
316
|
+
return { dir };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const agentsPath = path.join(dir, DEFAULT_AGENTS_FILENAME);
|
|
320
|
+
const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
|
|
321
|
+
const identityPath = path.join(dir, DEFAULT_IDENTITY_FILENAME);
|
|
322
|
+
const userPath = path.join(dir, DEFAULT_USER_FILENAME);
|
|
323
|
+
const heartbeatPath = path.join(dir, DEFAULT_HEARTBEAT_FILENAME);
|
|
324
|
+
const bootstrapPath = path.join(dir, DEFAULT_BOOTSTRAP_FILENAME);
|
|
325
|
+
|
|
326
|
+
const isBrandNewWorkspace = await (async () => {
|
|
327
|
+
const paths = [
|
|
328
|
+
agentsPath,
|
|
329
|
+
toolsPath,
|
|
330
|
+
identityPath,
|
|
331
|
+
userPath,
|
|
332
|
+
heartbeatPath,
|
|
333
|
+
];
|
|
334
|
+
const existing = await Promise.all(
|
|
335
|
+
paths.map(async (p) => {
|
|
336
|
+
try {
|
|
337
|
+
await fs.access(p);
|
|
338
|
+
return true;
|
|
339
|
+
} catch (err) {
|
|
340
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
throw err;
|
|
344
|
+
}
|
|
345
|
+
}),
|
|
346
|
+
);
|
|
347
|
+
return existing.every((v) => !v);
|
|
348
|
+
})();
|
|
349
|
+
|
|
350
|
+
const agentsTemplate = WORKSPACE_TEMPLATES[DEFAULT_AGENTS_FILENAME];
|
|
351
|
+
const toolsTemplate = WORKSPACE_TEMPLATES[DEFAULT_TOOLS_FILENAME];
|
|
352
|
+
const identityTemplate = WORKSPACE_TEMPLATES[DEFAULT_IDENTITY_FILENAME];
|
|
353
|
+
const userTemplate = WORKSPACE_TEMPLATES[DEFAULT_USER_FILENAME];
|
|
354
|
+
const heartbeatTemplate = WORKSPACE_TEMPLATES[DEFAULT_HEARTBEAT_FILENAME];
|
|
355
|
+
const bootstrapTemplate = WORKSPACE_TEMPLATES[DEFAULT_BOOTSTRAP_FILENAME];
|
|
356
|
+
|
|
357
|
+
const writeOps = [
|
|
358
|
+
writeFileIfMissing(agentsPath, agentsTemplate),
|
|
359
|
+
writeFileIfMissing(toolsPath, toolsTemplate),
|
|
360
|
+
writeFileIfMissing(identityPath, identityTemplate),
|
|
361
|
+
writeFileIfMissing(userPath, userTemplate),
|
|
362
|
+
writeFileIfMissing(heartbeatPath, heartbeatTemplate),
|
|
363
|
+
];
|
|
364
|
+
if (isBrandNewWorkspace) {
|
|
365
|
+
writeOps.push(writeFileIfMissing(bootstrapPath, bootstrapTemplate));
|
|
366
|
+
}
|
|
367
|
+
await Promise.all(writeOps);
|
|
368
|
+
await ensureGitRepo(dir, isBrandNewWorkspace);
|
|
369
|
+
|
|
370
|
+
return {
|
|
371
|
+
dir,
|
|
372
|
+
agentsPath,
|
|
373
|
+
toolsPath,
|
|
374
|
+
identityPath,
|
|
375
|
+
userPath,
|
|
376
|
+
heartbeatPath,
|
|
377
|
+
bootstrapPath,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async function resolveMemoryBootstrapEntries(
|
|
382
|
+
resolvedDir: string,
|
|
383
|
+
): Promise<Array<{ name: WorkspaceBootstrapFileName; filePath: string }>> {
|
|
384
|
+
const candidates: WorkspaceBootstrapFileName[] = [
|
|
385
|
+
DEFAULT_MEMORY_FILENAME,
|
|
386
|
+
DEFAULT_MEMORY_ALT_FILENAME,
|
|
387
|
+
];
|
|
388
|
+
const entries: Array<{ name: WorkspaceBootstrapFileName; filePath: string }> =
|
|
389
|
+
[];
|
|
390
|
+
for (const name of candidates) {
|
|
391
|
+
const filePath = path.join(resolvedDir, name);
|
|
392
|
+
try {
|
|
393
|
+
await fs.access(filePath);
|
|
394
|
+
entries.push({ name, filePath });
|
|
395
|
+
} catch (err) {
|
|
396
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
397
|
+
throw err;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (entries.length <= 1) {
|
|
402
|
+
return entries;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const seen = new Set<string>();
|
|
406
|
+
const deduped: Array<{ name: WorkspaceBootstrapFileName; filePath: string }> =
|
|
407
|
+
[];
|
|
408
|
+
for (const entry of entries) {
|
|
409
|
+
let key = entry.filePath;
|
|
410
|
+
try {
|
|
411
|
+
key = await fs.realpath(entry.filePath);
|
|
412
|
+
} catch (err) {
|
|
413
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
414
|
+
throw err;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (seen.has(key)) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
seen.add(key);
|
|
421
|
+
deduped.push(entry);
|
|
422
|
+
}
|
|
423
|
+
return deduped;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export async function loadWorkspaceBootstrapFiles(
|
|
427
|
+
dir: string,
|
|
428
|
+
): Promise<WorkspaceBootstrapFile[]> {
|
|
429
|
+
const resolvedDir = resolveUserPath(dir);
|
|
430
|
+
|
|
431
|
+
const entries: Array<{
|
|
432
|
+
name: WorkspaceBootstrapFileName;
|
|
433
|
+
filePath: string;
|
|
434
|
+
}> = [
|
|
435
|
+
{
|
|
436
|
+
name: DEFAULT_AGENTS_FILENAME,
|
|
437
|
+
filePath: path.join(resolvedDir, DEFAULT_AGENTS_FILENAME),
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
name: DEFAULT_TOOLS_FILENAME,
|
|
441
|
+
filePath: path.join(resolvedDir, DEFAULT_TOOLS_FILENAME),
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: DEFAULT_IDENTITY_FILENAME,
|
|
445
|
+
filePath: path.join(resolvedDir, DEFAULT_IDENTITY_FILENAME),
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: DEFAULT_USER_FILENAME,
|
|
449
|
+
filePath: path.join(resolvedDir, DEFAULT_USER_FILENAME),
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
name: DEFAULT_HEARTBEAT_FILENAME,
|
|
453
|
+
filePath: path.join(resolvedDir, DEFAULT_HEARTBEAT_FILENAME),
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
name: DEFAULT_BOOTSTRAP_FILENAME,
|
|
457
|
+
filePath: path.join(resolvedDir, DEFAULT_BOOTSTRAP_FILENAME),
|
|
458
|
+
},
|
|
459
|
+
];
|
|
460
|
+
|
|
461
|
+
entries.push(...(await resolveMemoryBootstrapEntries(resolvedDir)));
|
|
462
|
+
|
|
463
|
+
const result = await Promise.all(
|
|
464
|
+
entries.map(async (entry): Promise<WorkspaceBootstrapFile> => {
|
|
465
|
+
try {
|
|
466
|
+
const content = await fs.readFile(entry.filePath, "utf-8");
|
|
467
|
+
return {
|
|
468
|
+
name: entry.name,
|
|
469
|
+
path: entry.filePath,
|
|
470
|
+
content,
|
|
471
|
+
missing: false,
|
|
472
|
+
};
|
|
473
|
+
} catch (err) {
|
|
474
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
475
|
+
return { name: entry.name, path: entry.filePath, missing: true };
|
|
476
|
+
}
|
|
477
|
+
throw err;
|
|
478
|
+
}
|
|
479
|
+
}),
|
|
480
|
+
);
|
|
481
|
+
return result;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const SUBAGENT_BOOTSTRAP_ALLOWLIST = new Set([
|
|
485
|
+
DEFAULT_AGENTS_FILENAME,
|
|
486
|
+
DEFAULT_TOOLS_FILENAME,
|
|
487
|
+
]);
|
|
488
|
+
|
|
489
|
+
export function filterBootstrapFilesForSession(
|
|
490
|
+
files: WorkspaceBootstrapFile[],
|
|
491
|
+
sessionKey?: string,
|
|
492
|
+
): WorkspaceBootstrapFile[] {
|
|
493
|
+
if (!sessionKey || !isSubagentSessionKey(sessionKey)) {
|
|
494
|
+
return files;
|
|
495
|
+
}
|
|
496
|
+
return files.filter((file) => SUBAGENT_BOOTSTRAP_ALLOWLIST.has(file.name));
|
|
497
|
+
}
|