@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,389 @@
|
|
|
1
|
+
import type http from "node:http";
|
|
2
|
+
import { parseClampedInteger } from "../utils/number-parsing";
|
|
3
|
+
import type { RouteHelpers, RouteRequestMeta } from "./route-helpers";
|
|
4
|
+
|
|
5
|
+
interface LogEntryLike {
|
|
6
|
+
timestamp: number;
|
|
7
|
+
level: string;
|
|
8
|
+
source: string;
|
|
9
|
+
tags: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface StreamEventEnvelopeLike {
|
|
13
|
+
type: string;
|
|
14
|
+
eventId: string;
|
|
15
|
+
runId?: string;
|
|
16
|
+
seq?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface AuditEntryLike {
|
|
20
|
+
timestamp: string;
|
|
21
|
+
type: string;
|
|
22
|
+
summary: string;
|
|
23
|
+
severity: string;
|
|
24
|
+
metadata?: Record<string, string | number | boolean | null>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type DiagnosticsSseInit = (res: http.ServerResponse) => void;
|
|
28
|
+
type DiagnosticsSseWriteJson = (
|
|
29
|
+
res: http.ServerResponse,
|
|
30
|
+
payload: object,
|
|
31
|
+
event?: string,
|
|
32
|
+
) => void;
|
|
33
|
+
|
|
34
|
+
export interface DiagnosticsRouteContext
|
|
35
|
+
extends RouteRequestMeta,
|
|
36
|
+
Pick<RouteHelpers, "json"> {
|
|
37
|
+
url: URL;
|
|
38
|
+
logBuffer: LogEntryLike[];
|
|
39
|
+
eventBuffer: StreamEventEnvelopeLike[];
|
|
40
|
+
relayPort?: number;
|
|
41
|
+
checkRelayReachable?: (relayPort: number) => Promise<boolean>;
|
|
42
|
+
resolveExtensionPath?: () => string | null;
|
|
43
|
+
initSse?: DiagnosticsSseInit;
|
|
44
|
+
writeSseJson?: DiagnosticsSseWriteJson;
|
|
45
|
+
auditEventTypes: readonly string[];
|
|
46
|
+
auditSeverities: readonly string[];
|
|
47
|
+
getAuditFeedSize: () => number;
|
|
48
|
+
queryAuditFeed: (query: {
|
|
49
|
+
type?: string;
|
|
50
|
+
severity?: string;
|
|
51
|
+
sinceMs?: number;
|
|
52
|
+
limit?: number;
|
|
53
|
+
}) => AuditEntryLike[];
|
|
54
|
+
subscribeAuditFeed: (
|
|
55
|
+
subscriber: (entry: AuditEntryLike) => void,
|
|
56
|
+
) => () => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function defaultCheckRelayReachable(relayPort: number): Promise<boolean> {
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetch(`http://127.0.0.1:${relayPort}/`, {
|
|
62
|
+
method: "HEAD",
|
|
63
|
+
signal: AbortSignal.timeout(2000),
|
|
64
|
+
});
|
|
65
|
+
return response.ok || response.status < 500;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function defaultResolveExtensionPath(): string | null {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isAutonomyEvent(event: StreamEventEnvelopeLike): boolean {
|
|
76
|
+
return event.type === "agent_event" || event.type === "heartbeat_event";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function defaultInitSse(res: http.ServerResponse): void {
|
|
80
|
+
res.writeHead(200, {
|
|
81
|
+
"Content-Type": "text/event-stream",
|
|
82
|
+
"Cache-Control": "no-cache",
|
|
83
|
+
Connection: "keep-alive",
|
|
84
|
+
"X-Accel-Buffering": "no",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function defaultWriteSseData(
|
|
89
|
+
res: http.ServerResponse,
|
|
90
|
+
data: string,
|
|
91
|
+
event?: string,
|
|
92
|
+
): void {
|
|
93
|
+
if (event) {
|
|
94
|
+
res.write(`event: ${event}\n`);
|
|
95
|
+
}
|
|
96
|
+
const safe = data.replace(/\r?\n/g, "\ndata: ");
|
|
97
|
+
res.write(`data: ${safe}\n\n`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function defaultWriteSseJson(
|
|
101
|
+
res: http.ServerResponse,
|
|
102
|
+
payload: object,
|
|
103
|
+
event?: string,
|
|
104
|
+
): void {
|
|
105
|
+
defaultWriteSseData(res, JSON.stringify(payload), event);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function parseAuditSince(raw: string | null): {
|
|
109
|
+
value?: number;
|
|
110
|
+
error?: string;
|
|
111
|
+
} {
|
|
112
|
+
if (raw == null) return {};
|
|
113
|
+
const trimmed = raw.trim();
|
|
114
|
+
if (!trimmed) {
|
|
115
|
+
return {
|
|
116
|
+
error: 'Invalid "since" filter: expected epoch ms or ISO timestamp.',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const numeric = Number(trimmed);
|
|
121
|
+
if (Number.isFinite(numeric)) {
|
|
122
|
+
return { value: Math.trunc(numeric) };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const parsed = Date.parse(trimmed);
|
|
126
|
+
if (!Number.isFinite(parsed)) {
|
|
127
|
+
return {
|
|
128
|
+
error: 'Invalid "since" filter: expected epoch ms or ISO timestamp.',
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return { value: parsed };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isTruthyQueryParam(value: string | null): boolean {
|
|
135
|
+
if (!value) return false;
|
|
136
|
+
const normalized = value.trim().toLowerCase();
|
|
137
|
+
return (
|
|
138
|
+
normalized === "1" ||
|
|
139
|
+
normalized === "true" ||
|
|
140
|
+
normalized === "yes" ||
|
|
141
|
+
normalized === "on"
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function matchesAuditFilter(
|
|
146
|
+
entry: AuditEntryLike,
|
|
147
|
+
filters: {
|
|
148
|
+
type?: string;
|
|
149
|
+
severity?: string;
|
|
150
|
+
sinceMs?: number;
|
|
151
|
+
},
|
|
152
|
+
): boolean {
|
|
153
|
+
if (filters.type && entry.type !== filters.type) return false;
|
|
154
|
+
if (filters.severity && entry.severity !== filters.severity) return false;
|
|
155
|
+
if (
|
|
156
|
+
filters.sinceMs !== undefined &&
|
|
157
|
+
Date.parse(entry.timestamp) < filters.sinceMs
|
|
158
|
+
) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export async function handleDiagnosticsRoutes(
|
|
165
|
+
ctx: DiagnosticsRouteContext,
|
|
166
|
+
): Promise<boolean> {
|
|
167
|
+
const {
|
|
168
|
+
req,
|
|
169
|
+
res,
|
|
170
|
+
method,
|
|
171
|
+
pathname,
|
|
172
|
+
url,
|
|
173
|
+
logBuffer,
|
|
174
|
+
eventBuffer,
|
|
175
|
+
relayPort: relayPortOverride,
|
|
176
|
+
checkRelayReachable,
|
|
177
|
+
resolveExtensionPath,
|
|
178
|
+
initSse,
|
|
179
|
+
writeSseJson,
|
|
180
|
+
auditEventTypes,
|
|
181
|
+
auditSeverities,
|
|
182
|
+
getAuditFeedSize,
|
|
183
|
+
queryAuditFeed,
|
|
184
|
+
subscribeAuditFeed,
|
|
185
|
+
json,
|
|
186
|
+
} = ctx;
|
|
187
|
+
|
|
188
|
+
if (method === "GET" && pathname === "/api/logs") {
|
|
189
|
+
let entries = logBuffer;
|
|
190
|
+
|
|
191
|
+
const sourceFilter = url.searchParams.get("source");
|
|
192
|
+
if (sourceFilter) {
|
|
193
|
+
entries = entries.filter((entry) => entry.source === sourceFilter);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const levelFilter = url.searchParams.get("level");
|
|
197
|
+
if (levelFilter) {
|
|
198
|
+
entries = entries.filter((entry) => entry.level === levelFilter);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const tagFilter = url.searchParams.get("tag");
|
|
202
|
+
if (tagFilter) {
|
|
203
|
+
entries = entries.filter((entry) => entry.tags.includes(tagFilter));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const sinceFilter = url.searchParams.get("since");
|
|
207
|
+
if (sinceFilter) {
|
|
208
|
+
const sinceTimestamp = Number(sinceFilter);
|
|
209
|
+
if (!Number.isNaN(sinceTimestamp)) {
|
|
210
|
+
entries = entries.filter((entry) => entry.timestamp >= sinceTimestamp);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const sources = [...new Set(logBuffer.map((entry) => entry.source))].sort();
|
|
215
|
+
const tags = [...new Set(logBuffer.flatMap((entry) => entry.tags))].sort();
|
|
216
|
+
json(res, { entries: entries.slice(-200), sources, tags });
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (method === "GET" && pathname === "/api/agent/events") {
|
|
221
|
+
const limit = parseClampedInteger(url.searchParams.get("limit"), {
|
|
222
|
+
min: 1,
|
|
223
|
+
max: 1000,
|
|
224
|
+
fallback: 200,
|
|
225
|
+
});
|
|
226
|
+
const runIdFilter = url.searchParams.get("runId");
|
|
227
|
+
const fromSeqRaw = url.searchParams.get("fromSeq");
|
|
228
|
+
const fromSeq = parseClampedInteger(fromSeqRaw, {
|
|
229
|
+
min: 0,
|
|
230
|
+
});
|
|
231
|
+
if (fromSeqRaw !== null && fromSeq === undefined) {
|
|
232
|
+
json(res, { error: 'Invalid "fromSeq" filter.' }, 400);
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
const afterEventId = url.searchParams.get("after");
|
|
236
|
+
let autonomyEvents = eventBuffer.filter(isAutonomyEvent);
|
|
237
|
+
if (runIdFilter) {
|
|
238
|
+
autonomyEvents = autonomyEvents.filter(
|
|
239
|
+
(event) => event.runId === runIdFilter,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
if (fromSeq !== undefined) {
|
|
243
|
+
autonomyEvents = autonomyEvents.filter(
|
|
244
|
+
(event) => typeof event.seq === "number" && event.seq >= fromSeq,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let startIndex = 0;
|
|
249
|
+
if (afterEventId) {
|
|
250
|
+
const index = autonomyEvents.findIndex(
|
|
251
|
+
(event) => event.eventId === afterEventId,
|
|
252
|
+
);
|
|
253
|
+
if (index >= 0) {
|
|
254
|
+
startIndex = index + 1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const events = autonomyEvents.slice(startIndex, startIndex + limit);
|
|
259
|
+
const latestEventId =
|
|
260
|
+
events.length > 0 ? events[events.length - 1].eventId : null;
|
|
261
|
+
|
|
262
|
+
json(res, {
|
|
263
|
+
events,
|
|
264
|
+
latestEventId,
|
|
265
|
+
totalBuffered: autonomyEvents.length,
|
|
266
|
+
replayed: true,
|
|
267
|
+
});
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (method === "GET" && pathname === "/api/security/audit") {
|
|
272
|
+
const typeFilterRaw = url.searchParams.get("type");
|
|
273
|
+
const severityFilterRaw = url.searchParams.get("severity");
|
|
274
|
+
const limitFilter = parseClampedInteger(url.searchParams.get("limit"), {
|
|
275
|
+
min: 1,
|
|
276
|
+
max: 1000,
|
|
277
|
+
fallback: 200,
|
|
278
|
+
});
|
|
279
|
+
const sinceFilter = parseAuditSince(url.searchParams.get("since"));
|
|
280
|
+
|
|
281
|
+
if (sinceFilter.error) {
|
|
282
|
+
json(res, { error: sinceFilter.error }, 400);
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let typeFilter: string | undefined;
|
|
287
|
+
if (typeFilterRaw) {
|
|
288
|
+
const candidate = typeFilterRaw.trim();
|
|
289
|
+
if (!auditEventTypes.includes(candidate)) {
|
|
290
|
+
json(
|
|
291
|
+
res,
|
|
292
|
+
{
|
|
293
|
+
error: `Invalid "type" filter. Expected one of: ${auditEventTypes.join(", ")}`,
|
|
294
|
+
},
|
|
295
|
+
400,
|
|
296
|
+
);
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
typeFilter = candidate;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
let severityFilter: string | undefined;
|
|
303
|
+
if (severityFilterRaw) {
|
|
304
|
+
const candidate = severityFilterRaw.trim();
|
|
305
|
+
if (!auditSeverities.includes(candidate)) {
|
|
306
|
+
json(
|
|
307
|
+
res,
|
|
308
|
+
{
|
|
309
|
+
error: `Invalid "severity" filter. Expected one of: ${auditSeverities.join(", ")}`,
|
|
310
|
+
},
|
|
311
|
+
400,
|
|
312
|
+
);
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
severityFilter = candidate;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const streamRequested =
|
|
319
|
+
isTruthyQueryParam(url.searchParams.get("stream")) ||
|
|
320
|
+
(req.headers.accept ?? "").includes("text/event-stream");
|
|
321
|
+
const filter = {
|
|
322
|
+
type: typeFilter,
|
|
323
|
+
severity: severityFilter,
|
|
324
|
+
sinceMs: sinceFilter.value,
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
if (!streamRequested) {
|
|
328
|
+
const entries = queryAuditFeed({
|
|
329
|
+
...filter,
|
|
330
|
+
limit: limitFilter,
|
|
331
|
+
});
|
|
332
|
+
json(res, {
|
|
333
|
+
entries,
|
|
334
|
+
totalBuffered: getAuditFeedSize(),
|
|
335
|
+
replayed: true,
|
|
336
|
+
});
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const startSse = initSse ?? defaultInitSse;
|
|
341
|
+
const sendSseJson = writeSseJson ?? defaultWriteSseJson;
|
|
342
|
+
startSse(res);
|
|
343
|
+
sendSseJson(res, {
|
|
344
|
+
type: "snapshot",
|
|
345
|
+
entries: queryAuditFeed({ ...filter, limit: limitFilter }),
|
|
346
|
+
totalBuffered: getAuditFeedSize(),
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const unsubscribe = subscribeAuditFeed((entry) => {
|
|
350
|
+
if (!matchesAuditFilter(entry, filter)) return;
|
|
351
|
+
sendSseJson(res, { type: "entry", entry });
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
let closed = false;
|
|
355
|
+
const close = () => {
|
|
356
|
+
if (closed) return;
|
|
357
|
+
closed = true;
|
|
358
|
+
unsubscribe();
|
|
359
|
+
if (!res.writableEnded) {
|
|
360
|
+
res.end();
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
req.on("close", close);
|
|
365
|
+
req.on("aborted", close);
|
|
366
|
+
res.on("close", close);
|
|
367
|
+
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (method === "GET" && pathname === "/api/extension/status") {
|
|
372
|
+
const relayPort = relayPortOverride ?? 18792;
|
|
373
|
+
const relayReachable = await (
|
|
374
|
+
checkRelayReachable ?? defaultCheckRelayReachable
|
|
375
|
+
)(relayPort);
|
|
376
|
+
const extensionPath = (
|
|
377
|
+
resolveExtensionPath ?? defaultResolveExtensionPath
|
|
378
|
+
)();
|
|
379
|
+
|
|
380
|
+
json(res, {
|
|
381
|
+
relayReachable,
|
|
382
|
+
relayPort,
|
|
383
|
+
extensionPath,
|
|
384
|
+
});
|
|
385
|
+
return true;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MiladyMaker drop/mint service.
|
|
3
|
+
*
|
|
4
|
+
* Handles the ERC-8041 fixed-supply collection minting:
|
|
5
|
+
* - Public free mint (user pays gas)
|
|
6
|
+
* - Shiny mint (0.1 ETH + gas)
|
|
7
|
+
* - Whitelist mint (Merkle proof)
|
|
8
|
+
* - Supply tracking and status
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { logger } from "@elizaos/core";
|
|
12
|
+
import { ethers } from "ethers";
|
|
13
|
+
import type { DropStatus, MintResult } from "../contracts/drop";
|
|
14
|
+
import type { TxService } from "./tx-service";
|
|
15
|
+
|
|
16
|
+
export type { DropStatus, MintResult } from "../contracts/drop";
|
|
17
|
+
|
|
18
|
+
// ── ABI ──────────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
const COLLECTION_ABI = [
|
|
21
|
+
"function mint(string,string,bytes32) external returns (uint256)",
|
|
22
|
+
"function mintShiny(string,string,bytes32) external payable returns (uint256)",
|
|
23
|
+
"function mintWhitelist(string,string,bytes32,bytes32[]) external returns (uint256)",
|
|
24
|
+
"function mintFor(address,string,string,bytes32,bool) external returns (uint256)",
|
|
25
|
+
"function currentSupply() view returns (uint256)",
|
|
26
|
+
"function publicMintOpen() view returns (bool)",
|
|
27
|
+
"function whitelistMintOpen() view returns (bool)",
|
|
28
|
+
"function hasMinted(address) view returns (bool)",
|
|
29
|
+
"function getAgentMintNumber(uint256) view returns (uint256)",
|
|
30
|
+
"function isShiny(uint256) view returns (bool)",
|
|
31
|
+
"function getCollectionDetails() view returns (uint256,uint256,bool)",
|
|
32
|
+
"function MAX_SUPPLY() view returns (uint256)",
|
|
33
|
+
"function SHINY_PRICE() view returns (uint256)",
|
|
34
|
+
"function merkleRoot() view returns (bytes32)",
|
|
35
|
+
"event AgentMinted(uint256 indexed agentId, uint256 indexed mintNumber, address indexed owner, bool shiny)",
|
|
36
|
+
"event CollectionUpdated(uint256 maxSupply, uint256 currentSupply, bool publicOpen, bool whitelistOpen)",
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
const DEFAULT_CAP_HASH = ethers.id("milady-agent");
|
|
40
|
+
|
|
41
|
+
// ── Service ──────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
export class DropService {
|
|
44
|
+
private readonly contract: ethers.Contract;
|
|
45
|
+
private readonly txService: TxService;
|
|
46
|
+
private readonly dropEnabled: boolean;
|
|
47
|
+
|
|
48
|
+
constructor(
|
|
49
|
+
txService: TxService,
|
|
50
|
+
collectionAddress: string,
|
|
51
|
+
dropEnabled: boolean,
|
|
52
|
+
) {
|
|
53
|
+
this.txService = txService;
|
|
54
|
+
this.contract = txService.getContract(collectionAddress, COLLECTION_ABI);
|
|
55
|
+
this.dropEnabled = dropEnabled;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async getStatus(): Promise<DropStatus> {
|
|
59
|
+
if (!this.dropEnabled) {
|
|
60
|
+
return {
|
|
61
|
+
dropEnabled: false,
|
|
62
|
+
publicMintOpen: false,
|
|
63
|
+
whitelistMintOpen: false,
|
|
64
|
+
mintedOut: false,
|
|
65
|
+
currentSupply: 0,
|
|
66
|
+
maxSupply: 2138,
|
|
67
|
+
shinyPrice: "0.1",
|
|
68
|
+
userHasMinted: false,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const [collectionDetails, whitelistOpen, hasMinted, shinyPriceBN] =
|
|
73
|
+
await Promise.all([
|
|
74
|
+
this.contract.getCollectionDetails() as Promise<
|
|
75
|
+
[bigint, bigint, boolean]
|
|
76
|
+
>,
|
|
77
|
+
this.contract.whitelistMintOpen() as Promise<boolean>,
|
|
78
|
+
this.contract.hasMinted(this.txService.address) as Promise<boolean>,
|
|
79
|
+
this.contract.SHINY_PRICE() as Promise<bigint>,
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
const [maxSupply, currentSupply, publicOpen] = collectionDetails;
|
|
83
|
+
const maxSupplyNum = Number(maxSupply);
|
|
84
|
+
const currentSupplyNum = Number(currentSupply);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
dropEnabled: true,
|
|
88
|
+
publicMintOpen: publicOpen,
|
|
89
|
+
whitelistMintOpen: whitelistOpen,
|
|
90
|
+
mintedOut: currentSupplyNum >= maxSupplyNum,
|
|
91
|
+
currentSupply: currentSupplyNum,
|
|
92
|
+
maxSupply: maxSupplyNum,
|
|
93
|
+
shinyPrice: ethers.formatEther(shinyPriceBN),
|
|
94
|
+
userHasMinted: hasMinted,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async mint(
|
|
99
|
+
name: string,
|
|
100
|
+
endpoint: string,
|
|
101
|
+
capabilitiesHash?: string,
|
|
102
|
+
): Promise<MintResult> {
|
|
103
|
+
const capHash = capabilitiesHash || DEFAULT_CAP_HASH;
|
|
104
|
+
|
|
105
|
+
logger.info(`[drop] Minting agent "${name}" for ${this.txService.address}`);
|
|
106
|
+
|
|
107
|
+
// Get fresh nonce before transaction
|
|
108
|
+
const nonce = await this.txService.getFreshNonce();
|
|
109
|
+
|
|
110
|
+
const tx = await this.contract.mint(name, endpoint, capHash, { nonce });
|
|
111
|
+
logger.info(`[drop] Mint tx submitted: ${tx.hash}`);
|
|
112
|
+
|
|
113
|
+
const receipt = await tx.wait();
|
|
114
|
+
return this.parseMintReceipt(receipt, false);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async mintShiny(
|
|
118
|
+
name: string,
|
|
119
|
+
endpoint: string,
|
|
120
|
+
capabilitiesHash?: string,
|
|
121
|
+
): Promise<MintResult> {
|
|
122
|
+
const capHash = capabilitiesHash || DEFAULT_CAP_HASH;
|
|
123
|
+
const shinyPrice = (await this.contract.SHINY_PRICE()) as bigint;
|
|
124
|
+
|
|
125
|
+
logger.info(
|
|
126
|
+
`[drop] Minting SHINY agent "${name}" for ${this.txService.address} (${ethers.formatEther(shinyPrice)} ETH)`,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Get fresh nonce before transaction
|
|
130
|
+
const nonce = await this.txService.getFreshNonce();
|
|
131
|
+
|
|
132
|
+
const tx = await this.contract.mintShiny(name, endpoint, capHash, {
|
|
133
|
+
value: shinyPrice,
|
|
134
|
+
nonce,
|
|
135
|
+
});
|
|
136
|
+
logger.info(`[drop] Shiny mint tx submitted: ${tx.hash}`);
|
|
137
|
+
|
|
138
|
+
const receipt = await tx.wait();
|
|
139
|
+
return this.parseMintReceipt(receipt, true);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async mintWithWhitelist(
|
|
143
|
+
name: string,
|
|
144
|
+
endpoint: string,
|
|
145
|
+
proof: string[],
|
|
146
|
+
capabilitiesHash?: string,
|
|
147
|
+
): Promise<MintResult> {
|
|
148
|
+
const capHash = capabilitiesHash || DEFAULT_CAP_HASH;
|
|
149
|
+
|
|
150
|
+
logger.info(
|
|
151
|
+
`[drop] Whitelist minting agent "${name}" for ${this.txService.address}`,
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
// Get fresh nonce before transaction
|
|
155
|
+
const nonce = await this.txService.getFreshNonce();
|
|
156
|
+
|
|
157
|
+
const tx = await this.contract.mintWhitelist(
|
|
158
|
+
name,
|
|
159
|
+
endpoint,
|
|
160
|
+
capHash,
|
|
161
|
+
proof,
|
|
162
|
+
{ nonce },
|
|
163
|
+
);
|
|
164
|
+
logger.info(`[drop] Whitelist mint tx submitted: ${tx.hash}`);
|
|
165
|
+
|
|
166
|
+
const receipt = await tx.wait();
|
|
167
|
+
return this.parseMintReceipt(receipt, false);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async getMintNumber(agentId: number): Promise<number> {
|
|
171
|
+
return Number(await this.contract.getAgentMintNumber(agentId));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async checkIsShiny(agentId: number): Promise<boolean> {
|
|
175
|
+
return this.contract.isShiny(agentId) as Promise<boolean>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private parseMintReceipt(
|
|
179
|
+
receipt: ethers.TransactionReceipt,
|
|
180
|
+
shiny: boolean,
|
|
181
|
+
): MintResult {
|
|
182
|
+
const iface = new ethers.Interface(COLLECTION_ABI);
|
|
183
|
+
let agentId = 0;
|
|
184
|
+
let mintNumber = 0;
|
|
185
|
+
|
|
186
|
+
for (const log of receipt.logs) {
|
|
187
|
+
const parsed = iface.parseLog({
|
|
188
|
+
topics: log.topics as string[],
|
|
189
|
+
data: log.data,
|
|
190
|
+
});
|
|
191
|
+
if (parsed && parsed.name === "AgentMinted") {
|
|
192
|
+
agentId = Number(parsed.args[0]);
|
|
193
|
+
mintNumber = Number(parsed.args[1]);
|
|
194
|
+
shiny = parsed.args[3] as boolean;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
logger.info(
|
|
200
|
+
`[drop] Minted: agentId=${agentId} mintNumber=${mintNumber} shiny=${shiny} txHash=${receipt.hash}`,
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return { agentId, mintNumber, txHash: receipt.hash, isShiny: shiny };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Early log capture — split out from server.ts to avoid pulling in the entire
|
|
3
|
+
* API server dependency graph when only the log-buffer bootstrap is needed
|
|
4
|
+
* (e.g. during headless `startEliza()`).
|
|
5
|
+
*
|
|
6
|
+
* @module api/early-logs
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { logger } from "@elizaos/core";
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Types
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface EarlyLogEntry {
|
|
16
|
+
timestamp: number;
|
|
17
|
+
level: string;
|
|
18
|
+
message: string;
|
|
19
|
+
source: string;
|
|
20
|
+
tags: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Module-level state (shared via the exported accessors)
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
let earlyLogBuffer: EarlyLogEntry[] | null = null;
|
|
28
|
+
let earlyPatchCleanup: (() => void) | null = null;
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Public API
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Start capturing logs from the global @elizaos/core logger before the API
|
|
36
|
+
* server is up. Call this once, early in the startup flow (e.g. before
|
|
37
|
+
* `startEliza`). When `startApiServer` runs it will flush and take over.
|
|
38
|
+
*/
|
|
39
|
+
export function captureEarlyLogs(): void {
|
|
40
|
+
if (earlyLogBuffer) return; // already capturing
|
|
41
|
+
// If the global logger is already fully patched (e.g. dev-server started
|
|
42
|
+
// the API server before calling startEliza), skip early capture entirely.
|
|
43
|
+
if ((logger as unknown as Record<string, unknown>).__miladyLogPatched) return;
|
|
44
|
+
earlyLogBuffer = [];
|
|
45
|
+
const EARLY_PATCHED = "__miladyEarlyPatched";
|
|
46
|
+
if ((logger as unknown as Record<string, unknown>)[EARLY_PATCHED]) return;
|
|
47
|
+
|
|
48
|
+
const LEVELS = ["debug", "info", "warn", "error"] as const;
|
|
49
|
+
const originals = new Map<string, (...args: unknown[]) => void>();
|
|
50
|
+
|
|
51
|
+
for (const lvl of LEVELS) {
|
|
52
|
+
const original = logger[lvl].bind(logger);
|
|
53
|
+
originals.set(lvl, original as (...args: unknown[]) => void);
|
|
54
|
+
const earlyPatched: (typeof logger)[typeof lvl] = (
|
|
55
|
+
...args: Parameters<typeof original>
|
|
56
|
+
) => {
|
|
57
|
+
let msg = "";
|
|
58
|
+
let source = "agent";
|
|
59
|
+
const tags = ["agent"];
|
|
60
|
+
if (typeof args[0] === "string") {
|
|
61
|
+
msg = args[0];
|
|
62
|
+
} else if (args[0] && typeof args[0] === "object") {
|
|
63
|
+
const obj = args[0] as Record<string, unknown>;
|
|
64
|
+
if (typeof obj.src === "string") source = obj.src;
|
|
65
|
+
msg = typeof args[1] === "string" ? args[1] : JSON.stringify(obj);
|
|
66
|
+
}
|
|
67
|
+
const bracketMatch = /^\[([^\]]+)\]\s*/.exec(msg);
|
|
68
|
+
if (bracketMatch && source === "agent") source = bracketMatch[1];
|
|
69
|
+
if (source !== "agent" && !tags.includes(source)) tags.push(source);
|
|
70
|
+
earlyLogBuffer?.push({
|
|
71
|
+
timestamp: Date.now(),
|
|
72
|
+
level: lvl,
|
|
73
|
+
message: msg,
|
|
74
|
+
source,
|
|
75
|
+
tags,
|
|
76
|
+
});
|
|
77
|
+
return original(...args);
|
|
78
|
+
};
|
|
79
|
+
logger[lvl] = earlyPatched;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
(logger as unknown as Record<string, unknown>)[EARLY_PATCHED] = true;
|
|
83
|
+
|
|
84
|
+
earlyPatchCleanup = () => {
|
|
85
|
+
// Restore originals so `patchLogger` inside `startApiServer` can re-patch
|
|
86
|
+
for (const lvl of LEVELS) {
|
|
87
|
+
const orig = originals.get(lvl);
|
|
88
|
+
if (orig) logger[lvl] = orig as (typeof logger)[typeof lvl];
|
|
89
|
+
}
|
|
90
|
+
delete (logger as unknown as Record<string, unknown>)[EARLY_PATCHED];
|
|
91
|
+
// Don't set the main PATCHED_MARKER — `patchLogger` will do that
|
|
92
|
+
delete (logger as unknown as Record<string, unknown>).__miladyLogPatched;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Drain the early log buffer and clean up the early logger patch.
|
|
98
|
+
* Called by `startApiServer` to flush buffered entries into the main log
|
|
99
|
+
* buffer, then hand control to the server's own logger patch.
|
|
100
|
+
*
|
|
101
|
+
* Returns the buffered entries (empty array if none).
|
|
102
|
+
*/
|
|
103
|
+
export function flushEarlyLogs(): EarlyLogEntry[] {
|
|
104
|
+
const entries = earlyLogBuffer ? [...earlyLogBuffer] : [];
|
|
105
|
+
if (earlyPatchCleanup) {
|
|
106
|
+
earlyPatchCleanup();
|
|
107
|
+
earlyPatchCleanup = null;
|
|
108
|
+
}
|
|
109
|
+
earlyLogBuffer = null;
|
|
110
|
+
return entries;
|
|
111
|
+
}
|